Merge "Adding audiocontrol and evs hashes to current.txt" into qt-qpr1-dev am: df3648e4ff

Change-Id: Idec81bb231be3113db6672f1dcd7c4cd6def393e
diff --git a/Android.bp b/Android.bp
index 927e227..f64968f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -24,6 +24,11 @@
         "VtsHalHidlTargetTestBase",
         "libhidl-gen-utils",
     ],
+
+    header_libs: [
+        "libhidl_gtest_helper",
+    ],
+
     group_static_libs: true,
 
     // Lists all system dependencies that can be expected on the device.
@@ -33,8 +38,6 @@
         "libcutils",
         "liblog",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "libutils",
     ],
     cflags: [
@@ -42,4 +45,5 @@
         "-g",
     ],
 
+    require_root: true,
 }
diff --git a/CleanSpec.mk b/CleanSpec.mk
index edde1cb..76594fb 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -80,3 +80,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/android.hardware.configstore@1.2.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk-Q/android.hardware.configstore@1.2.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/android.hardware.configstore@1.2.so)
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/etc/init/android.hardware.audio@2.0-service.rc $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.audio@2.0-service)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.cas@1.1*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.cas@1.1*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/android.hardware.cas@1.1*)
diff --git a/OWNERS b/OWNERS
index 1d7a8e1..433bbb7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,6 @@
+per-file *.hal,*.aidl,OWNERS = set noparent
+per-file *.hal,*.aidl,OWNERS = elsk@google.com,malchev@google.com,smoreland@google.com
+
 elsk@google.com
 maco@google.com
 malchev@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 213c93a..6740bb5 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -2,4 +2,10 @@
 ignore_merged_commits = true
 
 [Builtin Hooks]
+bpfmt = true
 clang_format = true
+
+[Hook Scripts]
+aosp_hook_confirmationui = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} confirmationui
+aosp_hook_gatekeeper = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} gatekeeper
+aosp_hook_keymaster = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} keymaster
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..0e18f48
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,14 @@
+{
+  "presubmit": [
+    {
+      "name": "vts_treble_vintf_framework_test"
+    },
+    {
+      "name": "vts_treble_vintf_vendor_test"
+    },
+    {
+      "name": "hidl_implementation_test"
+    }
+  ]
+}
+
diff --git a/atrace/1.0/Android.bp b/atrace/1.0/Android.bp
index 4d73cfd..c7e8d04 100644
--- a/atrace/1.0/Android.bp
+++ b/atrace/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/atrace/1.0/default/Android.bp b/atrace/1.0/default/Android.bp
index bcaf064..4bbbdb3 100644
--- a/atrace/1.0/default/Android.bp
+++ b/atrace/1.0/default/Android.bp
@@ -29,7 +29,6 @@
         "libbase",
         "libutils",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.atrace@1.0",
     ],
 }
diff --git a/atrace/1.0/default/AtraceDevice.cpp b/atrace/1.0/default/AtraceDevice.cpp
index 35d11e9..4e82b0a 100644
--- a/atrace/1.0/default/AtraceDevice.cpp
+++ b/atrace/1.0/default/AtraceDevice.cpp
@@ -94,7 +94,7 @@
     for (auto& c : kTracingMap) {
         for (auto& p : c.second.paths) {
             if (!android::base::WriteStringToFile("0", p.first)) {
-                LOG(ERROR) << "Failed to enable tracing on: " << p.first;
+                LOG(ERROR) << "Failed to disable tracing on: " << p.first;
                 if (p.second) {
                     ret = Status::ERROR_TRACING_POINT;
                 }
diff --git a/atrace/1.0/vts/functional/Android.bp b/atrace/1.0/vts/functional/Android.bp
index d3f4276..ae24968 100644
--- a/atrace/1.0/vts/functional/Android.bp
+++ b/atrace/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalAtraceV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.atrace@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp b/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp
index c62c2f0..2eaa03e 100644
--- a/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp
+++ b/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp
@@ -18,8 +18,9 @@
 
 #include <android/hardware/atrace/1.0/IAtraceDevice.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_string;
@@ -28,29 +29,13 @@
 using ::android::hardware::atrace::V1_0::IAtraceDevice;
 using ::android::hardware::atrace::V1_0::Status;
 
-// Test environment for Boot HIDL HAL.
-class AtraceHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static AtraceHidlEnvironment* Instance() {
-        static AtraceHidlEnvironment* instance = new AtraceHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IAtraceDevice>(); }
-
-   private:
-    AtraceHidlEnvironment() {}
-};
-
 /**
  * There is no expected behaviour that can be tested so these tests check the
  * HAL doesn't crash with different execution orders.
  */
-struct AtraceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+struct AtraceHidlTest : public ::testing::TestWithParam<std::string> {
     virtual void SetUp() override {
-        atrace = ::testing::VtsHalHidlTargetTestBase::getService<IAtraceDevice>(
-            AtraceHidlEnvironment::Instance()->getServiceName<IAtraceDevice>());
+        atrace = IAtraceDevice::getService(GetParam());
         ASSERT_NE(atrace, nullptr);
     }
 
@@ -82,13 +67,13 @@
 }
 
 /* list categories from vendors. */
-TEST_F(AtraceHidlTest, listCategories) {
+TEST_P(AtraceHidlTest, listCategories) {
     hidl_vec<hidl_string> vnd_categories = getVendorCategoryName(atrace);
     EXPECT_NE(0, vnd_categories.size());
 }
 
 /* enable categories. */
-TEST_F(AtraceHidlTest, enableCategories) {
+TEST_P(AtraceHidlTest, enableCategories) {
     hidl_vec<hidl_string> vnd_categories = getVendorCategoryName(atrace);
     // empty Category with ERROR_INVALID_ARGUMENT
     hidl_vec<hidl_string> empty_categories;
@@ -102,17 +87,13 @@
 }
 
 /* enable categories. */
-TEST_F(AtraceHidlTest, disableAllCategories) {
+TEST_P(AtraceHidlTest, disableAllCategories) {
     auto ret = atrace->disableAllCategories();
     ASSERT_TRUE(ret.isOk());
     EXPECT_EQ(Status::SUCCESS, ret);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(AtraceHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    AtraceHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, AtraceHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAtraceDevice::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/audio/2.0/Android.bp b/audio/2.0/Android.bp
index 3495b1a..02f8b40 100644
--- a/audio/2.0/Android.bp
+++ b/audio/2.0/Android.bp
@@ -24,4 +24,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/4.0/Android.bp b/audio/4.0/Android.bp
index b97fe01..862c711 100644
--- a/audio/4.0/Android.bp
+++ b/audio/4.0/Android.bp
@@ -24,4 +24,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/4.0/config/api/current.txt b/audio/4.0/config/api/current.txt
index d59cade..3462568 100644
--- a/audio/4.0/config/api/current.txt
+++ b/audio/4.0/config/api/current.txt
@@ -114,11 +114,15 @@
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_EVRCNW;
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_EVRCWB;
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_E_AC3;
+    enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_FLAC;
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_IEC61937;
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_LDAC;
+    enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MAT_1_0;
+    enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MAT_2_0;
+    enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MAT_2_1;
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MP2;
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MP3;
     enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_OPUS;
diff --git a/audio/4.0/config/audio_policy_configuration.xsd b/audio/4.0/config/audio_policy_configuration.xsd
index 58bab22..f26e41b 100644
--- a/audio/4.0/config/audio_policy_configuration.xsd
+++ b/audio/4.0/config/audio_policy_configuration.xsd
@@ -357,6 +357,10 @@
             <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
             <xs:enumeration value="AUDIO_FORMAT_AC4"/>
             <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
         </xs:restriction>
     </xs:simpleType>
     <xs:simpleType name="extendableAudioFormat">
diff --git a/audio/5.0/Android.bp b/audio/5.0/Android.bp
index f6ac2eb..9b28497 100644
--- a/audio/5.0/Android.bp
+++ b/audio/5.0/Android.bp
@@ -25,4 +25,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/5.0/config/api/current.txt b/audio/5.0/config/api/current.txt
index c665781..a1d8e1e 100644
--- a/audio/5.0/config/api/current.txt
+++ b/audio/5.0/config/api/current.txt
@@ -237,6 +237,7 @@
     method public audio.policy.configuration.V5_0.GainMode getMode();
     method public String getName();
     method public int getStepValueMB();
+    method public boolean getUseForVolume();
     method public void setChannel_mask(String);
     method public void setDefaultValueMB(int);
     method public void setMaxRampMs(int);
@@ -246,6 +247,7 @@
     method public void setMode(audio.policy.configuration.V5_0.GainMode);
     method public void setName(String);
     method public void setStepValueMB(int);
+    method public void setUseForVolume(boolean);
   }
 
   public class GlobalConfiguration {
diff --git a/audio/5.0/config/audio_policy_configuration.xsd b/audio/5.0/config/audio_policy_configuration.xsd
index 2e1a722..284d2e2 100644
--- a/audio/5.0/config/audio_policy_configuration.xsd
+++ b/audio/5.0/config/audio_policy_configuration.xsd
@@ -446,6 +446,7 @@
                     <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
                     <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
                     <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+                    <xs:attribute name="useForVolume" type="xs:boolean" use="optional"/>
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
diff --git a/audio/6.0/Android.bp b/audio/6.0/Android.bp
new file mode 100644
index 0000000..dc6bb98
--- /dev/null
+++ b/audio/6.0/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio@6.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IDevice.hal",
+        "IDevicesFactory.hal",
+        "IPrimaryDevice.hal",
+        "IStream.hal",
+        "IStreamIn.hal",
+        "IStreamOut.hal",
+        "IStreamOutCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.effect@6.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
new file mode 100644
index 0000000..122c550
--- /dev/null
+++ b/audio/6.0/IDevice.hal
@@ -0,0 +1,298 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStreamIn;
+import IStreamOut;
+
+interface IDevice {
+    /**
+     * Returns whether the audio hardware interface has been initialized.
+     *
+     * @return retval OK on success, NOT_INITIALIZED on failure.
+     */
+    initCheck() generates (Result retval);
+
+    /**
+     * Sets the audio volume for all audio activities other than voice call. If
+     * NOT_SUPPORTED is returned, the software mixer will emulate this
+     * capability.
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setMasterVolume(float volume) generates (Result retval);
+
+    /**
+     * Get the current master volume value for the HAL, if the HAL supports
+     * master volume control. For example, AudioFlinger will query this value
+     * from the primary audio HAL when the service starts and use the value for
+     * setting the initial master volume across all HALs. HALs which do not
+     * support this method must return NOT_SUPPORTED in 'retval'.
+     *
+     * @return retval operation completion status.
+     * @return volume 1.0f means unity, 0.0f is zero.
+     */
+    getMasterVolume() generates (Result retval, float volume);
+
+    /**
+     * Sets microphone muting state.
+     *
+     * @param mute whether microphone is muted.
+     * @return retval operation completion status.
+     */
+    setMicMute(bool mute) generates (Result retval);
+
+    /**
+     * Gets whether microphone is muted.
+     *
+     * @return retval operation completion status.
+     * @return mute whether microphone is muted.
+     */
+    getMicMute() generates (Result retval, bool mute);
+
+    /**
+     * Set the audio mute status for all audio activities. If the return value
+     * is NOT_SUPPORTED, the software mixer will emulate this capability.
+     *
+     * @param mute whether audio is muted.
+     * @return retval operation completion status.
+     */
+    setMasterMute(bool mute) generates (Result retval);
+
+    /**
+     * Get the current master mute status for the HAL, if the HAL supports
+     * master mute control. AudioFlinger will query this value from the primary
+     * audio HAL when the service starts and use the value for setting the
+     * initial master mute across all HALs. HAL must indicate that the feature
+     * is not supported by returning NOT_SUPPORTED status.
+     *
+     * @return retval operation completion status.
+     * @return mute whether audio is muted.
+     */
+    getMasterMute() generates (Result retval, bool mute);
+
+    /**
+     * Returns audio input buffer size according to parameters passed or
+     * INVALID_ARGUMENTS if one of the parameters is not supported.
+     *
+     * @param config audio configuration.
+     * @return retval operation completion status.
+     * @return bufferSize input buffer size in bytes.
+     */
+    getInputBufferSize(AudioConfig config)
+            generates (Result retval, uint64_t bufferSize);
+
+    /**
+     * This method creates and opens the audio hardware output stream.
+     * If the stream can not be opened with the proposed audio config,
+     * HAL must provide suggested values for the audio config.
+     *
+     * @param ioHandle handle assigned by AudioFlinger.
+     * @param device device type and (if needed) address.
+     * @param config stream configuration.
+     * @param flags additional flags.
+     * @param sourceMetadata Description of the audio that will be played.
+                             May be used by implementations to configure hardware effects.
+     * @return retval operation completion status.
+     * @return outStream created output stream.
+     * @return suggestedConfig in case of invalid parameters, suggested config.
+     */
+    openOutputStream(
+            AudioIoHandle ioHandle,
+            DeviceAddress device,
+            AudioConfig config,
+            bitfield<AudioOutputFlag> flags,
+            SourceMetadata sourceMetadata) generates (
+                    Result retval,
+                    IStreamOut outStream,
+                    AudioConfig suggestedConfig);
+
+    /**
+     * This method creates and opens the audio hardware input stream.
+     * If the stream can not be opened with the proposed audio config,
+     * HAL must provide suggested values for the audio config.
+     *
+     * @param ioHandle handle assigned by AudioFlinger.
+     * @param device device type and (if needed) address.
+     * @param config stream configuration.
+     * @param flags additional flags.
+     * @param sinkMetadata Description of the audio that is suggested by the client.
+     *                     May be used by implementations to configure processing effects.
+     * @return retval operation completion status.
+     * @return inStream in case of success, created input stream.
+     * @return suggestedConfig in case of invalid parameters, suggested config.
+     */
+    openInputStream(
+            AudioIoHandle ioHandle,
+            DeviceAddress device,
+            AudioConfig config,
+            bitfield<AudioInputFlag> flags,
+            SinkMetadata sinkMetadata) generates (
+                    Result retval,
+                    IStreamIn inStream,
+                    AudioConfig suggestedConfig);
+
+    /**
+     * Returns whether HAL supports audio patches.
+     *
+     * @return supports true if audio patches are supported.
+     */
+    supportsAudioPatches() generates (bool supports);
+
+    /**
+     * Creates an audio patch between several source and sink ports.  The handle
+     * is allocated by the HAL and must be unique for this audio HAL module.
+     *
+     * @param sources patch sources.
+     * @param sinks patch sinks.
+     * @return retval operation completion status.
+     * @return patch created patch handle.
+     */
+    createAudioPatch(vec<AudioPortConfig> sources, vec<AudioPortConfig> sinks)
+            generates (Result retval, AudioPatchHandle patch);
+
+    /**
+     * Release an audio patch.
+     *
+     * @param patch patch handle.
+     * @return retval operation completion status.
+     */
+    releaseAudioPatch(AudioPatchHandle patch) generates (Result retval);
+
+    /**
+     * Returns the list of supported attributes for a given audio port.
+     *
+     * As input, 'port' contains the information (type, role, address etc...)
+     * needed by the HAL to identify the port.
+     *
+     * As output, 'resultPort' contains possible attributes (sampling rates,
+     * formats, channel masks, gain controllers...) for this port.
+     *
+     * @param port port identifier.
+     * @return retval operation completion status.
+     * @return resultPort port descriptor with all parameters filled up.
+     */
+    getAudioPort(AudioPort port)
+            generates (Result retval, AudioPort resultPort);
+
+    /**
+     * Set audio port configuration.
+     *
+     * @param config audio port configuration.
+     * @return retval operation completion status.
+     */
+    setAudioPortConfig(AudioPortConfig config) generates (Result retval);
+
+    /**
+     * Gets the HW synchronization source of the device. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_HW_AV_SYNC on the legacy HAL.
+     * Optional method
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     * @return hwAvSync HW synchronization source
+     */
+    getHwAvSync() generates (Result retval, AudioHwSync hwAvSync);
+
+    /**
+     * Sets whether the screen is on. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_KEY_SCREEN_STATE on the legacy HAL.
+     * Optional method
+     *
+     * @param turnedOn whether the screen is turned on.
+     * @return retval operation completion status.
+     */
+    setScreenState(bool turnedOn) generates (Result retval);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be retrieved at the same time.
+     * The implementation should return as many requested parameters
+     * as possible, even if one or more is not supported
+     *
+     * @param context provides more information about the request
+     * @param keys keys of the requested parameters
+     * @return retval operation completion status.
+     *         OK must be returned if keys is empty.
+     *         NOT_SUPPORTED must be returned if at least one key is unknown.
+     * @return parameters parameter key value pairs.
+     *         Must contain the value of all requested keys if retval == OK
+     */
+    getParameters(vec<ParameterValue> context, vec<string> keys)
+            generates (Result retval, vec<ParameterValue> parameters);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be set at the same time though this is
+     * discouraged as it make failure analysis harder.
+     *
+     * If possible, a failed setParameters should not impact the platform state.
+     *
+     * @param context provides more information about the request
+     * @param parameters parameter key value pairs.
+     * @return retval operation completion status.
+     *         All parameters must be successfully set for OK to be returned
+     */
+    setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+            generates (Result retval);
+
+    /**
+     * Returns an array with available microphones in device.
+     *
+     * @return retval NOT_SUPPORTED if there are no microphones on this device
+     *                INVALID_STATE if the call is not successful,
+     *                OK otherwise.
+     *
+     * @return microphones array with microphones info
+     */
+    getMicrophones()
+         generates(Result retval, vec<MicrophoneInfo> microphones);
+
+    /**
+     * Notifies the device module about the connection state of an input/output
+     * device attached to it. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy HAL.
+     *
+     * @param address audio device specification.
+     * @param connected whether the device is connected.
+     * @return retval operation completion status.
+     */
+    setConnectedState(DeviceAddress address, bool connected)
+            generates (Result retval);
+
+    /**
+     * Called by the framework to deinitialize the device and free up
+     * all currently allocated resources. It is recommended to close
+     * the device on the client side as soon as it is becomes unused.
+     *
+     * Note that all streams must be closed by the client before
+     * attempting to close the device they belong to.
+     *
+     * @return retval OK in case the success.
+     *                INVALID_STATE if the device was already closed
+     *                or there are streams currently opened.
+     */
+    @exit
+    close() generates (Result retval);
+};
diff --git a/audio/6.0/IDevicesFactory.hal b/audio/6.0/IDevicesFactory.hal
new file mode 100644
index 0000000..0483473
--- /dev/null
+++ b/audio/6.0/IDevicesFactory.hal
@@ -0,0 +1,70 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IDevice;
+import IPrimaryDevice;
+
+/** This factory allows a HAL implementation to be split in multiple independent
+ *  devices (called module in the pre-treble API).
+ *  Note that this division is arbitrary and implementation are free
+ *  to only have a Primary.
+ *  The framework will query the devices according to audio_policy_configuration.xml
+ *
+ *  Each device name is arbitrary, provided by the vendor's audio_policy_configuration.xml
+ *  and only used to identify a device in this factory.
+ *  The framework must not interpret the name, treating it as a vendor opaque data
+ *  with the following exception:
+ *  - the "r_submix" device that must be present to support policyMixes (Eg: Android projected).
+ *    Note that this Device is included by default in a build derived from AOSP.
+ *
+ *  Note that on AOSP Oreo (including MR1) the "a2dp" module is not using this API
+ *  but is loaded directly from the system partition using the legacy API
+ *  due to limitations with the Bluetooth framework.
+ */
+interface IDevicesFactory {
+
+    /**
+     * Opens an audio device. To close the device, it is necessary to release
+     * references to the returned device object.
+     *
+     * @param device device name.
+     * @return retval operation completion status. Returns INVALID_ARGUMENTS
+     *         if there is no corresponding hardware module found,
+     *         NOT_INITIALIZED if an error occurred while opening the hardware
+     *         module.
+     * @return result the interface for the created device.
+     */
+    openDevice(string device) generates (Result retval, IDevice result);
+
+    /**
+     * Opens the Primary audio device that must be present.
+     * This function is not optional and must return successfully the primary device.
+     *
+     * This device must have the name "primary".
+     *
+     * The telephony stack uses this device to control the audio during a voice call.
+     *
+     * @return retval operation completion status. Must be SUCCESS.
+     *         For debugging, return INVALID_ARGUMENTS if there is no corresponding
+     *         hardware module found, NOT_INITIALIZED if an error occurred
+     *         while opening the hardware module.
+     * @return result the interface for the created device.
+     */
+    openPrimaryDevice() generates (Result retval, IPrimaryDevice result);
+};
diff --git a/audio/6.0/IPrimaryDevice.hal b/audio/6.0/IPrimaryDevice.hal
new file mode 100644
index 0000000..78cfc65
--- /dev/null
+++ b/audio/6.0/IPrimaryDevice.hal
@@ -0,0 +1,195 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IDevice;
+
+interface IPrimaryDevice extends IDevice {
+    /**
+     * Sets the audio volume of a voice call.
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setVoiceVolume(float volume) generates (Result retval);
+
+    /**
+     * This method is used to notify the HAL about audio mode changes.
+     *
+     * @param mode new mode.
+     * @return retval operation completion status.
+     */
+    setMode(AudioMode mode) generates (Result retval);
+
+    /**
+     * Sets the name of the current BT SCO headset. Calling this method
+     * is equivalent to setting legacy "bt_headset_name" parameter.
+     * The BT SCO headset name must only be used for debugging purposes.
+     * Optional method
+     *
+     * @param name the name of the current BT SCO headset (can be empty).
+     * @return retval operation completion status.
+     */
+    setBtScoHeadsetDebugName(string name) generates (Result retval);
+
+    /**
+     * Gets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+     * Calling this method is equivalent to getting AUDIO_PARAMETER_KEY_BT_NREC
+     * on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT SCO NR + EC are enabled.
+     */
+    getBtScoNrecEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+     * Calling this method is equivalent to setting AUDIO_PARAMETER_KEY_BT_NREC
+     * on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT SCO NR + EC are enabled.
+     * @return retval operation completion status.
+     */
+    setBtScoNrecEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Gets whether BT SCO Wideband mode is enabled. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT Wideband is enabled.
+     */
+    getBtScoWidebandEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT SCO Wideband mode is enabled. Calling this method is
+     * equivalent to setting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT Wideband is enabled.
+     * @return retval operation completion status.
+     */
+    setBtScoWidebandEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Gets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+     * is equivalent to getting "hfp_enable" parameter value on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT HFP is enabled.
+     */
+    getBtHfpEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+     * is equivalent to setting "hfp_enable" parameter on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT HFP is enabled.
+     * @return retval operation completion status.
+     */
+    setBtHfpEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Sets the sampling rate of BT HFP (Hands-Free Profile). Calling this
+     * method is equivalent to setting "hfp_set_sampling_rate" parameter
+     * on the legacy HAL.
+     * Optional method
+     *
+     * @param sampleRateHz sample rate in Hz.
+     * @return retval operation completion status.
+     */
+    setBtHfpSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+    /**
+     * Sets the current output volume Hz for BT HFP (Hands-Free Profile).
+     * Calling this method is equivalent to setting "hfp_volume" parameter value
+     * on the legacy HAL (except that legacy HAL implementations expect
+     * an integer value in the range from 0 to 15.)
+     * Optional method
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setBtHfpVolume(float volume) generates (Result retval);
+
+    enum TtyMode : int32_t {
+        OFF,
+        VCO,
+        HCO,
+        FULL
+    };
+
+    /**
+     * Gets current TTY mode selection. Calling this method is equivalent to
+     * getting AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return mode TTY mode.
+     */
+    getTtyMode() generates (Result retval, TtyMode mode);
+
+    /**
+     * Sets current TTY mode. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+     *
+     * @param mode TTY mode.
+     * @return retval operation completion status.
+     */
+    setTtyMode(TtyMode mode) generates (Result retval);
+
+    /**
+     * Gets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+     * enabled. Calling this method is equivalent to getting
+     * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether HAC mode is enabled.
+     */
+    getHacEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+     * enabled. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether HAC mode is enabled.
+     * @return retval operation completion status.
+     */
+    setHacEnabled(bool enabled) generates (Result retval);
+
+    enum Rotation : int32_t {
+        DEG_0,
+        DEG_90,
+        DEG_180,
+        DEG_270
+    };
+
+    /**
+     * Updates HAL on the current rotation of the device relative to natural
+     * orientation. Calling this method is equivalent to setting legacy
+     * parameter "rotation".
+     *
+     * @param rotation rotation in degrees relative to natural device
+     *     orientation.
+     * @return retval operation completion status.
+     */
+    updateRotation(Rotation rotation) generates (Result retval);
+};
diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal
new file mode 100644
index 0000000..d7d3c84
--- /dev/null
+++ b/audio/6.0/IStream.hal
@@ -0,0 +1,316 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import android.hardware.audio.effect@6.0::IEffect;
+
+interface IStream {
+    /**
+     * Return the frame size (number of bytes per sample).
+     *
+     * @return frameSize frame size in bytes.
+     */
+    getFrameSize() generates (uint64_t frameSize);
+
+    /**
+     * Return the frame count of the buffer. Calling this method is equivalent
+     * to getting AUDIO_PARAMETER_STREAM_FRAME_COUNT on the legacy HAL.
+     *
+     * @return count frame count.
+     */
+    getFrameCount() generates (uint64_t count);
+
+    /**
+     * Return the size of input/output buffer in bytes for this stream.
+     * It must be a multiple of the frame size.
+     *
+     * @return buffer buffer size in bytes.
+     */
+    getBufferSize() generates (uint64_t bufferSize);
+
+    /**
+     * Return the sampling rate in Hz.
+     *
+     * @return sampleRateHz sample rate in Hz.
+     */
+    getSampleRate() generates (uint32_t sampleRateHz);
+
+    /**
+     * Return supported native sampling rates of the stream for a given format.
+     * A supported native sample rate is a sample rate that can be efficiently
+     * played by the hardware (typically without sample-rate conversions).
+     *
+     * This function is only called for dynamic profile. If called for
+     * non-dynamic profile is should return NOT_SUPPORTED or the same list
+     * as in audio_policy_configuration.xml.
+     *
+     * Calling this method is equivalent to getting
+     * AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES on the legacy HAL.
+     *
+     *
+     * @param format audio format for which the sample rates are supported.
+     * @return retval operation completion status.
+     *                Must be OK if the format is supported.
+     * @return sampleRateHz supported sample rates.
+     */
+    getSupportedSampleRates(AudioFormat format)
+            generates (Result retval, vec<uint32_t> sampleRates);
+
+    /**
+     * Sets the sampling rate of the stream. Calling this method is equivalent
+     * to setting AUDIO_PARAMETER_STREAM_SAMPLING_RATE on the legacy HAL.
+     * Optional method. If implemented, only called on a stopped stream.
+     *
+     * @param sampleRateHz sample rate in Hz.
+     * @return retval operation completion status.
+     */
+    setSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+    /**
+     * Return the channel mask of the stream.
+     *
+     * @return mask channel mask.
+     */
+    getChannelMask() generates (bitfield<AudioChannelMask> mask);
+
+    /**
+     * Return supported channel masks of the stream. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_CHANNELS on the legacy
+     * HAL.
+     *
+     * @param format audio format for which the channel masks are supported.
+     * @return retval operation completion status.
+     *                Must be OK if the format is supported.
+     * @return masks supported audio masks.
+     */
+    getSupportedChannelMasks(AudioFormat format)
+            generates (Result retval, vec<bitfield<AudioChannelMask>> masks);
+
+    /**
+     * Sets the channel mask of the stream. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_STREAM_CHANNELS on the legacy HAL.
+     * Optional method
+     *
+     * @param format audio format.
+     * @return retval operation completion status.
+     */
+    setChannelMask(bitfield<AudioChannelMask> mask) generates (Result retval);
+
+    /**
+     * Return the audio format of the stream.
+     *
+     * @return format audio format.
+     */
+    getFormat() generates (AudioFormat format);
+
+    /**
+     * Return supported audio formats of the stream. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy
+     * HAL.
+     *
+     * @return retval operation completion status.
+     * @return formats supported audio formats.
+     *                 Must be non empty if retval is OK.
+     */
+    getSupportedFormats() generates (Result retval, vec<AudioFormat> formats);
+
+    /**
+     * Sets the audio format of the stream. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_STREAM_FORMAT on the legacy HAL.
+     * Optional method
+     *
+     * @param format audio format.
+     * @return retval operation completion status.
+     */
+    setFormat(AudioFormat format) generates (Result retval);
+
+    /**
+     * Convenience method for retrieving several stream parameters in
+     * one transaction.
+     *
+     * @return sampleRateHz sample rate in Hz.
+     * @return mask channel mask.
+     * @return format audio format.
+     */
+    getAudioProperties() generates (
+            uint32_t sampleRateHz, bitfield<AudioChannelMask> mask, AudioFormat format);
+
+    /**
+     * Applies audio effect to the stream.
+     *
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect to apply.
+     * @return retval operation completion status.
+     */
+    addEffect(uint64_t effectId) generates (Result retval);
+
+    /**
+     * Stops application of the effect to the stream.
+     *
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect to remove.
+     * @return retval operation completion status.
+     */
+    removeEffect(uint64_t effectId) generates (Result retval);
+
+    /**
+     * Put the audio hardware input/output into standby mode.
+     * Driver must exit from standby mode at the next I/O operation.
+     *
+     * @return retval operation completion status.
+     */
+    standby() generates (Result retval);
+
+    /**
+     * Return the set of devices which this stream is connected to.
+     * Optional method
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     * @return device set of devices which this stream is connected to.
+     */
+    getDevices() generates (Result retval, vec<DeviceAddress> devices);
+
+    /**
+     * Connects the stream to one or multiple devices.
+     *
+     * This method must only be used for HALs that do not support
+     * 'IDevice.createAudioPatch' method. Calling this method is
+     * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING preceded
+     * with a device address in the legacy HAL interface.
+     *
+     * @param address device to connect the stream to.
+     * @return retval operation completion status.
+     */
+    setDevices(vec<DeviceAddress> devices) generates (Result retval);
+
+    /**
+     * Sets the HW synchronization source. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_STREAM_HW_AV_SYNC on the legacy HAL.
+     * Optional method
+     *
+     * @param hwAvSync HW synchronization source
+     * @return retval operation completion status.
+     */
+    setHwAvSync(AudioHwSync hwAvSync) generates (Result retval);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be retrieved at the same time.
+     * The implementation should return as many requested parameters
+     * as possible, even if one or more is not supported
+     *
+     * @param context provides more information about the request
+     * @param keys keys of the requested parameters
+     * @return retval operation completion status.
+     *         OK must be returned if keys is empty.
+     *         NOT_SUPPORTED must be returned if at least one key is unknown.
+     * @return parameters parameter key value pairs.
+     *         Must contain the value of all requested keys if retval == OK
+     */
+    getParameters(vec<ParameterValue> context, vec<string> keys)
+            generates (Result retval, vec<ParameterValue> parameters);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be set at the same time though this is
+     * discouraged as it make failure analysis harder.
+     *
+     * If possible, a failed setParameters should not impact the platform state.
+     *
+     * @param context provides more information about the request
+     * @param parameters parameter key value pairs.
+     * @return retval operation completion status.
+     *         All parameters must be successfully set for OK to be returned
+     */
+    setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+            generates (Result retval);
+
+    /**
+     * Called by the framework to start a stream operating in mmap mode.
+     * createMmapBuffer() must be called before calling start().
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     */
+    start() generates (Result retval);
+
+    /**
+     * Called by the framework to stop a stream operating in mmap mode.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     */
+    stop() generates (Result retval) ;
+
+    /**
+     * Called by the framework to retrieve information on the mmap buffer used for audio
+     * samples transfer.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @param minSizeFrames minimum buffer size requested. The actual buffer
+     *                     size returned in struct MmapBufferInfo can be larger.
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                NOT_INITIALIZED in case of memory allocation error
+     *                INVALID_ARGUMENTS if the requested buffer size is invalid
+     *                INVALID_STATE if called out of sequence
+     * @return info    a MmapBufferInfo struct containing information on the MMMAP buffer created.
+     */
+    createMmapBuffer(int32_t minSizeFrames)
+            generates (Result retval, MmapBufferInfo info);
+
+    /**
+     * Called by the framework to read current read/write position in the mmap buffer
+     * with associated time stamp.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     * @return position a MmapPosition struct containing current HW read/write position in frames
+     *                  with associated time stamp.
+     */
+    getMmapPosition()
+            generates (Result retval, MmapPosition position);
+
+    /**
+     * Called by the framework to deinitialize the stream and free up
+     * all currently allocated resources. It is recommended to close
+     * the stream on the client side as soon as it is becomes unused.
+     *
+     * The client must ensure that this function is not called while
+     * audio data is being transferred through the stream's message queues.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED if called on IStream instead of input or
+     *                              output stream interface.
+     *                INVALID_STATE if the stream was already closed.
+     */
+    @exit
+    close() generates (Result retval);
+};
diff --git a/audio/6.0/IStreamIn.hal b/audio/6.0/IStreamIn.hal
new file mode 100644
index 0000000..aadc370
--- /dev/null
+++ b/audio/6.0/IStreamIn.hal
@@ -0,0 +1,199 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStream;
+
+interface IStreamIn extends IStream {
+    /**
+     * Returns the source descriptor of the input stream. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_STREAM_INPUT_SOURCE on the legacy
+     * HAL.
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return source audio source.
+     */
+    getAudioSource() generates (Result retval, AudioSource source);
+
+    /**
+     * Set the input gain for the audio driver.
+     * Optional method
+     *
+     * @param gain 1.0f is unity, 0.0f is zero.
+     * @result retval operation completion status.
+     */
+    setGain(float gain) generates (Result retval);
+
+    /**
+     * Commands that can be executed on the driver reader thread.
+     */
+    enum ReadCommand : int32_t {
+        READ,
+        GET_CAPTURE_POSITION
+    };
+
+    /**
+     * Data structure passed to the driver for executing commands
+     * on the driver reader thread.
+     */
+    struct ReadParameters {
+        ReadCommand command;  // discriminator
+        union Params {
+            uint64_t read;    // READ command, amount of bytes to read, >= 0.
+            // No parameters for GET_CAPTURE_POSITION.
+        } params;
+    };
+
+    /**
+     * Data structure passed back to the client via status message queue
+     * of 'read' operation.
+     *
+     * Possible values of 'retval' field:
+     *  - OK, read operation was successful;
+     *  - INVALID_ARGUMENTS, stream was not configured properly;
+     *  - INVALID_STATE, stream is in a state that doesn't allow reads.
+     */
+    struct ReadStatus {
+        Result retval;
+        ReadCommand replyTo;  // discriminator
+        union Reply {
+            uint64_t read;    // READ command, amount of bytes read, >= 0.
+            struct CapturePosition { // same as generated by getCapturePosition.
+                uint64_t frames;
+                uint64_t time;
+            } capturePosition;
+        } reply;
+    };
+
+    /**
+     * Called when the metadata of the stream's sink has been changed.
+     * @param sinkMetadata Description of the audio that is suggested by the clients.
+     */
+    updateSinkMetadata(SinkMetadata sinkMetadata);
+
+    /**
+     * Set up required transports for receiving audio buffers from the driver.
+     *
+     * The transport consists of three message queues:
+     *  -- command queue is used to instruct the reader thread what operation
+     *     to perform;
+     *  -- data queue is used for passing audio data from the driver
+     *     to the client;
+     *  -- status queue is used for reporting operation status
+     *     (e.g. amount of bytes actually read or error code).
+     *
+     * The driver operates on a dedicated thread. The client must ensure that
+     * the thread is given an appropriate priority and assigned to correct
+     * scheduler and cgroup. For this purpose, the method returns identifiers
+     * of the driver thread.
+     *
+     * @param frameSize the size of a single frame, in bytes.
+     * @param framesCount the number of frames in a buffer.
+     * @param threadPriority priority of the driver thread.
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queues.
+     * @return commandMQ a message queue used for passing commands.
+     * @return dataMQ a message queue used for passing audio data in the format
+     *                specified at the stream opening.
+     * @return statusMQ a message queue used for passing status from the driver
+     *                  using ReadStatus structures.
+     * @return threadInfo identifiers of the driver's dedicated thread.
+     */
+    prepareForReading(uint32_t frameSize, uint32_t framesCount)
+    generates (
+            Result retval,
+            fmq_sync<ReadParameters> commandMQ,
+            fmq_sync<uint8_t> dataMQ,
+            fmq_sync<ReadStatus> statusMQ,
+            ThreadInfo threadInfo);
+
+    /**
+     * Return the amount of input frames lost in the audio driver since the last
+     * call of this function.
+     *
+     * Audio driver is expected to reset the value to 0 and restart counting
+     * upon returning the current value by this function call. Such loss
+     * typically occurs when the user space process is blocked longer than the
+     * capacity of audio driver buffers.
+     *
+     * @return framesLost the number of input audio frames lost.
+     */
+    getInputFramesLost() generates (uint32_t framesLost);
+
+    /**
+     * Return a recent count of the number of audio frames received and the
+     * clock time associated with that frame count.
+     *
+     * @return retval INVALID_STATE if the device is not ready/available,
+     *                NOT_SUPPORTED if the command is not supported,
+     *                OK otherwise.
+     * @return frames the total frame count received. This must be as early in
+     *                the capture pipeline as possible. In general, frames
+     *                must be non-negative and must not go "backwards".
+     * @return time is the clock monotonic time when frames was measured. In
+     *              general, time must be a positive quantity and must not
+     *              go "backwards".
+     */
+    getCapturePosition()
+            generates (Result retval, uint64_t frames, uint64_t time);
+
+    /**
+     * Returns an array with active microphones in the stream.
+     *
+     * @return retval INVALID_STATE if the call is not successful,
+     *                OK otherwise.
+     *
+     * @return microphones array with microphones info
+     */
+    getActiveMicrophones()
+               generates(Result retval, vec<MicrophoneInfo> microphones);
+
+    /**
+     * Specifies the logical microphone (for processing).
+     *
+     * If the feature is not supported an error should be returned
+     * If multiple microphones are present, this should be treated as a preference
+     * for their combined direction.
+     *
+     * Optional method
+     *
+     * @param Direction constant
+     * @return retval OK if the call is successful, an error code otherwise.
+     */
+    setMicrophoneDirection(MicrophoneDirection direction)
+               generates(Result retval);
+
+    /**
+     * Specifies the zoom factor for the selected microphone (for processing).
+     *
+     * If the feature is not supported an error should be returned
+     * If multiple microphones are present, this should be treated as a preference
+     * for their combined field dimension.
+     *
+     * Optional method
+     *
+     * @param the desired field dimension of microphone capture. Range is from -1 (wide angle),
+     * though 0 (no zoom) to 1 (maximum zoom).
+     *
+     * @return retval OK if the call is not successful, an error code otherwise.
+     */
+    setMicrophoneFieldDimension(float zoom) generates(Result retval);
+};
diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal
new file mode 100644
index 0000000..941ba61
--- /dev/null
+++ b/audio/6.0/IStreamOut.hal
@@ -0,0 +1,279 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStream;
+import IStreamOutCallback;
+
+interface IStreamOut extends IStream {
+    /**
+     * Return the audio hardware driver estimated latency in milliseconds.
+     *
+     * @return latencyMs latency in milliseconds.
+     */
+    getLatency() generates (uint32_t latencyMs);
+
+    /**
+     * This method is used in situations where audio mixing is done in the
+     * hardware. This method serves as a direct interface with hardware,
+     * allowing to directly set the volume as apposed to via the framework.
+     * This method might produce multiple PCM outputs or hardware accelerated
+     * codecs, such as MP3 or AAC.
+     * Optional method
+     *
+     * @param left left channel attenuation, 1.0f is unity, 0.0f is zero.
+     * @param right right channel attenuation, 1.0f is unity, 0.0f is zero.
+     * @return retval operation completion status.
+     *        If a volume is outside [0,1], return INVALID_ARGUMENTS
+     */
+    setVolume(float left, float right) generates (Result retval);
+
+    /**
+     * Commands that can be executed on the driver writer thread.
+     */
+    enum WriteCommand : int32_t {
+        WRITE,
+        GET_PRESENTATION_POSITION,
+        GET_LATENCY
+    };
+
+    /**
+     * Data structure passed back to the client via status message queue
+     * of 'write' operation.
+     *
+     * Possible values of 'retval' field:
+     *  - OK, write operation was successful;
+     *  - INVALID_ARGUMENTS, stream was not configured properly;
+     *  - INVALID_STATE, stream is in a state that doesn't allow writes;
+     *  - INVALID_OPERATION, retrieving presentation position isn't supported.
+     */
+    struct WriteStatus {
+        Result retval;
+        WriteCommand replyTo;  // discriminator
+        union Reply {
+            uint64_t written;  // WRITE command, amount of bytes written, >= 0.
+            struct PresentationPosition {  // same as generated by
+                uint64_t frames;           // getPresentationPosition.
+                TimeSpec timeStamp;
+            } presentationPosition;
+            uint32_t latencyMs; // Same as generated by getLatency.
+        } reply;
+    };
+
+    /**
+     * Called when the metadata of the stream's source has been changed.
+     * @param sourceMetadata Description of the audio that is played by the clients.
+     */
+    updateSourceMetadata(SourceMetadata sourceMetadata);
+
+    /**
+     * Set up required transports for passing audio buffers to the driver.
+     *
+     * The transport consists of three message queues:
+     *  -- command queue is used to instruct the writer thread what operation
+     *     to perform;
+     *  -- data queue is used for passing audio data from the client
+     *     to the driver;
+     *  -- status queue is used for reporting operation status
+     *     (e.g. amount of bytes actually written or error code).
+     *
+     * The driver operates on a dedicated thread. The client must ensure that
+     * the thread is given an appropriate priority and assigned to correct
+     * scheduler and cgroup. For this purpose, the method returns identifiers
+     * of the driver thread.
+     *
+     * @param frameSize the size of a single frame, in bytes.
+     * @param framesCount the number of frames in a buffer.
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queues.
+     * @return commandMQ a message queue used for passing commands.
+     * @return dataMQ a message queue used for passing audio data in the format
+     *                specified at the stream opening.
+     * @return statusMQ a message queue used for passing status from the driver
+     *                  using WriteStatus structures.
+     * @return threadInfo identifiers of the driver's dedicated thread.
+     */
+    prepareForWriting(uint32_t frameSize, uint32_t framesCount)
+    generates (
+            Result retval,
+            fmq_sync<WriteCommand> commandMQ,
+            fmq_sync<uint8_t> dataMQ,
+            fmq_sync<WriteStatus> statusMQ,
+            ThreadInfo threadInfo);
+
+    /**
+     * Return the number of audio frames written by the audio DSP to DAC since
+     * the output has exited standby.
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return dspFrames number of audio frames written.
+     */
+    getRenderPosition() generates (Result retval, uint32_t dspFrames);
+
+    /**
+     * Get the local time at which the next write to the audio driver will be
+     * presented. The units are microseconds, where the epoch is decided by the
+     * local audio HAL.
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return timestampUs time of the next write.
+     */
+    getNextWriteTimestamp() generates (Result retval, int64_t timestampUs);
+
+    /**
+     * Set the callback interface for notifying completion of non-blocking
+     * write and drain.
+     *
+     * Calling this function implies that all future 'write' and 'drain'
+     * must be non-blocking and use the callback to signal completion.
+     *
+     * 'clearCallback' method needs to be called in order to release the local
+     * callback proxy on the server side and thus dereference the callback
+     * implementation on the client side.
+     *
+     * @return retval operation completion status.
+     */
+    setCallback(IStreamOutCallback callback) generates (Result retval);
+
+    /**
+     * Clears the callback previously set via 'setCallback' method.
+     *
+     * Warning: failure to call this method results in callback implementation
+     * on the client side being held until the HAL server termination.
+     *
+     * If no callback was previously set, the method should be a no-op
+     * and return OK.
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     */
+    clearCallback() generates (Result retval);
+
+    /**
+     * Returns whether HAL supports pausing and resuming of streams.
+     *
+     * @return supportsPause true if pausing is supported.
+     * @return supportsResume true if resume is supported.
+     */
+    supportsPauseAndResume()
+            generates (bool supportsPause, bool supportsResume);
+
+    /**
+     * Notifies to the audio driver to stop playback however the queued buffers
+     * are retained by the hardware. Useful for implementing pause/resume. Empty
+     * implementation if not supported however must be implemented for hardware
+     * with non-trivial latency. In the pause state, some audio hardware may
+     * still be using power. Client code may consider calling 'suspend' after a
+     * timeout to prevent that excess power usage.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    pause() generates (Result retval);
+
+    /**
+     * Notifies to the audio driver to resume playback following a pause.
+     * Returns error INVALID_STATE if called without matching pause.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    resume() generates (Result retval);
+
+    /**
+     * Returns whether HAL supports draining of streams.
+     *
+     * @return supports true if draining is supported.
+     */
+    supportsDrain() generates (bool supports);
+
+    /**
+     * Requests notification when data buffered by the driver/hardware has been
+     * played. If 'setCallback' has previously been called to enable
+     * non-blocking mode, then 'drain' must not block, instead it must return
+     * quickly and completion of the drain is notified through the callback. If
+     * 'setCallback' has not been called, then 'drain' must block until
+     * completion.
+     *
+     * If 'type' is 'ALL', the drain completes when all previously written data
+     * has been played.
+     *
+     * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data
+     * for the current track has played to allow time for the framework to
+     * perform a gapless track switch.
+     *
+     * Drain must return immediately on 'stop' and 'flush' calls.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @param type type of drain.
+     * @return retval operation completion status.
+     */
+    drain(AudioDrain type) generates (Result retval);
+
+    /**
+     * Notifies to the audio driver to flush the queued data. Stream must
+     * already be paused before calling 'flush'.
+     * Optional method
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    flush() generates (Result retval);
+
+    /**
+     * Return a recent count of the number of audio frames presented to an
+     * external observer. This excludes frames which have been written but are
+     * still in the pipeline. The count is not reset to zero when output enters
+     * standby. Also returns the value of CLOCK_MONOTONIC as of this
+     * presentation count. The returned count is expected to be 'recent', but
+     * does not need to be the most recent possible value. However, the
+     * associated time must correspond to whatever count is returned.
+     *
+     * Example: assume that N+M frames have been presented, where M is a 'small'
+     * number. Then it is permissible to return N instead of N+M, and the
+     * timestamp must correspond to N rather than N+M. The terms 'recent' and
+     * 'small' are not defined. They reflect the quality of the implementation.
+     *
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return frames count of presented audio frames.
+     * @return timeStamp associated clock time.
+     */
+    getPresentationPosition()
+            generates (Result retval, uint64_t frames, TimeSpec timeStamp);
+
+    /**
+     * Selects a presentation for decoding from a next generation media stream
+     * (as defined per ETSI TS 103 190-2) and a program within the presentation.
+     * Optional method
+     *
+     * @param presentationId selected audio presentation.
+     * @param programId refinement for the presentation.
+     * @return retval operation completion status.
+     */
+    selectPresentation(int32_t presentationId, int32_t programId)
+            generates (Result retval);
+};
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/audio/6.0/IStreamOutCallback.hal
similarity index 64%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to audio/6.0/IStreamOutCallback.hal
index 8bb72a1..e393d9a 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/audio/6.0/IStreamOutCallback.hal
@@ -14,13 +14,24 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
+package android.hardware.audio@6.0;
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
+/**
+ * Asynchronous write callback interface.
+ */
+interface IStreamOutCallback {
+    /**
+     * Non blocking write completed.
+     */
+    oneway onWriteReady();
 
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
+    /**
+     * Drain completed.
+     */
+    oneway onDrainReady();
 
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+    /**
+     * Stream hit an error.
+     */
+    oneway onError();
+};
diff --git a/audio/6.0/config/Android.bp b/audio/6.0/config/Android.bp
new file mode 100644
index 0000000..182dfcc
--- /dev/null
+++ b/audio/6.0/config/Android.bp
@@ -0,0 +1,7 @@
+
+xsd_config {
+    name: "audio_policy_configuration_V6_0",
+    srcs: ["audio_policy_configuration.xsd"],
+    package_name: "audio.policy.configuration.V6_0",
+}
+
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
new file mode 100644
index 0000000..431bc90
--- /dev/null
+++ b/audio/6.0/config/api/current.txt
@@ -0,0 +1,424 @@
+// Signature format: 2.0
+package audio.policy.configuration.V6_0 {
+
+  public class AttachedDevices {
+    ctor public AttachedDevices();
+    method public java.util.List<java.lang.String> getItem();
+  }
+
+  public enum AudioDevice {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BACK_MIC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BUS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_DEFAULT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_HDMI;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_IP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_LINE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_PROXY;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_SPDIF;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_STUB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_TV_TUNER;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_NONE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BUS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_DEFAULT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_EARPIECE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_FM;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HDMI;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_IP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_LINE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_PROXY;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_STUB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
+  }
+
+  public enum AudioFormat {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADIF;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ELD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ERLC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_HE_V1;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_HE_V2;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_LC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LTP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_MAIN;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_SCALABLE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_SSR;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_XHE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AC3;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AC4;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_ALAC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_NB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_WB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_HD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_TWSP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_CELT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DSD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS_HD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCNW;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCWB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_E_AC3;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_FLAC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_IEC61937;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LDAC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LHDC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LHDC_LL;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_1_0;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_2_0;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_2_1;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MP2;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MP3;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_OPUS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_16_BIT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_32_BIT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_8_BIT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_FLOAT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_QCELP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_SBC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_VORBIS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_WMA;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_WMA_PRO;
+  }
+
+  public class AudioPolicyConfiguration {
+    ctor public AudioPolicyConfiguration();
+    method public audio.policy.configuration.V6_0.GlobalConfiguration getGlobalConfiguration();
+    method public java.util.List<audio.policy.configuration.V6_0.Modules> getModules();
+    method public audio.policy.configuration.V6_0.SurroundSound getSurroundSound();
+    method public audio.policy.configuration.V6_0.Version getVersion();
+    method public java.util.List<audio.policy.configuration.V6_0.Volumes> getVolumes();
+    method public void setGlobalConfiguration(audio.policy.configuration.V6_0.GlobalConfiguration);
+    method public void setSurroundSound(audio.policy.configuration.V6_0.SurroundSound);
+    method public void setVersion(audio.policy.configuration.V6_0.Version);
+  }
+
+  public enum AudioUsage {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ALARM;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_GAME;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_MEDIA;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_NOTIFICATION;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_UNKNOWN;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+  }
+
+  public enum DeviceCategory {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+    enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+    enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+    enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+  }
+
+  public class DevicePorts {
+    ctor public DevicePorts();
+    method public java.util.List<audio.policy.configuration.V6_0.DevicePorts.DevicePort> getDevicePort();
+  }
+
+  public static class DevicePorts.DevicePort {
+    ctor public DevicePorts.DevicePort();
+    method public String getAddress();
+    method public java.util.List<audio.policy.configuration.V6_0.AudioFormat> getEncodedFormats();
+    method public audio.policy.configuration.V6_0.Gains getGains();
+    method public java.util.List<audio.policy.configuration.V6_0.Profile> getProfile();
+    method public audio.policy.configuration.V6_0.Role getRole();
+    method public String getTagName();
+    method public String getType();
+    method public boolean get_default();
+    method public void setAddress(String);
+    method public void setEncodedFormats(java.util.List<audio.policy.configuration.V6_0.AudioFormat>);
+    method public void setGains(audio.policy.configuration.V6_0.Gains);
+    method public void setRole(audio.policy.configuration.V6_0.Role);
+    method public void setTagName(String);
+    method public void setType(String);
+    method public void set_default(boolean);
+  }
+
+  public enum GainMode {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_CHANNELS;
+    enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_JOINT;
+    enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_RAMP;
+  }
+
+  public class Gains {
+    ctor public Gains();
+    method public java.util.List<audio.policy.configuration.V6_0.Gains.Gain> getGain();
+  }
+
+  public static class Gains.Gain {
+    ctor public Gains.Gain();
+    method public String getChannel_mask();
+    method public int getDefaultValueMB();
+    method public int getMaxRampMs();
+    method public int getMaxValueMB();
+    method public int getMinRampMs();
+    method public int getMinValueMB();
+    method public audio.policy.configuration.V6_0.GainMode getMode();
+    method public String getName();
+    method public int getStepValueMB();
+    method public boolean getUseForVolume();
+    method public void setChannel_mask(String);
+    method public void setDefaultValueMB(int);
+    method public void setMaxRampMs(int);
+    method public void setMaxValueMB(int);
+    method public void setMinRampMs(int);
+    method public void setMinValueMB(int);
+    method public void setMode(audio.policy.configuration.V6_0.GainMode);
+    method public void setName(String);
+    method public void setStepValueMB(int);
+    method public void setUseForVolume(boolean);
+  }
+
+  public class GlobalConfiguration {
+    ctor public GlobalConfiguration();
+    method public boolean getSpeaker_drc_enabled();
+    method public void setSpeaker_drc_enabled(boolean);
+  }
+
+  public enum HalVersion {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.HalVersion _2_0;
+    enum_constant public static final audio.policy.configuration.V6_0.HalVersion _3_0;
+  }
+
+  public class MixPorts {
+    ctor public MixPorts();
+    method public java.util.List<audio.policy.configuration.V6_0.MixPorts.MixPort> getMixPort();
+  }
+
+  public static class MixPorts.MixPort {
+    ctor public MixPorts.MixPort();
+    method public String getFlags();
+    method public audio.policy.configuration.V6_0.Gains getGains();
+    method public long getMaxActiveCount();
+    method public long getMaxOpenCount();
+    method public String getName();
+    method public java.util.List<audio.policy.configuration.V6_0.AudioUsage> getPreferredUsage();
+    method public java.util.List<audio.policy.configuration.V6_0.Profile> getProfile();
+    method public audio.policy.configuration.V6_0.Role getRole();
+    method public void setFlags(String);
+    method public void setGains(audio.policy.configuration.V6_0.Gains);
+    method public void setMaxActiveCount(long);
+    method public void setMaxOpenCount(long);
+    method public void setName(String);
+    method public void setPreferredUsage(java.util.List<audio.policy.configuration.V6_0.AudioUsage>);
+    method public void setRole(audio.policy.configuration.V6_0.Role);
+  }
+
+  public enum MixType {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.MixType mix;
+    enum_constant public static final audio.policy.configuration.V6_0.MixType mux;
+  }
+
+  public class Modules {
+    ctor public Modules();
+    method public java.util.List<audio.policy.configuration.V6_0.Modules.Module> getModule();
+  }
+
+  public static class Modules.Module {
+    ctor public Modules.Module();
+    method public audio.policy.configuration.V6_0.AttachedDevices getAttachedDevices();
+    method public String getDefaultOutputDevice();
+    method public audio.policy.configuration.V6_0.DevicePorts getDevicePorts();
+    method public audio.policy.configuration.V6_0.HalVersion getHalVersion();
+    method public audio.policy.configuration.V6_0.MixPorts getMixPorts();
+    method public String getName();
+    method public audio.policy.configuration.V6_0.Routes getRoutes();
+    method public void setAttachedDevices(audio.policy.configuration.V6_0.AttachedDevices);
+    method public void setDefaultOutputDevice(String);
+    method public void setDevicePorts(audio.policy.configuration.V6_0.DevicePorts);
+    method public void setHalVersion(audio.policy.configuration.V6_0.HalVersion);
+    method public void setMixPorts(audio.policy.configuration.V6_0.MixPorts);
+    method public void setName(String);
+    method public void setRoutes(audio.policy.configuration.V6_0.Routes);
+  }
+
+  public class Profile {
+    ctor public Profile();
+    method public String getChannelMasks();
+    method public String getFormat();
+    method public String getName();
+    method public String getSamplingRates();
+    method public void setChannelMasks(String);
+    method public void setFormat(String);
+    method public void setName(String);
+    method public void setSamplingRates(String);
+  }
+
+  public class Reference {
+    ctor public Reference();
+    method public String getName();
+    method public java.util.List<java.lang.String> getPoint();
+    method public void setName(String);
+  }
+
+  public enum Role {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.Role sink;
+    enum_constant public static final audio.policy.configuration.V6_0.Role source;
+  }
+
+  public class Routes {
+    ctor public Routes();
+    method public java.util.List<audio.policy.configuration.V6_0.Routes.Route> getRoute();
+  }
+
+  public static class Routes.Route {
+    ctor public Routes.Route();
+    method public String getSink();
+    method public String getSources();
+    method public audio.policy.configuration.V6_0.MixType getType();
+    method public void setSink(String);
+    method public void setSources(String);
+    method public void setType(audio.policy.configuration.V6_0.MixType);
+  }
+
+  public enum Stream {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ACCESSIBILITY;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ALARM;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_BLUETOOTH_SCO;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_DTMF;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_MUSIC;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_NOTIFICATION;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_PATCH;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_REROUTING;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_RING;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_SYSTEM;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_TTS;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_VOICE_CALL;
+  }
+
+  public class SurroundFormats {
+    ctor public SurroundFormats();
+    method public java.util.List<audio.policy.configuration.V6_0.SurroundFormats.Format> getFormat();
+  }
+
+  public static class SurroundFormats.Format {
+    ctor public SurroundFormats.Format();
+    method public audio.policy.configuration.V6_0.AudioFormat getName();
+    method public java.util.List<audio.policy.configuration.V6_0.AudioFormat> getSubformats();
+    method public void setName(audio.policy.configuration.V6_0.AudioFormat);
+    method public void setSubformats(java.util.List<audio.policy.configuration.V6_0.AudioFormat>);
+  }
+
+  public class SurroundSound {
+    ctor public SurroundSound();
+    method public audio.policy.configuration.V6_0.SurroundFormats getFormats();
+    method public void setFormats(audio.policy.configuration.V6_0.SurroundFormats);
+  }
+
+  public enum Version {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.Version _1_0;
+  }
+
+  public class Volume {
+    ctor public Volume();
+    method public audio.policy.configuration.V6_0.DeviceCategory getDeviceCategory();
+    method public java.util.List<java.lang.String> getPoint();
+    method public String getRef();
+    method public audio.policy.configuration.V6_0.Stream getStream();
+    method public void setDeviceCategory(audio.policy.configuration.V6_0.DeviceCategory);
+    method public void setRef(String);
+    method public void setStream(audio.policy.configuration.V6_0.Stream);
+  }
+
+  public class Volumes {
+    ctor public Volumes();
+    method public java.util.List<audio.policy.configuration.V6_0.Reference> getReference();
+    method public java.util.List<audio.policy.configuration.V6_0.Volume> getVolume();
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static audio.policy.configuration.V6_0.AudioPolicyConfiguration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/tests/pointer/1.0/.hidl_for_test b/audio/6.0/config/api/last_current.txt
similarity index 100%
copy from tests/pointer/1.0/.hidl_for_test
copy to audio/6.0/config/api/last_current.txt
diff --git a/tests/pointer/1.0/.hidl_for_test b/audio/6.0/config/api/last_removed.txt
similarity index 100%
copy from tests/pointer/1.0/.hidl_for_test
copy to audio/6.0/config/api/last_removed.txt
diff --git a/audio/6.0/config/api/removed.txt b/audio/6.0/config/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/6.0/config/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..d0f80ea
--- /dev/null
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -0,0 +1,625 @@
+<?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.
+-->
+<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
+<xs:schema version="2.0"
+           elementFormDefault="qualified"
+           attributeFormDefault="unqualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <!-- List the config versions supported by audio policy. -->
+    <xs:simpleType name="version">
+        <xs:restriction base="xs:decimal">
+            <xs:enumeration value="1.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="halVersion">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Version of the interface the hal implements.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:decimal">
+            <!-- List of HAL versions supported by the framework. -->
+            <xs:enumeration value="2.0"/>
+            <xs:enumeration value="3.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="audioPolicyConfiguration">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="globalConfiguration" type="globalConfiguration"/>
+                <xs:element name="modules" type="modules" maxOccurs="unbounded"/>
+                <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/>
+                <xs:element name="surroundSound" type="surroundSound" minOccurs="0" />
+            </xs:sequence>
+            <xs:attribute name="version" type="version"/>
+        </xs:complexType>
+        <xs:key name="moduleNameKey">
+            <xs:selector xpath="modules/module"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:unique name="volumeTargetUniqueness">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@stream"/>
+            <xs:field xpath="@deviceCategory"/>
+        </xs:unique>
+        <xs:key name="volumeCurveNameKey">
+            <xs:selector xpath="volumes/reference"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@ref"/>
+        </xs:keyref>
+    </xs:element>
+    <xs:complexType name="globalConfiguration">
+        <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="modules">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                There should be one section per audio HW module present on the platform.
+                Each <module/> contains two mandatory tags: “halVersion” and “name”.
+                The module "name" is the same as in previous .conf file.
+                Each module must contain the following sections:
+                 - <devicePorts/>: a list of device descriptors for all
+                   input and output devices accessible via this module.
+                   This contains both permanently attached devices and removable devices.
+                 - <mixPorts/>: listing all output and input streams exposed by the audio HAL
+                 - <routes/>: list of possible connections between input
+                   and output devices or between stream and devices.
+                   A <route/> is defined by a set of 3 attributes:
+                        -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix)
+                        -"sink": the sink involved in this route
+                        -"sources": all the sources than can be connected to the sink via this route
+                 - <attachedDevices/>: permanently attached devices.
+                   The attachedDevices section is a list of devices names.
+                   Their names correspond to device names defined in "devicePorts" section.
+                 - <defaultOutputDevice/> is the device to be used when no policy rule applies
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="module" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0">
+                            <xs:unique name="attachedDevicesUniqueness">
+                                <xs:selector xpath="item"/>
+                                <xs:field xpath="."/>
+                            </xs:unique>
+                        </xs:element>
+                        <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/>
+                        <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/>
+                        <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
+                        <xs:element name="routes" type="routes" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:string" use="required"/>
+                    <xs:attribute name="halVersion" type="halVersion" use="required"/>
+                </xs:complexType>
+                <xs:unique name="mixPortNameUniqueness">
+                    <xs:selector xpath="mixPorts/mixPort"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+                <xs:key name="devicePortNameKey">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@tagName"/>
+                </xs:key>
+                <xs:unique name="devicePortUniqueness">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@type"/>
+                    <xs:field xpath="@address"/>
+                </xs:unique>
+                <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="defaultOutputDevice"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="attachedDevices/item"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <!-- The following 3 constraints try to make sure each sink port
+                     is reference in one an only one route. -->
+                <xs:key name="routeSinkKey">
+                    <!-- predicate [@type='sink'] does not work in xsd 1.0 -->
+                    <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/>
+                    <xs:field xpath="@tagName|@name"/>
+                </xs:key>
+                <xs:keyref name="routeSinkRef" refer="routeSinkKey">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:keyref>
+                <xs:unique name="routeUniqueness">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="attachedDevices">
+        <xs:sequence>
+            <xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- TODO: separate values by space for better xsd validations. -->
+    <xs:simpleType name="audioInOutFlags">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                "|" separated list of audio_output_flags_t or audio_input_flags_t.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="|[_A-Z]+(\|[_A-Z]+)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="role">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="sink"/>
+            <xs:enumeration value="source"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="mixPorts">
+        <xs:sequence>
+            <xs:element name="mixPort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:token" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="flags" type="audioInOutFlags"/>
+                    <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/>
+                    <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/>
+                    <xs:attribute name="preferredUsage" type="audioUsageList">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                When choosing the mixPort of an audio track, the audioPolicy
+                                first considers the mixPorts with a preferredUsage including
+                                the track AudioUsage preferred .
+                                If non support the track format, the other mixPorts are considered.
+                                Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive
+                                    the audio of all apps playing with a MEDIA usage.
+                                    It may receive audio from ALARM if there are no audio compatible
+                                    <mixPort preferredUsage="AUDIO_USAGE_ALARM" />.
+                             </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                </xs:complexType>
+                <xs:unique name="mixPortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="mixPortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- Enum values of audio_device_t in audio.h
+         TODO: generate from hidl to avoid manual sync.
+         TODO: separate source and sink in the xml for better xsd validations. -->
+    <xs:simpleType name="audioDevice">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_DEVICE_NONE"/>
+
+            <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/>
+
+            <!-- Due to the xml format, IN types can not be a separated from OUT types -->
+            <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="vendorExtension">
+        <!-- Vendor extension names must be prefixed by "VX_" to distinguish them from AOSP values.
+             Vendor are encouraged to namespace their module names to avoid conflicts.
+             Example for an hypothetical Google virtual reality device:
+                <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink">
+        -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="VX_[_a-zA-Z0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="extendableAudioDevice">
+        <xs:union memberTypes="audioDevice vendorExtension"/>
+    </xs:simpleType>
+    <!-- Enum values of audio_format_t in audio.h
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="audioFormat">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
+            <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRC"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP2"/>
+            <xs:enumeration value="AUDIO_FORMAT_QCELP"/>
+            <xs:enumeration value="AUDIO_FORMAT_DSD"/>
+            <xs:enumeration value="AUDIO_FORMAT_FLAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_ALAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_SBC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC4"/>
+            <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_CELT"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE"/>
+            <xs:enumeration value="AUDIO_FORMAT_LHDC"/>
+            <xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_TWSP"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="extendableAudioFormat">
+        <xs:union memberTypes="audioFormat vendorExtension"/>
+    </xs:simpleType>
+    <!-- Enum values of audio::common::4_0::AudioUsage
+         TODO: generate from HIDL to avoid manual sync. -->
+    <xs:simpleType name="audioUsage">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
+            <xs:enumeration value="AUDIO_USAGE_MEDIA" />
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+            <xs:enumeration value="AUDIO_USAGE_ALARM" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+            <xs:enumeration value="AUDIO_USAGE_GAME" />
+            <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioUsageList">
+        <xs:list itemType="audioUsage"/>
+    </xs:simpleType>
+    <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
+    <xs:simpleType name="samplingRates">
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[0-9]+(,[0-9]+)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
+    <xs:simpleType name="channelMask">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Comma (",") separated list of channel flags
+                from audio_channel_mask_t.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[_A-Z][_A-Z0-9]*(,[_A-Z][_A-Z0-9]*)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="profile">
+        <xs:attribute name="name" type="xs:token" use="optional"/>
+        <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
+        <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
+        <xs:attribute name="channelMasks" type="channelMask" use="optional"/>
+    </xs:complexType>
+    <xs:simpleType name="gainMode">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_GAIN_MODE_JOINT"/>
+            <xs:enumeration value="AUDIO_GAIN_MODE_CHANNELS"/>
+            <xs:enumeration value="AUDIO_GAIN_MODE_RAMP"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="gains">
+        <xs:sequence>
+            <xs:element name="gain" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="xs:token" use="required"/>
+                    <xs:attribute name="mode" type="gainMode" use="required"/>
+                    <xs:attribute name="channel_mask" type="channelMask" use="optional"/>
+                    <xs:attribute name="minValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="maxValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="defaultValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
+                    <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+                    <xs:attribute name="useForVolume" type="xs:boolean" use="optional"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="devicePorts">
+        <xs:sequence>
+            <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="tagName" type="xs:token" use="required"/>
+                    <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="address" type="xs:string" use="optional" default=""/>
+                    <!-- Note that XSD 1.0 can not check that a type only has one default. -->
+                    <xs:attribute name="default" type="xs:boolean" use="optional">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                The default device will be used if multiple have the same type
+                                and no explicit route request exists for a specific device of
+                                that type.
+                            </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                    <xs:attribute name="encodedFormats" type="audioFormatsList" use="optional"
+                                  default="" />
+                </xs:complexType>
+                <xs:unique name="devicePortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="devicePortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="mixType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="mix"/>
+            <xs:enumeration value="mux"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="routes">
+        <xs:sequence>
+            <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+                <xs:annotation>
+                    <xs:documentation xml:lang="en">
+                        List all available sources for a given sink.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:complexType>
+                    <xs:attribute name="type" type="mixType" use="required"/>
+                    <xs:attribute name="sink" type="xs:string" use="required"/>
+                    <xs:attribute name="sources" type="xs:string" use="required"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="volumes">
+        <xs:sequence>
+            <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded">
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- TODO: Always require a ref for better xsd validations.
+               Currently a volume could have no points nor ref
+               as it can not be forbidden by xsd 1.0.-->
+    <xs:simpleType name="volumePoint">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Comma separated pair of number.
+                The fist one is the framework level (between 0 and 100).
+                The second one is the volume to send to the HAL.
+                The framework will interpolate volumes not specified.
+                Their MUST be at least 2 points specified.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of audio_stream_type_t in audio-base.h
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="stream">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+            <xs:enumeration value="AUDIO_STREAM_RING"/>
+            <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+            <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+            <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+            <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+            <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+            <xs:enumeration value="AUDIO_STREAM_TTS"/>
+            <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+            <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
+            <xs:enumeration value="AUDIO_STREAM_PATCH"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of device_category from Volume.h.
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="deviceCategory">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+            <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+            <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="volume">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Volume section defines a volume curve for a given use case and device category.
+                It contains a list of points of this curve expressing the attenuation in Millibels
+                for a given volume index from 0 to 100.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </volume>
+
+                It may also reference a reference/@name to avoid duplicating curves.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                        ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+                <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </reference>
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="stream" type="stream"/>
+        <xs:attribute name="deviceCategory" type="deviceCategory"/>
+        <xs:attribute name="ref" type="xs:token" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="reference">
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="name" type="xs:token" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="surroundSound">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Surround Sound section provides configuration related to handling of
+                multi-channel formats.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="formats" type="surroundFormats"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="audioFormatsList">
+        <xs:list itemType="audioFormat" />
+    </xs:simpleType>
+    <xs:complexType name="surroundFormats">
+        <xs:sequence>
+            <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="audioFormat" use="required"/>
+                    <xs:attribute name="subformats" type="audioFormatsList" />
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+</xs:schema>
diff --git a/audio/6.0/types.hal b/audio/6.0/types.hal
new file mode 100644
index 0000000..1a704f8
--- /dev/null
+++ b/audio/6.0/types.hal
@@ -0,0 +1,249 @@
+/*
+ * 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.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+
+enum Result : int32_t {
+    OK,
+    NOT_INITIALIZED,
+    INVALID_ARGUMENTS,
+    INVALID_STATE,
+    /**
+     * Methods marked as "Optional method" must return this result value
+     * if the operation is not supported by HAL.
+     */
+    NOT_SUPPORTED
+};
+
+@export(name="audio_drain_type_t", value_prefix="AUDIO_DRAIN_")
+enum AudioDrain : int32_t {
+    /** drain() returns when all data has been played. */
+    ALL,
+    /**
+     * drain() returns a short time before all data from the current track has
+     * been played to give time for gapless track switch.
+     */
+    EARLY_NOTIFY
+};
+
+/**
+ * A substitute for POSIX timespec.
+ */
+struct TimeSpec {
+    uint64_t tvSec;   // seconds
+    uint64_t tvNSec;  // nanoseconds
+};
+
+struct ParameterValue {
+    string key;
+    string value;
+};
+
+enum MmapBufferFlag : uint32_t {
+    NONE    = 0x0,
+    /**
+     * If the buffer can be securely shared to untrusted applications
+     * through the AAudio exclusive mode.
+     * Only set this flag if applications are restricted from accessing the
+     * memory surrounding the audio data buffer by a kernel mechanism.
+     * See Linux kernel's dma_buf.
+     */
+    APPLICATION_SHAREABLE    = 0x1,
+};
+
+/**
+ * Mmap buffer descriptor returned by IStream.createMmapBuffer().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapBufferInfo {
+    /** Mmap memory buffer */
+    memory  sharedMemory;
+    /** Total buffer size in frames */
+    uint32_t bufferSizeFrames;
+    /** Transfer size granularity in frames */
+    uint32_t burstSizeFrames;
+    /** Attributes describing the buffer. */
+    bitfield<MmapBufferFlag> flags;
+};
+
+/**
+ * Mmap buffer read/write position returned by IStream.getMmapPosition().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapPosition {
+    int64_t  timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC
+    int32_t  positionFrames;  // increasing 32 bit frame count reset when IStream.stop() is called
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * message queues used by StreamIn and StreamOut.
+ */
+enum MessageQueueFlagBits : uint32_t {
+    NOT_EMPTY = 1 << 0,
+    NOT_FULL = 1 << 1
+};
+
+/*
+ * Microphone information
+ *
+ */
+
+/**
+ * A 3D point used to represent position or orientation of a microphone.
+ *
+ * Position: Coordinates of the microphone's capsule, in meters, from the
+ * bottom-left-back corner of the bounding box of android device in natural
+ * orientation (PORTRAIT for phones, LANDSCAPE for tablets, tvs, etc).
+ * The orientation musth match the reported by the api Display.getRotation().
+ *
+ * Orientation: Normalized vector to signal the main orientation of the
+ * microphone's capsule. Magnitude = sqrt(x^2 + y^2 + z^2) = 1
+ */
+struct AudioMicrophoneCoordinate {
+    float x;
+    float y;
+    float z;
+};
+
+/**
+ * Enum to identify the type of channel mapping for active microphones.
+ * Used channels further identify if the microphone has any significative
+ * process (e.g. High Pass Filtering, dynamic compression)
+ * Simple processing as constant gain adjustment must be DIRECT.
+ */
+enum AudioMicrophoneChannelMapping : uint32_t {
+    UNUSED      = 0, /* Channel not used */
+    DIRECT      = 1, /* Channel used and signal not processed */
+    PROCESSED   = 2, /* Channel used and signal has some process */
+};
+
+/**
+ * Enum to identify locations of microphones in regards to the body of the
+ * android device.
+ */
+enum AudioMicrophoneLocation : uint32_t {
+    UNKNOWN             = 0,
+    MAINBODY            = 1,
+    MAINBODY_MOVABLE    = 2,
+    PERIPHERAL          = 3,
+};
+
+/**
+ * Identifier to help group related microphones together
+ * e.g. microphone arrays should belong to the same group
+ */
+typedef int32_t AudioMicrophoneGroup;
+
+/**
+ * Enum with standard polar patterns of microphones
+ */
+enum AudioMicrophoneDirectionality : uint32_t {
+    UNKNOWN         = 0,
+    OMNI            = 1,
+    BI_DIRECTIONAL  = 2,
+    CARDIOID        = 3,
+    HYPER_CARDIOID  = 4,
+    SUPER_CARDIOID  = 5,
+};
+
+/**
+ * A (frequency, level) pair. Used to represent frequency response.
+ */
+struct AudioFrequencyResponsePoint {
+    /** In Hz */
+    float frequency;
+    /** In dB */
+    float level;
+};
+
+/**
+ * Structure used by the HAL to describe microphone's characteristics
+ * Used by StreamIn and Device
+ */
+struct MicrophoneInfo {
+    /** Unique alphanumeric id for microphone. Guaranteed to be the same
+     * even after rebooting.
+     */
+    string                                  deviceId;
+    /**
+     * Device specific information
+     */
+    DeviceAddress                           deviceAddress;
+    /** Each element of the vector must describe the channel with the same
+     *  index.
+     */
+    vec<AudioMicrophoneChannelMapping>      channelMapping;
+    /** Location of the microphone in regard to the body of the device */
+    AudioMicrophoneLocation                 location;
+    /** Identifier to help group related microphones together
+     *  e.g. microphone arrays should belong to the same group
+     */
+    AudioMicrophoneGroup                    group;
+    /** Index of this microphone within the group.
+     *  (group, index) must be unique within the same device.
+     */
+    uint32_t                                indexInTheGroup;
+    /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */
+    float                                   sensitivity;
+    /** Level in dB of the max SPL supported at 1000 Hz */
+    float                                   maxSpl;
+    /** Level in dB of the min SPL supported at 1000 Hz */
+    float                                   minSpl;
+    /** Standard polar pattern of the microphone */
+    AudioMicrophoneDirectionality           directionality;
+    /** Vector with ordered frequency responses (from low to high frequencies)
+     *  with the frequency response of the microphone.
+     *  Levels are in dB, relative to level at 1000 Hz
+     */
+    vec<AudioFrequencyResponsePoint>        frequencyResponse;
+    /** Position of the microphone's capsule in meters, from the
+     *  bottom-left-back corner of the bounding box of device.
+     */
+    AudioMicrophoneCoordinate               position;
+    /** Normalized point to signal the main orientation of the microphone's
+     *  capsule. sqrt(x^2 + y^2 + z^2) = 1
+     */
+    AudioMicrophoneCoordinate               orientation;
+};
+
+/**
+ * Constants used by the HAL to determine how to select microphones and process those inputs in
+ * order to optimize for capture in the specified direction.
+ *
+ * MicrophoneDirection Constants are defined in MicrophoneDirection.java.
+ */
+@export(name="audio_microphone_direction_t", value_prefix="MIC_DIRECTION_")
+enum MicrophoneDirection : int32_t {
+    /**
+     * Don't do any directionality processing of the activated microphone(s).
+     */
+    UNSPECIFIED = 0,
+    /**
+     * Optimize capture for audio coming from the screen-side of the device.
+     */
+    FRONT = 1,
+    /**
+     * Optimize capture for audio coming from the side of the device opposite the screen.
+     */
+    BACK = 2,
+    /**
+     * Optimize capture for audio coming from an off-device microphone.
+     */
+    EXTERNAL = 3,
+};
diff --git a/audio/common/2.0/Android.bp b/audio/common/2.0/Android.bp
index a64548f..bd3b069 100644
--- a/audio/common/2.0/Android.bp
+++ b/audio/common/2.0/Android.bp
@@ -9,7 +9,6 @@
     srcs: [
         "types.hal",
     ],
-    gen_java: false,
+    gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/audio/common/4.0/Android.bp b/audio/common/4.0/Android.bp
index cd504e5..c01c486 100644
--- a/audio/common/4.0/Android.bp
+++ b/audio/common/4.0/Android.bp
@@ -9,7 +9,6 @@
     srcs: [
         "types.hal",
     ],
-    gen_java: false,
+    gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/audio/common/5.0/Android.bp b/audio/common/5.0/Android.bp
index 66c6fe8..761c171 100644
--- a/audio/common/5.0/Android.bp
+++ b/audio/common/5.0/Android.bp
@@ -12,7 +12,6 @@
     interfaces: [
         "android.hidl.safe_union@1.0",
     ],
-    gen_java: false,
+    gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/audio/common/6.0/Android.bp b/audio/common/6.0/Android.bp
new file mode 100644
index 0000000..94f1cf8
--- /dev/null
+++ b/audio/common/6.0/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio.common@6.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: true,
+    gen_java_constants: true,
+}
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
new file mode 100644
index 0000000..132f86d
--- /dev/null
+++ b/audio/common/6.0/types.hal
@@ -0,0 +1,1032 @@
+/*
+ * 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.audio.common@6.0;
+
+import android.hidl.safe_union@1.0;
+
+/*
+ *
+ *  IDs and Handles
+ *
+ */
+
+/**
+ * Handle type for identifying audio sources and sinks.
+ */
+typedef int32_t AudioIoHandle;
+
+/**
+ * Audio hw module handle functions or structures referencing a module.
+ */
+typedef int32_t AudioModuleHandle;
+
+/**
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+typedef int32_t AudioPortHandle;
+
+/**
+ * Each patch is identified by a handle at the interface used to create that
+ * patch. For instance, when a patch is created by the audio HAL, the HAL
+ * allocates and returns a handle.  This handle is unique to a given audio HAL
+ * hardware module.  But the same patch receives another system wide unique
+ * handle allocated by the framework.  This unique handle is used for all
+ * transactions inside the framework.
+ */
+typedef int32_t AudioPatchHandle;
+
+/**
+ * A HW synchronization source returned by the audio HAL.
+ */
+typedef uint32_t AudioHwSync;
+
+/**
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+@export(name="")
+enum AudioHandleConsts : int32_t {
+    AUDIO_IO_HANDLE_NONE = 0,
+    AUDIO_MODULE_HANDLE_NONE = 0,
+    AUDIO_PORT_HANDLE_NONE = 0,
+    AUDIO_PATCH_HANDLE_NONE = 0,
+};
+
+/**
+ * Commonly used structure for passing unique identifieds (UUID).
+ * For the definition of UUID, refer to ITU-T X.667 spec.
+ */
+struct Uuid {
+    uint32_t timeLow;
+    uint16_t timeMid;
+    uint16_t versionAndTimeHigh;
+    uint16_t variantAndClockSeqHigh;
+    uint8_t[6] node;
+};
+
+
+/*
+ *
+ *  Audio streams
+ *
+ */
+
+/**
+ * Audio stream type describing the intended use case of a stream.
+ */
+@export(name="audio_stream_type_t", value_prefix="AUDIO_STREAM_")
+enum AudioStreamType : int32_t {
+    // These values must kept in sync with
+    //  frameworks/base/media/java/android/media/AudioSystem.java
+    DEFAULT          = -1,
+    MIN              = 0,
+    VOICE_CALL       = 0,
+    SYSTEM           = 1,
+    RING             = 2,
+    MUSIC            = 3,
+    ALARM            = 4,
+    NOTIFICATION     = 5,
+    BLUETOOTH_SCO    = 6,
+    ENFORCED_AUDIBLE = 7,  // Sounds that cannot be muted by user and must be
+                           // routed to speaker
+    DTMF             = 8,
+    TTS              = 9,  // Transmitted Through Speaker.  Plays over speaker
+                           // only, silent on other devices
+    ACCESSIBILITY    = 10, // For accessibility talk back prompts
+};
+
+@export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
+enum AudioSource : int32_t {
+    // These values must kept in sync with
+    //  frameworks/base/media/java/android/media/MediaRecorder.java,
+    //  frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
+    //  system/media/audio_effects/include/audio_effects/audio_effects_conf.h
+    DEFAULT             = 0,
+    MIC                 = 1,
+    VOICE_UPLINK        = 2,
+    VOICE_DOWNLINK      = 3,
+    VOICE_CALL          = 4,
+    CAMCORDER           = 5,
+    VOICE_RECOGNITION   = 6,
+    VOICE_COMMUNICATION = 7,
+    /**
+     * Source for the mix to be presented remotely. An example of remote
+     * presentation is Wifi Display where a dongle attached to a TV can be used
+     * to play the mix captured by this audio source.
+     */
+    REMOTE_SUBMIX       = 8,
+    /**
+     * Source for unprocessed sound. Usage examples include level measurement
+     * and raw signal analysis.
+     */
+    UNPROCESSED         = 9,
+    /**
+     * Source for capturing audio meant to be processed in real time and played back for live
+     * performance (e.g karaoke). The capture path will minimize latency and coupling with
+     * playback path.
+     */
+    VOICE_PERFORMANCE    = 10,
+    /**
+     * Source for an echo canceller to capture the reference signal to be cancelled.
+     * The echo reference signal will be captured as close as possible to the DAC in order
+     * to include all post processing applied to the playback path.
+     */
+    ECHO_REFERENCE      = 1997,
+    FM_TUNER            = 1998,
+    HOTWORD             = 1999,
+};
+
+typedef int32_t AudioSession;
+/**
+ * Special audio session values.
+ */
+@export(name="audio_session_t", value_prefix="AUDIO_SESSION_")
+enum AudioSessionConsts : int32_t {
+    /**
+     * Session for effects attached to a particular output stream
+     * (value must be less than 0)
+     */
+    OUTPUT_STAGE = -1,
+    /**
+     * Session for effects applied to output mix. These effects can
+     * be moved by audio policy manager to another output stream
+     * (value must be 0)
+     */
+    OUTPUT_MIX = 0,
+    /**
+     * Application does not specify an explicit session ID to be used, and
+     * requests a new session ID to be allocated. Corresponds to
+     * AudioManager.AUDIO_SESSION_ID_GENERATE and
+     * AudioSystem.AUDIO_SESSION_ALLOCATE.
+     */
+    ALLOCATE = 0,
+    /**
+     * For use with AudioRecord::start(), this indicates no trigger session.
+     * It is also used with output tracks and patch tracks, which never have a
+     * session.
+     */
+    NONE = 0
+};
+
+/**
+ * Audio format  is a 32-bit word that consists of:
+ *   main format field (upper 8 bits)
+ *   sub format field (lower 24 bits).
+ *
+ * The main format indicates the main codec type. The sub format field indicates
+ * options and parameters for each format. The sub format is mainly used for
+ * record to indicate for instance the requested bitrate or profile.  It can
+ * also be used for certain formats to give informations not present in the
+ * encoded audio stream (e.g. octet alignement for AMR).
+ */
+@export(name="audio_format_t", value_prefix="AUDIO_FORMAT_")
+enum AudioFormat : uint32_t {
+    INVALID             = 0xFFFFFFFFUL,
+    DEFAULT             = 0,
+    PCM                 = 0x00000000UL,
+    MP3                 = 0x01000000UL,
+    AMR_NB              = 0x02000000UL,
+    AMR_WB              = 0x03000000UL,
+    AAC                 = 0x04000000UL,
+    /** Deprecated, Use AAC_HE_V1 */
+    HE_AAC_V1           = 0x05000000UL,
+    /** Deprecated, Use AAC_HE_V2 */
+    HE_AAC_V2           = 0x06000000UL,
+    VORBIS              = 0x07000000UL,
+    OPUS                = 0x08000000UL,
+    AC3                 = 0x09000000UL,
+    E_AC3               = 0x0A000000UL,
+    DTS                 = 0x0B000000UL,
+    DTS_HD              = 0x0C000000UL,
+    /** IEC61937 is encoded audio wrapped in 16-bit PCM. */
+    IEC61937            = 0x0D000000UL,
+    DOLBY_TRUEHD        = 0x0E000000UL,
+    EVRC                = 0x10000000UL,
+    EVRCB               = 0x11000000UL,
+    EVRCWB              = 0x12000000UL,
+    EVRCNW              = 0x13000000UL,
+    AAC_ADIF            = 0x14000000UL,
+    WMA                 = 0x15000000UL,
+    WMA_PRO             = 0x16000000UL,
+    AMR_WB_PLUS         = 0x17000000UL,
+    MP2                 = 0x18000000UL,
+    QCELP               = 0x19000000UL,
+    DSD                 = 0x1A000000UL,
+    FLAC                = 0x1B000000UL,
+    ALAC                = 0x1C000000UL,
+    APE                 = 0x1D000000UL,
+    AAC_ADTS            = 0x1E000000UL,
+    SBC                 = 0x1F000000UL,
+    APTX                = 0x20000000UL,
+    APTX_HD             = 0x21000000UL,
+    AC4                 = 0x22000000UL,
+    LDAC                = 0x23000000UL,
+    /** Dolby Metadata-enhanced Audio Transmission */
+    MAT                 = 0x24000000UL,
+    AAC_LATM            = 0x25000000UL,
+    CELT                = 0x26000000UL,
+    APTX_ADAPTIVE       = 0x27000000UL,
+    LHDC                = 0x28000000UL,
+    LHDC_LL             = 0x29000000UL,
+    APTX_TWSP           = 0x2A000000UL,
+
+    /** Deprecated */
+    MAIN_MASK           = 0xFF000000UL,
+    SUB_MASK            = 0x00FFFFFFUL,
+
+    /* Subformats */
+    PCM_SUB_16_BIT        = 0x1, // PCM signed 16 bits
+    PCM_SUB_8_BIT         = 0x2, // PCM unsigned 8 bits
+    PCM_SUB_32_BIT        = 0x3, // PCM signed .31 fixed point
+    PCM_SUB_8_24_BIT      = 0x4, // PCM signed 8.23 fixed point
+    PCM_SUB_FLOAT         = 0x5, // PCM single-precision float pt
+    PCM_SUB_24_BIT_PACKED = 0x6, // PCM signed .23 fix pt (3 bytes)
+
+    MP3_SUB_NONE          = 0x0,
+
+    AMR_SUB_NONE          = 0x0,
+
+    AAC_SUB_MAIN          = 0x1,
+    AAC_SUB_LC            = 0x2,
+    AAC_SUB_SSR           = 0x4,
+    AAC_SUB_LTP           = 0x8,
+    AAC_SUB_HE_V1         = 0x10,
+    AAC_SUB_SCALABLE      = 0x20,
+    AAC_SUB_ERLC          = 0x40,
+    AAC_SUB_LD            = 0x80,
+    AAC_SUB_HE_V2         = 0x100,
+    AAC_SUB_ELD           = 0x200,
+    AAC_SUB_XHE           = 0x300,
+
+    VORBIS_SUB_NONE       = 0x0,
+
+    E_AC3_SUB_JOC         = 0x1,
+
+    MAT_SUB_1_0           = 0x1,
+    MAT_SUB_2_0           = 0x2,
+    MAT_SUB_2_1           = 0x3,
+
+    /* Aliases */
+    /** note != AudioFormat.ENCODING_PCM_16BIT */
+    PCM_16_BIT          = (PCM | PCM_SUB_16_BIT),
+    /** note != AudioFormat.ENCODING_PCM_8BIT */
+    PCM_8_BIT           = (PCM | PCM_SUB_8_BIT),
+    PCM_32_BIT          = (PCM | PCM_SUB_32_BIT),
+    PCM_8_24_BIT        = (PCM | PCM_SUB_8_24_BIT),
+    PCM_FLOAT           = (PCM | PCM_SUB_FLOAT),
+    PCM_24_BIT_PACKED   = (PCM | PCM_SUB_24_BIT_PACKED),
+    AAC_MAIN            = (AAC | AAC_SUB_MAIN),
+    AAC_LC              = (AAC | AAC_SUB_LC),
+    AAC_SSR             = (AAC | AAC_SUB_SSR),
+    AAC_LTP             = (AAC | AAC_SUB_LTP),
+    AAC_HE_V1           = (AAC | AAC_SUB_HE_V1),
+    AAC_SCALABLE        = (AAC | AAC_SUB_SCALABLE),
+    AAC_ERLC            = (AAC | AAC_SUB_ERLC),
+    AAC_LD              = (AAC | AAC_SUB_LD),
+    AAC_HE_V2           = (AAC | AAC_SUB_HE_V2),
+    AAC_ELD             = (AAC | AAC_SUB_ELD),
+    AAC_XHE             = (AAC | AAC_SUB_XHE),
+    AAC_ADTS_MAIN       = (AAC_ADTS | AAC_SUB_MAIN),
+    AAC_ADTS_LC         = (AAC_ADTS | AAC_SUB_LC),
+    AAC_ADTS_SSR        = (AAC_ADTS | AAC_SUB_SSR),
+    AAC_ADTS_LTP        = (AAC_ADTS | AAC_SUB_LTP),
+    AAC_ADTS_HE_V1      = (AAC_ADTS | AAC_SUB_HE_V1),
+    AAC_ADTS_SCALABLE   = (AAC_ADTS | AAC_SUB_SCALABLE),
+    AAC_ADTS_ERLC       = (AAC_ADTS | AAC_SUB_ERLC),
+    AAC_ADTS_LD         = (AAC_ADTS | AAC_SUB_LD),
+    AAC_ADTS_HE_V2      = (AAC_ADTS | AAC_SUB_HE_V2),
+    AAC_ADTS_ELD        = (AAC_ADTS | AAC_SUB_ELD),
+    AAC_ADTS_XHE        = (AAC_ADTS | AAC_SUB_XHE),
+    E_AC3_JOC           = (E_AC3 | E_AC3_SUB_JOC),
+    MAT_1_0             = (MAT | MAT_SUB_1_0),
+    MAT_2_0             = (MAT | MAT_SUB_2_0),
+    MAT_2_1             = (MAT | MAT_SUB_2_1),
+    AAC_LATM_LC         = (AAC_LATM | AAC_SUB_LC),
+    AAC_LATM_HE_V1      = (AAC_LATM | AAC_SUB_HE_V1),
+    AAC_LATM_HE_V2      = (AAC_LATM | AAC_SUB_HE_V2),
+};
+
+/**
+ * Usage of these values highlights places in the code that use 2- or 8- channel
+ * assumptions.
+ */
+@export(name="")
+enum FixedChannelCount : int32_t {
+    FCC_2 = 2, // This is typically due to legacy implementation of stereo I/O
+    FCC_8 = 8  // This is typically due to audio mixer and resampler limitations
+};
+
+/**
+ * A channel mask per se only defines the presence or absence of a channel, not
+ * the order.
+ *
+ * The channel order convention is that channels are interleaved in order from
+ * least significant channel mask bit to most significant channel mask bit,
+ * with unused bits skipped. For example for stereo, LEFT would be first,
+ * followed by RIGHT.
+ * Any exceptions to this convention are noted at the appropriate API.
+ *
+ * AudioChannelMask is an opaque type and its internal layout should not be
+ * assumed as it may change in the future.  Instead, always use functions
+ * to examine it.
+ *
+ * These are the current representations:
+ *
+ *   REPRESENTATION_POSITION
+ *     is a channel mask representation for position assignment.  Each low-order
+ *     bit corresponds to the spatial position of a transducer (output), or
+ *     interpretation of channel (input).  The user of a channel mask needs to
+ *     know the context of whether it is for output or input.  The constants
+ *     OUT_* or IN_* apply to the bits portion.  It is not permitted for no bits
+ *     to be set.
+ *
+ *   REPRESENTATION_INDEX
+ *     is a channel mask representation for index assignment.  Each low-order
+ *     bit corresponds to a selected channel.  There is no platform
+ *     interpretation of the various bits.  There is no concept of output or
+ *     input.  It is not permitted for no bits to be set.
+ *
+ * All other representations are reserved for future use.
+ *
+ * Warning: current representation distinguishes between input and output, but
+ * this will not the be case in future revisions of the platform. Wherever there
+ * is an ambiguity between input and output that is currently resolved by
+ * checking the channel mask, the implementer should look for ways to fix it
+ * with additional information outside of the mask.
+ */
+@export(name="", value_prefix="AUDIO_CHANNEL_")
+enum AudioChannelMask : uint32_t {
+    /** must be 0 for compatibility */
+    REPRESENTATION_POSITION = 0,
+    /** 1 is reserved for future use */
+    REPRESENTATION_INDEX    = 2,
+    /* 3 is reserved for future use */
+
+    /** These can be a complete value of AudioChannelMask */
+    NONE                      = 0x0,
+    INVALID                   = 0xC0000000,
+
+   /*
+    * These can be the bits portion of an AudioChannelMask
+    * with representation REPRESENTATION_POSITION.
+    */
+
+    /** output channels */
+    OUT_FRONT_LEFT            = 0x1,
+    OUT_FRONT_RIGHT           = 0x2,
+    OUT_FRONT_CENTER          = 0x4,
+    OUT_LOW_FREQUENCY         = 0x8,
+    OUT_BACK_LEFT             = 0x10,
+    OUT_BACK_RIGHT            = 0x20,
+    OUT_FRONT_LEFT_OF_CENTER  = 0x40,
+    OUT_FRONT_RIGHT_OF_CENTER = 0x80,
+    OUT_BACK_CENTER           = 0x100,
+    OUT_SIDE_LEFT             = 0x200,
+    OUT_SIDE_RIGHT            = 0x400,
+    OUT_TOP_CENTER            = 0x800,
+    OUT_TOP_FRONT_LEFT        = 0x1000,
+    OUT_TOP_FRONT_CENTER      = 0x2000,
+    OUT_TOP_FRONT_RIGHT       = 0x4000,
+    OUT_TOP_BACK_LEFT         = 0x8000,
+    OUT_TOP_BACK_CENTER       = 0x10000,
+    OUT_TOP_BACK_RIGHT        = 0x20000,
+    OUT_TOP_SIDE_LEFT         = 0x40000,
+    OUT_TOP_SIDE_RIGHT        = 0x80000,
+
+    /**
+     * Haptic channel characteristics are specific to a device and
+     * only used to play device specific resources (eg: ringtones).
+     * The HAL can freely map A and B to haptic controllers, the
+     * framework shall not interpret those values and forward them
+     * from the device audio assets.
+     */
+    OUT_HAPTIC_A              = 0x20000000,
+    OUT_HAPTIC_B              = 0x10000000,
+
+    OUT_MONO     = OUT_FRONT_LEFT,
+    OUT_STEREO   = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
+    OUT_2POINT1  = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
+    OUT_2POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+                         OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+                         OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT |
+                         OUT_LOW_FREQUENCY),
+    OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER |
+                         OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER |
+                        OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT |
+                        OUT_LOW_FREQUENCY),
+    OUT_QUAD     = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT),
+    OUT_QUAD_BACK = OUT_QUAD,
+    /** like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
+    OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_BACK_CENTER),
+    OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER),
+    OUT_5POINT1   = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT),
+    OUT_5POINT1_BACK = OUT_5POINT1,
+    /** like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
+    OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_5POINT1POINT2  = (OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_5POINT1POINT4  = (OUT_5POINT1 |
+            OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT |
+            OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
+    OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT |
+            OUT_BACK_CENTER),
+    /** matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND */
+    OUT_7POINT1  = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT |
+            OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_7POINT1POINT2  = (OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_7POINT1POINT4  = (OUT_7POINT1 |
+            OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT |
+            OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
+    OUT_MONO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_HAPTIC_A),
+    OUT_STEREO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A),
+    OUT_HAPTIC_AB = (OUT_HAPTIC_A | OUT_HAPTIC_B),
+    OUT_MONO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_HAPTIC_A | OUT_HAPTIC_B),
+    OUT_STEREO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_HAPTIC_A | OUT_HAPTIC_B),
+    // Note that the 2.0 OUT_ALL* have been moved to helper functions
+
+    /* These are bits only, not complete values */
+
+    /** input channels */
+    IN_LEFT            = 0x4,
+    IN_RIGHT           = 0x8,
+    IN_FRONT           = 0x10,
+    IN_BACK            = 0x20,
+    IN_LEFT_PROCESSED  = 0x40,
+    IN_RIGHT_PROCESSED = 0x80,
+    IN_FRONT_PROCESSED = 0x100,
+    IN_BACK_PROCESSED  = 0x200,
+    IN_PRESSURE        = 0x400,
+    IN_X_AXIS          = 0x800,
+    IN_Y_AXIS          = 0x1000,
+    IN_Z_AXIS          = 0x2000,
+    IN_BACK_LEFT       = 0x10000,
+    IN_BACK_RIGHT      = 0x20000,
+    IN_CENTER          = 0x40000,
+    IN_LOW_FREQUENCY   = 0x100000,
+    IN_TOP_LEFT        = 0x200000,
+    IN_TOP_RIGHT       = 0x400000,
+
+    IN_VOICE_UPLINK    = 0x4000,
+    IN_VOICE_DNLINK    = 0x8000,
+
+    IN_MONO   = IN_FRONT,
+    IN_STEREO = (IN_LEFT | IN_RIGHT),
+    IN_FRONT_BACK = (IN_FRONT | IN_BACK),
+    IN_6 = (IN_LEFT | IN_RIGHT |
+            IN_FRONT | IN_BACK |
+            IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED),
+    IN_2POINT0POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT),
+    IN_2POINT1POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT |
+            IN_LOW_FREQUENCY),
+    IN_3POINT0POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT),
+    IN_3POINT1POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT |
+            IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY),
+    IN_5POINT1 = (IN_LEFT | IN_CENTER | IN_RIGHT |
+                  IN_BACK_LEFT | IN_BACK_RIGHT | IN_LOW_FREQUENCY),
+    IN_VOICE_UPLINK_MONO = (IN_VOICE_UPLINK | IN_MONO),
+    IN_VOICE_DNLINK_MONO = (IN_VOICE_DNLINK | IN_MONO),
+    IN_VOICE_CALL_MONO   = (IN_VOICE_UPLINK_MONO |
+            IN_VOICE_DNLINK_MONO),
+    // Note that the 2.0 IN_ALL* have been moved to helper functions
+
+    COUNT_MAX    = 30,
+    INDEX_HDR    = REPRESENTATION_INDEX << COUNT_MAX,
+    INDEX_MASK_1 = INDEX_HDR | ((1 << 1) - 1),
+    INDEX_MASK_2 = INDEX_HDR | ((1 << 2) - 1),
+    INDEX_MASK_3 = INDEX_HDR | ((1 << 3) - 1),
+    INDEX_MASK_4 = INDEX_HDR | ((1 << 4) - 1),
+    INDEX_MASK_5 = INDEX_HDR | ((1 << 5) - 1),
+    INDEX_MASK_6 = INDEX_HDR | ((1 << 6) - 1),
+    INDEX_MASK_7 = INDEX_HDR | ((1 << 7) - 1),
+    INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1),
+    INDEX_MASK_9 = INDEX_HDR | ((1 << 9) - 1),
+    INDEX_MASK_10 = INDEX_HDR | ((1 << 10) - 1),
+    INDEX_MASK_11 = INDEX_HDR | ((1 << 11) - 1),
+    INDEX_MASK_12 = INDEX_HDR | ((1 << 12) - 1),
+    INDEX_MASK_13 = INDEX_HDR | ((1 << 13) - 1),
+    INDEX_MASK_14 = INDEX_HDR | ((1 << 14) - 1),
+    INDEX_MASK_15 = INDEX_HDR | ((1 << 15) - 1),
+    INDEX_MASK_16 = INDEX_HDR | ((1 << 16) - 1),
+    INDEX_MASK_17 = INDEX_HDR | ((1 << 17) - 1),
+    INDEX_MASK_18 = INDEX_HDR | ((1 << 18) - 1),
+    INDEX_MASK_19 = INDEX_HDR | ((1 << 19) - 1),
+    INDEX_MASK_20 = INDEX_HDR | ((1 << 20) - 1),
+    INDEX_MASK_21 = INDEX_HDR | ((1 << 21) - 1),
+    INDEX_MASK_22 = INDEX_HDR | ((1 << 22) - 1),
+    INDEX_MASK_23 = INDEX_HDR | ((1 << 23) - 1),
+    INDEX_MASK_24 = INDEX_HDR | ((1 << 24) - 1),
+};
+
+/**
+ * Major modes for a mobile device. The current mode setting affects audio
+ * routing.
+ */
+@export(name="audio_mode_t", value_prefix="AUDIO_MODE_")
+enum AudioMode : int32_t {
+    NORMAL           = 0,
+    RINGTONE         = 1,
+    /** Calls handled by the telephony stack (Eg: PSTN). */
+    IN_CALL          = 2,
+    /** Calls handled by apps (Eg: Hangout). */
+    IN_COMMUNICATION = 3,
+};
+
+@export(name="", value_prefix="AUDIO_DEVICE_")
+enum AudioDevice : uint32_t {
+    NONE                          = 0x0,
+    /** reserved bits */
+    BIT_IN                        = 0x80000000,
+    BIT_DEFAULT                   = 0x40000000,
+    /** output devices */
+    OUT_EARPIECE                  = 0x1,
+    OUT_SPEAKER                   = 0x2,
+    OUT_WIRED_HEADSET             = 0x4,
+    OUT_WIRED_HEADPHONE           = 0x8,
+    OUT_BLUETOOTH_SCO             = 0x10,
+    OUT_BLUETOOTH_SCO_HEADSET     = 0x20,
+    OUT_BLUETOOTH_SCO_CARKIT      = 0x40,
+    OUT_BLUETOOTH_A2DP            = 0x80,
+    OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+    OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200,
+    OUT_AUX_DIGITAL               = 0x400,
+    OUT_HDMI                      = OUT_AUX_DIGITAL,
+    /** uses an analog connection (multiplexed over the USB pins for instance) */
+    OUT_ANLG_DOCK_HEADSET         = 0x800,
+    OUT_DGTL_DOCK_HEADSET         = 0x1000,
+    /** USB accessory mode: Android device is USB device and dock is USB host */
+    OUT_USB_ACCESSORY             = 0x2000,
+    /** USB host mode: Android device is USB host and dock is USB device */
+    OUT_USB_DEVICE                = 0x4000,
+    OUT_REMOTE_SUBMIX             = 0x8000,
+    /** Telephony voice TX path */
+    OUT_TELEPHONY_TX              = 0x10000,
+    /** Analog jack with line impedance detected */
+    OUT_LINE                      = 0x20000,
+    /** HDMI Audio Return Channel */
+    OUT_HDMI_ARC                  = 0x40000,
+    /** S/PDIF out */
+    OUT_SPDIF                     = 0x80000,
+    /** FM transmitter out */
+    OUT_FM                        = 0x100000,
+    /** Line out for av devices */
+    OUT_AUX_LINE                  = 0x200000,
+    /** limited-output speaker device for acoustic safety */
+    OUT_SPEAKER_SAFE              = 0x400000,
+    OUT_IP                        = 0x800000,
+    /** audio bus implemented by the audio system (e.g an MOST stereo channel) */
+    OUT_BUS                       = 0x1000000,
+    OUT_PROXY                     = 0x2000000,
+    OUT_USB_HEADSET               = 0x4000000,
+    OUT_HEARING_AID               = 0x8000000,
+    OUT_ECHO_CANCELLER            = 0x10000000,
+    OUT_DEFAULT                   = BIT_DEFAULT,
+    // Note that the 2.0 OUT_ALL* have been moved to helper functions
+
+    /** input devices */
+    IN_COMMUNICATION         = BIT_IN | 0x1,
+    IN_AMBIENT               = BIT_IN | 0x2,
+    IN_BUILTIN_MIC           = BIT_IN | 0x4,
+    IN_BLUETOOTH_SCO_HEADSET = BIT_IN | 0x8,
+    IN_WIRED_HEADSET         = BIT_IN | 0x10,
+    IN_AUX_DIGITAL           = BIT_IN | 0x20,
+    IN_HDMI                  = IN_AUX_DIGITAL,
+    /** Telephony voice RX path */
+    IN_VOICE_CALL            = BIT_IN | 0x40,
+    IN_TELEPHONY_RX          = IN_VOICE_CALL,
+    IN_BACK_MIC              = BIT_IN | 0x80,
+    IN_REMOTE_SUBMIX         = BIT_IN | 0x100,
+    IN_ANLG_DOCK_HEADSET     = BIT_IN | 0x200,
+    IN_DGTL_DOCK_HEADSET     = BIT_IN | 0x400,
+    IN_USB_ACCESSORY         = BIT_IN | 0x800,
+    IN_USB_DEVICE            = BIT_IN | 0x1000,
+    /** FM tuner input */
+    IN_FM_TUNER              = BIT_IN | 0x2000,
+    /** TV tuner input */
+    IN_TV_TUNER              = BIT_IN | 0x4000,
+    /** Analog jack with line impedance detected */
+    IN_LINE                  = BIT_IN | 0x8000,
+    /** S/PDIF in */
+    IN_SPDIF                 = BIT_IN | 0x10000,
+    IN_BLUETOOTH_A2DP        = BIT_IN | 0x20000,
+    IN_LOOPBACK              = BIT_IN | 0x40000,
+    IN_IP                    = BIT_IN | 0x80000,
+    /** audio bus implemented by the audio system (e.g an MOST stereo channel) */
+    IN_BUS                   = BIT_IN | 0x100000,
+    IN_PROXY                 = BIT_IN | 0x1000000,
+    IN_USB_HEADSET           = BIT_IN | 0x2000000,
+    IN_BLUETOOTH_BLE         = BIT_IN | 0x4000000,
+    IN_ECHO_REFERENCE        = BIT_IN | 0x10000000,
+    IN_DEFAULT               = BIT_IN | BIT_DEFAULT,
+
+    // Note that the 2.0 IN_ALL* have been moved to helper functions
+};
+
+/**
+ * IEEE 802 MAC address.
+ */
+typedef uint8_t[6] MacAddress;
+
+/**
+ * Specifies a device address in case when several devices of the same type
+ * can be connected (e.g. BT A2DP, USB).
+ */
+struct DeviceAddress {
+    AudioDevice device;  // discriminator
+    union Address {
+        MacAddress mac;     // used for BLUETOOTH_A2DP_*
+        uint8_t[4] ipv4;    // used for IP
+        struct Alsa {
+            int32_t card;
+            int32_t device;
+        } alsa;             // used for USB_*
+    } address;
+    /** Arbitrary BUS device unique address. Should not be interpreted by the framework. */
+    string busAddress;
+    /** Arbitrary REMOTE_SUBMIX device unique address. Should not be interpreted by the HAL. */
+    string rSubmixAddress;
+};
+
+/**
+ * The audio output flags serve two purposes:
+ *
+ *  - when an AudioTrack is created they indicate a "wish" to be connected to an
+ *    output stream with attributes corresponding to the specified flags;
+ *
+ *  - when present in an output profile descriptor listed for a particular audio
+ *    hardware module, they indicate that an output stream can be opened that
+ *    supports the attributes indicated by the flags.
+ *
+ * The audio policy manager will try to match the flags in the request
+ * (when getOuput() is called) to an available output stream.
+ */
+@export(name="audio_output_flags_t", value_prefix="AUDIO_OUTPUT_FLAG_")
+enum AudioOutputFlag : int32_t {
+    NONE    = 0x0, // no attributes
+    DIRECT  = 0x1, // this output directly connects a track
+                   // to one output stream: no software mixer
+    PRIMARY = 0x2, // this output is the primary output of the device. It is
+                   // unique and must be present. It is opened by default and
+                   // receives routing, audio mode and volume controls related
+                   // to voice calls.
+    FAST    = 0x4,    // output supports "fast tracks", defined elsewhere
+    DEEP_BUFFER      = 0x8,   // use deep audio buffers
+    COMPRESS_OFFLOAD = 0x10,  // offload playback of compressed streams to
+                              // hardware codec
+    NON_BLOCKING     = 0x20,  // use non-blocking write
+    HW_AV_SYNC = 0x40,   // output uses a hardware A/V sync
+    TTS        = 0x80,   // output for streams transmitted through speaker at a
+                         // sample rate high enough to accommodate lower-range
+                         // ultrasonic p/b
+    RAW        = 0x100,  // minimize signal processing
+    SYNC       = 0x200,  // synchronize I/O streams
+    IEC958_NONAUDIO = 0x400, // Audio stream contains compressed audio in SPDIF
+                             // data bursts, not PCM.
+    DIRECT_PCM = 0x2000,     // Audio stream containing PCM data that needs
+                             // to pass through compress path for DSP post proc.
+    MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode.
+    VOIP_RX = 0x8000,    // preferred output for VoIP calls.
+    /** preferred output for call music */
+    INCALL_MUSIC = 0x10000,
+};
+
+/**
+ * The audio input flags are analogous to audio output flags.
+ * Currently they are used only when an AudioRecord is created,
+ * to indicate a preference to be connected to an input stream with
+ * attributes corresponding to the specified flags.
+ */
+@export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_")
+enum AudioInputFlag : int32_t {
+    NONE         = 0x0,  // no attributes
+    FAST         = 0x1,  // prefer an input that supports "fast tracks"
+    HW_HOTWORD   = 0x2,  // prefer an input that captures from hw hotword source
+    RAW          = 0x4,  // minimize signal processing
+    SYNC         = 0x8,  // synchronize I/O streams
+    MMAP_NOIRQ   = 0x10, // input operates in MMAP no IRQ mode.
+    VOIP_TX      = 0x20, // preferred input for VoIP calls.
+    HW_AV_SYNC   = 0x40, // input connected to an output that uses a hardware A/V sync
+};
+
+@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
+enum AudioUsage : int32_t {
+    // These values must kept in sync with
+    //  frameworks/base/media/java/android/media/AudioAttributes.java
+    // Note that not all framework values are exposed
+    UNKNOWN                            = 0,
+    MEDIA                              = 1,
+    VOICE_COMMUNICATION                = 2,
+    VOICE_COMMUNICATION_SIGNALLING     = 3,
+    ALARM                              = 4,
+    NOTIFICATION                       = 5,
+    NOTIFICATION_TELEPHONY_RINGTONE    = 6,
+    ASSISTANCE_ACCESSIBILITY           = 11,
+    ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
+    ASSISTANCE_SONIFICATION            = 13,
+    GAME                               = 14,
+    VIRTUAL_SOURCE                     = 15,
+    ASSISTANT                          = 16,
+};
+
+/** Type of audio generated by an application. */
+@export(name="audio_content_type_t", value_prefix="AUDIO_CONTENT_TYPE_")
+enum AudioContentType : uint32_t {
+    // Do not change these values without updating their counterparts
+    // in frameworks/base/media/java/android/media/AudioAttributes.java
+    UNKNOWN      = 0,
+    SPEECH       = 1,
+    MUSIC        = 2,
+    MOVIE        = 3,
+    SONIFICATION = 4,
+};
+
+/**
+ * Additional information about the stream passed to hardware decoders.
+ */
+struct AudioOffloadInfo {
+    uint32_t sampleRateHz;
+    bitfield<AudioChannelMask> channelMask;
+    AudioFormat format;
+    AudioStreamType streamType;
+    uint32_t bitRatePerSecond;
+    int64_t durationMicroseconds;  // -1 if unknown
+    bool hasVideo;
+    bool isStreaming;
+    uint32_t bitWidth;
+    uint32_t bufferSize;
+    AudioUsage usage;
+};
+
+/**
+ * Commonly used audio stream configuration parameters.
+ */
+struct AudioConfig {
+    uint32_t sampleRateHz;
+    bitfield<AudioChannelMask> channelMask;
+    AudioFormat format;
+    AudioOffloadInfo offloadInfo;
+    uint64_t frameCount;
+};
+
+/** Metadata of a playback track for a StreamOut. */
+struct PlaybackTrackMetadata {
+    AudioUsage usage;
+    AudioContentType contentType;
+    /**
+     * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+     * 2 means double amplification...
+     * Must not be negative.
+     */
+    float gain;
+};
+
+/** Metadatas of the source of a StreamOut. */
+struct SourceMetadata {
+    vec<PlaybackTrackMetadata> tracks;
+};
+
+/** Metadata of a record track for a StreamIn. */
+struct RecordTrackMetadata {
+    AudioSource source;
+    /**
+     * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+     * 2 means double amplification...
+     * Must not be negative.
+     */
+    float gain;
+    /**
+     * Indicates the destination of an input stream, can be left unspecified.
+     */
+    safe_union Destination {
+        Monostate unspecified;
+        DeviceAddress device;
+    };
+    Destination destination;
+};
+
+/** Metadatas of the sink of a StreamIn. */
+struct SinkMetadata {
+    vec<RecordTrackMetadata> tracks;
+};
+
+
+/*
+ *
+ *  Volume control
+ *
+ */
+
+/**
+ * Type of gain control exposed by an audio port.
+ */
+@export(name="", value_prefix="AUDIO_GAIN_MODE_")
+enum AudioGainMode : uint32_t {
+    JOINT = 0x1,    // supports joint channel gain control
+    CHANNELS = 0x2, // supports separate channel gain control
+    RAMP = 0x4      // supports gain ramps
+};
+
+/**
+ * An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port.
+ */
+struct AudioGain {
+    bitfield<AudioGainMode> mode;
+    bitfield<AudioChannelMask> channelMask; // channels which gain an be controlled
+    int32_t minValue;     // minimum gain value in millibels
+    int32_t maxValue;     // maximum gain value in millibels
+    int32_t defaultValue; // default gain value in millibels
+    uint32_t stepValue;   // gain step in millibels
+    uint32_t minRampMs;   // minimum ramp duration in ms
+    uint32_t maxRampMs;   // maximum ramp duration in ms
+};
+
+/**
+ * The gain configuration structure is used to get or set the gain values of a
+ * given port.
+ */
+struct AudioGainConfig {
+    int32_t index;  // index of the corresponding AudioGain in AudioPort.gains
+    AudioGainMode mode;
+    AudioChannelMask channelMask;  // channels which gain value follows
+    /**
+     * 4 = sizeof(AudioChannelMask),
+     * 8 is not "FCC_8", so it won't need to be changed for > 8 channels.
+     * Gain values in millibels for each channel ordered from LSb to MSb in
+     * channel mask. The number of values is 1 in joint mode or
+     * popcount(channel_mask).
+     */
+    int32_t[4 * 8] values;
+    uint32_t rampDurationMs;  // ramp duration in ms
+};
+
+
+/*
+ *
+ *  Routing control
+ *
+ */
+
+/*
+ * Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * the interface.
+ */
+
+/** Audio port role: either source or sink */
+@export(name="audio_port_role_t", value_prefix="AUDIO_PORT_ROLE_")
+enum AudioPortRole : int32_t {
+    NONE,
+    SOURCE,
+    SINK,
+};
+
+/**
+ * Audio port type indicates if it is a session (e.g AudioTrack), a mix (e.g
+ * PlaybackThread output) or a physical device (e.g OUT_SPEAKER)
+ */
+@export(name="audio_port_type_t", value_prefix="AUDIO_PORT_TYPE_")
+enum AudioPortType : int32_t {
+    NONE,
+    DEVICE,
+    MIX,
+    SESSION,
+};
+
+/**
+ * Extension for audio port configuration structure when the audio port is a
+ * hardware device.
+ */
+struct AudioPortConfigDeviceExt {
+    AudioModuleHandle hwModule;  // module the device is attached to
+    AudioDevice type;            // device type (e.g OUT_SPEAKER)
+    uint8_t[32] address;         // device address. "" if N/A
+};
+
+/**
+ * Extension for audio port configuration structure when the audio port is an
+ * audio session.
+ */
+struct AudioPortConfigSessionExt {
+    AudioSession session;
+};
+
+/**
+ * Flags indicating which fields are to be considered in AudioPortConfig.
+ */
+@export(name="", value_prefix="AUDIO_PORT_CONFIG_")
+enum AudioPortConfigMask : uint32_t {
+    SAMPLE_RATE = 0x1,
+    CHANNEL_MASK =  0x2,
+    FORMAT = 0x4,
+    GAIN = 0x8,
+};
+
+/**
+ * Audio port configuration structure used to specify a particular configuration
+ * of an audio port.
+ */
+struct AudioPortConfig {
+    AudioPortHandle id;
+    bitfield<AudioPortConfigMask> configMask;
+    uint32_t sampleRateHz;
+    bitfield<AudioChannelMask> channelMask;
+    AudioFormat format;
+    AudioGainConfig gain;
+    AudioPortType type;  // type is used as a discriminator for Ext union
+    AudioPortRole role;  // role is used as a discriminator for UseCase union
+    union Ext {
+        AudioPortConfigDeviceExt device;
+        struct AudioPortConfigMixExt {
+            AudioModuleHandle hwModule; // module the stream is attached to
+            AudioIoHandle ioHandle;     // I/O handle of the input/output stream
+            union UseCase {
+                AudioStreamType stream;
+                AudioSource source;
+            } useCase;
+        } mix;
+        AudioPortConfigSessionExt session;
+    } ext;
+};
+
+/**
+ * Extension for audio port structure when the audio port is a hardware device.
+ */
+struct AudioPortDeviceExt {
+    AudioModuleHandle hwModule;    // module the device is attached to
+    AudioDevice type;
+    /** 32 byte string identifying the port. */
+    uint8_t[32] address;
+};
+
+/**
+ * Latency class of the audio mix.
+ */
+@export(name="audio_mix_latency_class_t", value_prefix="AUDIO_LATENCY_")
+enum AudioMixLatencyClass : int32_t {
+    LOW,
+    NORMAL
+};
+
+struct AudioPortMixExt {
+    AudioModuleHandle hwModule;     // module the stream is attached to
+    AudioIoHandle ioHandle;         // I/O handle of the stream
+    AudioMixLatencyClass latencyClass;
+};
+
+/**
+ * Extension for audio port structure when the audio port is an audio session.
+ */
+struct AudioPortSessionExt {
+    AudioSession session;
+};
+
+struct AudioPort {
+    AudioPortHandle id;
+    AudioPortRole role;
+    string name;
+    vec<uint32_t> sampleRates;
+    vec<bitfield<AudioChannelMask>> channelMasks;
+    vec<AudioFormat> formats;
+    vec<AudioGain> gains;
+    AudioPortConfig activeConfig; // current audio port configuration
+    AudioPortType type;  // type is used as a discriminator
+    union Ext {
+        AudioPortDeviceExt device;
+        AudioPortMixExt mix;
+        AudioPortSessionExt session;
+    } ext;
+};
+
+struct ThreadInfo {
+    int64_t pid;
+    int64_t tid;
+};
diff --git a/audio/common/all-versions/copyHAL.sh b/audio/common/all-versions/copyHAL.sh
new file mode 100755
index 0000000..d07012f
--- /dev/null
+++ b/audio/common/all-versions/copyHAL.sh
@@ -0,0 +1,204 @@
+#/usr/bin/env bash
+
+set -euo pipefail
+
+if (echo "$@" |grep -qe -h); then
+    echo "This script will generate a new HAL version identical to an other one."
+    echo "This helps creating the boilerplate for a new version."
+    echo
+    echo "USAGE: $0 [BASE_VERSION] [NEW_VERSION]"
+    echo "       BASE_VERSION default value is the highest version currently existing"
+    echo "       NEW_VERSION default value is BASE_VERSION + 1"
+    echo
+    echo "Example: to generate a V6.0 by copying V5, do: $0 5.0 6.0"
+    exit
+fi
+readonly HAL_DIRECTORY=hardware/interfaces/audio
+readonly HAL_VTS_DIRECTORY=core/all-versions/vts/functional
+readonly HAL_VTS_FILE=AudioPrimaryHidlHalTest.cpp
+readonly HAL_SERVICE_DIRECTORY=common/all-versions/default/service/
+readonly HAL_SERVICE_CPP=service.cpp
+
+readonly FWK_DIRECTORY=frameworks/av/media/libaudiohal
+readonly IMPL_DIRECTORY=impl
+readonly IMPL_FACTORYHAL=$IMPL_DIRECTORY/include/libaudiohal/FactoryHalHidl.h
+
+readonly VTS_DIRECTORY=test/vts-testcase/hal/audio
+readonly VTS_LIST=test/vts/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk
+readonly WATCHDOG=frameworks/base/services/core/java/com/android/server/Watchdog.cpp
+readonly GSI_CURRENT=build/make/target/product/gsi/current.txt
+
+readonly BASE_VERSION=${1:-$(ls $ANDROID_BUILD_TOP/$HAL_DIRECTORY | grep -E '[0-9]+\.[0-9]+' |
+                                  sort -n |tail -n1)}
+readonly BASE_MAJOR_VERSION=${BASE_VERSION%.*}
+readonly BASE_MINOR_VERSION=${BASE_VERSION##*.}
+
+readonly NEW_VERSION="${2:-$((${BASE_MAJOR_VERSION} + 1)).0}"
+readonly NEW_MAJOR_VERSION=${NEW_VERSION%.*}
+readonly NEW_MINOR_VERSION=${NEW_VERSION##*.}
+
+
+readonly BASE_VERSION_REGEX="${BASE_MAJOR_VERSION}[._]${BASE_MINOR_VERSION}"
+readonly NEW_VERSION_REGEX="${NEW_MAJOR_VERSION}[._]${NEW_MINOR_VERSION}"
+
+readonly BASE_VERSION_ESCAPE="${BASE_MAJOR_VERSION}\.${BASE_MINOR_VERSION}"
+readonly BASE_VERSION_UNDERSCORE="${BASE_MAJOR_VERSION}_${BASE_MINOR_VERSION}"
+readonly NEW_VERSION_UNDERSCORE="${NEW_MAJOR_VERSION}_${NEW_MINOR_VERSION}"
+updateVersion() {
+    if [ $1 == "-e" ]; then
+        local -r REGEX="$2"; shift 2
+    else
+        local -r REGEX="$BASE_VERSION_REGEX"
+    fi
+    awk -i inplace -e "{if (!/$REGEX/) print; else {
+                            if (original_before) print
+                            if (original_after) original_line=\$0;
+
+                            gsub(/$BASE_VERSION_ESCAPE/,\"$NEW_VERSION\");
+                            gsub(/$BASE_VERSION_UNDERSCORE/,\"$NEW_VERSION_UNDERSCORE\");
+                            gsub(/MAJOR_VERSION=$BASE_MAJOR_VERSION/,
+                                 \"MAJOR_VERSION=$NEW_MAJOR_VERSION\");
+                            gsub(/MINOR_VERSION=$BASE_MINOR_VERSION/,
+                                 \"MINOR_VERSION=$NEW_MINOR_VERSION\");
+
+                            print
+                            if (original_after) print original_line
+                       }}" "$@"
+}
+
+updateAudioVersion() {
+    updateVersion -e "audio.*$BASE_VERSION_REGEX" "$@"
+}
+
+updateLicenceDates() {
+    # Update date on the 2 first lines
+    sed -i "1,2 s/20[0-9][0-9]/$(date +"%Y")/g" "$@"
+}
+
+echo "Creating new audio HAL V$NEW_VERSION based on V$BASE_VERSION"
+echo "Press Ctrl-C to cancel, Enter to continue"
+read
+
+MODIFIED=
+runIfNeeded() {
+    local -r TARGET=$1; shift
+    cd $ANDROID_BUILD_TOP/$TARGET
+    if grep -q -r "audio.*$NEW_VERSION_REGEX"; then
+        echo "  Skipping $TARGET as already up to date"
+    else
+        echo "  Updating $PWD"
+        MODIFIED+=$'\n - '$TARGET
+        "$@"
+    fi
+}
+
+createHALVersion() {
+    local -r DIRS=". common effect"
+    local COPY=
+    echo "Copy $BASE_VERSION to $NEW_VERSION in $DIRS"
+    for DIR in $DIRS; do
+        cp -Tar $DIR/$BASE_VERSION $DIR/$NEW_VERSION
+        COPY+=" $DIR/$NEW_VERSION"
+    done
+
+    echo "Replacing $BASE_VERSION by $NEW_VERSION in the copied files"
+    updateVersion $(find $COPY -type f)
+    updateLicenceDates $(find $COPY -type f)
+
+    echo "Update implementation and VTS generic code"
+    local -r FILES="*/all-versions/default/Android.bp */all-versions/vts/functional/Android.bp"
+    updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $FILES
+    sed -i '${/^$/d}' $FILES # Remove \n at the end of the files
+
+    updateVersion -v original_before=1 $HAL_SERVICE_DIRECTORY/Android.bp
+
+    updateVersion -e "audio::.*$BASE_VERSION_REGEX" -v original_after=1 \
+        $HAL_SERVICE_DIRECTORY/$HAL_SERVICE_CPP
+    updateVersion -e "audio\/.*$BASE_VERSION_REGEX" -v original_before=1 \
+        $HAL_SERVICE_DIRECTORY/$HAL_SERVICE_CPP
+
+    local -r HAL_VTS_PATH=$HAL_VTS_DIRECTORY/$NEW_VERSION/$HAL_VTS_FILE
+    mkdir -p $(dirname $HAL_VTS_PATH)
+    cat > $HAL_VTS_PATH <<EOF
+/*
+ * Copyright (C) $(date +"%Y") 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.
+ */
+
+// pull in all the <= $BASE_VERSION tests
+#include "$BASE_VERSION/$(basename AudioPrimaryHidlHalTest.cpp)"
+EOF
+
+    echo "New HAL version $NEW_VERSION successfully created"
+}
+
+echo "Creating new audio HAL definition, default impl and VTS"
+runIfNeeded $HAL_DIRECTORY createHALVersion
+
+
+createFrameworkAdapter() {
+    updateVersion -v original_before=1 Android.bp
+    updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $IMPL_FACTORYHAL/Android.bp
+    updateVersion -v original_after=1 $IMPL_FACTORYHAL
+}
+echo "Now creating the framework adapter version"
+runIfNeeded $FWK_DIRECTORY createFrameworkAdapter
+
+createVTSXML() {
+    cp -Tar V$BASE_VERSION_UNDERSCORE V$NEW_VERSION_UNDERSCORE
+    cp -Tar effect/{V$BASE_VERSION_UNDERSCORE,V$NEW_VERSION_UNDERSCORE}
+    local -r FILES=$(find {.,effect}/V$NEW_VERSION_UNDERSCORE -type f)
+    updateVersion $FILES
+    updateLicenceDates $FILES
+}
+echo "Now update VTS XML"
+runIfNeeded $VTS_DIRECTORY createVTSXML
+
+echo "Now register new VTS"
+runIfNeeded $(dirname $VTS_LIST) updateAudioVersion -v original_before=1 $(basename $VTS_LIST)
+
+echo "Now update watchdog"
+runIfNeeded $(dirname $WATCHDOG) updateAudioVersion -v original_before=1 $(basename $WATCHDOG)
+
+echo "Now update GSI current.txt"
+runIfNeeded $(dirname $GSI_CURRENT) update-vndk-list.sh
+
+if ! [ "$MODIFIED" ]; then
+    echo
+    echo "$NEW_VERSION already exist, nothing to do"
+    exit
+fi
+
+cat << EOF
+
+All File generated successfully. Please submit a patch in all those directories: $MODIFIED
+
+-----------------------------------------------------------
+WHAT WAS *NOT* DONE, and you need to do now:
+ 1) You need to choose if the new HAL is optional or not for new devices.
+    Either add or replace $BASE_VERSION by $NEW_VERSION in
+    compatibility_matrices/compatibility_matrix.current.xml
+    Do not forget to update both the "audio" and "audio.effects" HAL'
+
+ 2) Then you need to choose a device to update its audio HAL implementation:
+    a) Update the HAL manifest of your device: open your device manifest.xml
+       and replace $BASE_VERSION by $NEW_VERSION for both
+        - android.hardware.audio
+        - android.hardware.audio.effect
+    b) Go to your device device.mk (usually next to the manifest) and replace:
+        - android.hardware.audio@$BASE_VERSION-impl by
+          android.hardware.audio@$NEW_VERSION-impl
+        - android.hardware.audio.effect@$BASE_VERSION-impl by
+          android.hardware.audio.effect@$NEW_VERSION-impl
+EOF
diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp
index c0bd34c..0eb4a71 100644
--- a/audio/common/all-versions/default/Android.bp
+++ b/audio/common/all-versions/default/Android.bp
@@ -69,7 +69,6 @@
 cc_library_shared {
     name: "android.hardware.audio.common@2.0-util",
     defaults: ["android.hardware.audio.common-util_default"],
-
     shared_libs: [
         "android.hardware.audio.common@2.0",
     ],
@@ -83,7 +82,6 @@
 cc_library_shared {
     name: "android.hardware.audio.common@4.0-util",
     defaults: ["android.hardware.audio.common-util_default"],
-
     shared_libs: [
         "android.hardware.audio.common@4.0",
     ],
@@ -97,7 +95,6 @@
 cc_library_shared {
     name: "android.hardware.audio.common@5.0-util",
     defaults: ["android.hardware.audio.common-util_default"],
-
     shared_libs: [
         "android.hardware.audio.common@5.0",
     ],
@@ -107,3 +104,16 @@
         "-include common/all-versions/VersionMacro.h",
     ]
 }
+
+cc_library_shared {
+    name: "android.hardware.audio.common@6.0-util",
+    defaults: ["android.hardware.audio.common-util_default"],
+    shared_libs: [
+        "android.hardware.audio.common@6.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
new file mode 100644
index 0000000..4565730
--- /dev/null
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -0,0 +1,51 @@
+cc_binary {
+    name: "android.hardware.audio.service",
+
+    init_rc: ["android.hardware.audio.service.rc"],
+    relative_install_path: "hw",
+    vendor: true,
+    // Only support 32 bit  as the binary must always be installed at the same
+    // location for init to start it and the build system does not support
+    // having two binaries installable to the same location even if they are
+    // not installed in the same build.
+    compile_multilib: "32",
+    srcs: ["service.cpp"],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libbinder",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "libhardware",
+        "android.hardware.audio@2.0",
+        "android.hardware.audio@4.0",
+        "android.hardware.audio@5.0",
+        "android.hardware.audio@6.0",
+        "android.hardware.audio.common@2.0",
+        "android.hardware.audio.common@4.0",
+        "android.hardware.audio.common@5.0",
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.effect@2.0",
+        "android.hardware.audio.effect@4.0",
+        "android.hardware.audio.effect@5.0",
+        "android.hardware.audio.effect@6.0",
+        "android.hardware.bluetooth.a2dp@1.0",
+        "android.hardware.bluetooth.audio@2.0",
+        "android.hardware.soundtrigger@2.0",
+        "android.hardware.soundtrigger@2.1",
+        "android.hardware.soundtrigger@2.2",
+    ],
+}
+
+// Legacy service name, use android.hardware.audio.service instead
+phony {
+    name: "android.hardware.audio@2.0-service",
+    required: ["android.hardware.audio.service"],
+}
diff --git a/audio/common/all-versions/default/service/Android.mk b/audio/common/all-versions/default/service/Android.mk
deleted file mode 100644
index b57a1ae..0000000
--- a/audio/common/all-versions/default/service/Android.mk
+++ /dev/null
@@ -1,65 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-LOCAL_PATH := $(call my-dir)
-
-#
-# Service
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.audio@2.0-service
-LOCAL_INIT_RC := android.hardware.audio@2.0-service.rc
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_SRC_FILES := \
-    service.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libbinder \
-    libhidlbase \
-    libhidltransport \
-    liblog \
-    libutils \
-    libhardware \
-    libhwbinder \
-    android.hardware.audio@2.0 \
-    android.hardware.audio@4.0 \
-    android.hardware.audio@5.0 \
-    android.hardware.audio.common@2.0 \
-    android.hardware.audio.common@4.0 \
-    android.hardware.audio.common@5.0 \
-    android.hardware.audio.effect@2.0 \
-    android.hardware.audio.effect@4.0 \
-    android.hardware.audio.effect@5.0 \
-    android.hardware.bluetooth.a2dp@1.0 \
-    android.hardware.bluetooth.audio@2.0 \
-    android.hardware.soundtrigger@2.0 \
-    android.hardware.soundtrigger@2.1 \
-    android.hardware.soundtrigger@2.2
-
-# Can not switch to Android.bp until AUDIOSERVER_MULTILIB
-# is deprecated as build config variable are not supported
-ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
-LOCAL_MULTILIB := 32
-else
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-endif
-
-include $(BUILD_EXECUTABLE)
diff --git a/audio/common/all-versions/default/service/android.hardware.audio.service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
new file mode 100644
index 0000000..63d2542
--- /dev/null
+++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
@@ -0,0 +1,9 @@
+service vendor.audio-hal /vendor/bin/hw/android.hardware.audio.service
+    class hal
+    user audioserver
+    # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
+    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock
+    capabilities BLOCK_SUSPEND
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    onrestart restart audioserver
diff --git a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc b/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
deleted file mode 100644
index 6e91bcc..0000000
--- a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
+++ /dev/null
@@ -1,14 +0,0 @@
-service vendor.audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service
-    class hal
-    user audioserver
-    # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
-    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock
-    capabilities BLOCK_SUSPEND
-    ioprio rt 4
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
-    # audioflinger restarts itself when it loses connection with the hal
-    # and its .rc file has an "onrestart restart audio-hal" rule, thus
-    # an additional auto-restart from the init process isn't needed.
-    oneshot
-    interface android.hardware.audio@4.0::IDevicesFactory default
-    interface android.hardware.audio@2.0::IDevicesFactory default
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 8a7b2ea..2730f3b 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -19,9 +19,11 @@
 #include <android/hardware/audio/2.0/IDevicesFactory.h>
 #include <android/hardware/audio/4.0/IDevicesFactory.h>
 #include <android/hardware/audio/5.0/IDevicesFactory.h>
+#include <android/hardware/audio/6.0/IDevicesFactory.h>
 #include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
 #include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
 #include <android/hardware/audio/effect/5.0/IEffectsFactory.h>
+#include <android/hardware/audio/effect/6.0/IEffectsFactory.h>
 #include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
 #include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
@@ -36,6 +38,15 @@
 using namespace android::hardware;
 using android::OK;
 
+/** Try to register the provided factories in the provided order.
+ *  If any registers successfully, do not register any other and return true.
+ *  If all fail, return false.
+ */
+template <class... Factories>
+bool registerPassthroughServiceImplementations() {
+    return ((registerPassthroughServiceImplementation<Factories>() != OK) && ...);
+}
+
 int main(int /* argc */, char* /* argv */ []) {
     ::android::ProcessState::initWithDriver("/dev/vndbinder");
     // start a threadpool for vndbinder interactions
@@ -50,30 +61,36 @@
     }
     configureRpcThreadpool(16, true /*callerWillJoin*/);
 
-    bool fail = registerPassthroughServiceImplementation<audio::V5_0::IDevicesFactory>() != OK &&
-                registerPassthroughServiceImplementation<audio::V4_0::IDevicesFactory>() != OK &&
-                registerPassthroughServiceImplementation<audio::V2_0::IDevicesFactory>() != OK;
-    LOG_ALWAYS_FATAL_IF(fail, "Could not register audio core API 2, 4 nor 5");
+    // Keep versions on a separate line for easier parsing
+    // clang-format off
+    LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
+                                audio::V6_0::IDevicesFactory,
+                                audio::V5_0::IDevicesFactory,
+                                audio::V4_0::IDevicesFactory,
+                                audio::V2_0::IDevicesFactory>()),
+                        "Could not register audio core API");
 
-    fail = registerPassthroughServiceImplementation<audio::effect::V5_0::IEffectsFactory>() != OK &&
-           registerPassthroughServiceImplementation<audio::effect::V4_0::IEffectsFactory>() != OK &&
-           registerPassthroughServiceImplementation<audio::effect::V2_0::IEffectsFactory>() != OK,
-    LOG_ALWAYS_FATAL_IF(fail, "Could not register audio effect API 2, 4 nor 5");
+    LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
+                                audio::effect::V6_0::IEffectsFactory,
+                                audio::effect::V5_0::IEffectsFactory,
+                                audio::effect::V4_0::IEffectsFactory,
+                                audio::effect::V2_0::IEffectsFactory>()),
+                        "Could not register audio effect API");
+    // clang-format on
 
-    fail = registerPassthroughServiceImplementation<soundtrigger::V2_2::ISoundTriggerHw>() != OK &&
-           registerPassthroughServiceImplementation<soundtrigger::V2_1::ISoundTriggerHw>() != OK &&
-           registerPassthroughServiceImplementation<soundtrigger::V2_0::ISoundTriggerHw>() != OK,
-    ALOGW_IF(fail, "Could not register soundtrigger API 2.0, 2.1 nor 2.2");
+    ALOGW_IF((registerPassthroughServiceImplementations<soundtrigger::V2_2::ISoundTriggerHw,
+                                                        soundtrigger::V2_1::ISoundTriggerHw,
+                                                        soundtrigger::V2_0::ISoundTriggerHw>()),
+             "Could not register soundtrigger API");
 
-    fail = registerPassthroughServiceImplementation<
-                   bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>() != OK;
-    ALOGW_IF(fail, "Could not register Bluetooth Audio API 2.0");
+    ALOGW_IF(registerPassthroughServiceImplementations<
+                     bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>(),
+             "Could not register Bluetooth audio API");
 
     // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
-    fail =
-        registerPassthroughServiceImplementation<bluetooth::a2dp::V1_0::IBluetoothAudioOffload>() !=
-        OK;
-    ALOGW_IF(fail, "Could not register Bluetooth audio offload 1.0");
+    ALOGW_IF(registerPassthroughServiceImplementations<
+                     bluetooth::a2dp::V1_0::IBluetoothAudioOffload>(),
+             "Could not register Bluetooth audio offload API");
 
     joinRpcThreadpool();
 }
diff --git a/audio/common/all-versions/test/utility/include/utility/AssertOk.h b/audio/common/all-versions/test/utility/include/utility/AssertOk.h
index 5ac2fdc..03a6305 100644
--- a/audio/common/all-versions/test/utility/include/utility/AssertOk.h
+++ b/audio/common/all-versions/test/utility/include/utility/AssertOk.h
@@ -114,6 +114,27 @@
 #define ASSERT_RESULT(expected, ret) ASSERT_PRED_FORMAT2(detail::assertResult, expected, ret)
 #define EXPECT_RESULT(expected, ret) EXPECT_PRED_FORMAT2(detail::assertResult, expected, ret)
 
+/** Unpack the provided result.
+ * If the result is not OK, register a failure and return the default initializer value. */
+template <class R>
+static R extract(const Return<R>& ret) {
+    if (!ret.isOk()) {
+        EXPECT_IS_OK(ret);
+        return R{};
+    }
+    return ret;
+}
+
+template <class Result, class Value>
+static void expectValueOrFailure(Result res, Value expectedValue, Value actualValue,
+                                 Result expectedFailure) {
+    if (res == Result::OK) {
+        ASSERT_EQ(expectedValue, actualValue);
+    } else {
+        ASSERT_EQ(expectedFailure, res) << "Unexpected result " << toString(res);
+    }
+}
+
 }  // namespace utility
 }  // namespace test
 }  // namespace common
diff --git a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
index 0e416f3..2b240ce 100644
--- a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
+++ b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
@@ -20,9 +20,6 @@
 #include <functional>
 #include <list>
 
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <gtest/gtest.h>
-
 namespace android {
 namespace hardware {
 namespace audio {
@@ -34,18 +31,20 @@
  * Avoid destroying static objects after main return.
  * Post main return destruction leads to incorrect gtest timing measurements as
  * well as harder debuging if anything goes wrong during destruction. */
-class Environment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
+class EnvironmentTearDown {
+  public:
     using TearDownFunc = std::function<void()>;
     void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_front(std::move(tearDown)); }
 
-   private:
-    void HidlTearDown() override {
+  protected:
+    void executeAllTearDowns() {
         // Call the tear downs in reverse order of insertion
         for (auto& tearDown : tearDowns) {
             tearDown();
         }
     }
+
+  private:
     std::list<TearDownFunc> tearDowns;
 };
 
diff --git a/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h b/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h
deleted file mode 100644
index 3833fd0..0000000
--- a/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
-#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
-
-#include <iosfwd>
-#include <utility>
-
-/** @file Use HIDL generated toString methods to pretty print gtest errors
- *        Unfortunately Gtest does not offer a template to specialize, only
- *        overloading PrintTo.
- *  @note that this overload can NOT be template because
- *        the fallback is already template, resulting in ambiguity.
- *  @note that the overload MUST be in the exact namespace
- *        the type is declared in, as per the ADL rules.
- */
-
-namespace android {
-namespace hardware {
-namespace audio {
-
-#define DEFINE_GTEST_PRINT_TO(T) \
-    inline void PrintTo(const T& val, ::std::ostream* os) { *os << toString(val); }
-
-namespace CPP_VERSION {
-DEFINE_GTEST_PRINT_TO(IPrimaryDevice::TtyMode)
-DEFINE_GTEST_PRINT_TO(Result)
-}  // namespace CPP_VERSION
-
-namespace common {
-namespace CPP_VERSION {
-DEFINE_GTEST_PRINT_TO(AudioConfig)
-DEFINE_GTEST_PRINT_TO(AudioMode)
-DEFINE_GTEST_PRINT_TO(AudioDevice)
-DEFINE_GTEST_PRINT_TO(AudioFormat)
-DEFINE_GTEST_PRINT_TO(AudioChannelMask)
-}  // namespace CPP_VERSION
-}  // namespace common
-
-#undef DEFINE_GTEST_PRINT_TO
-
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
index a1af3c4..6f18d1d 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -19,12 +19,12 @@
     export_include_dirs: ["include"],
 
     shared_libs: [
+        "libaudiofoundation",
         "libbase",
         "libcutils",
         "libfmq",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.audio.common-util",
@@ -46,13 +46,11 @@
 cc_library_shared {
     name: "android.hardware.audio@2.0-impl",
     defaults: ["android.hardware.audio-impl_default"],
-
     shared_libs: [
         "android.hardware.audio@2.0",
         "android.hardware.audio.common@2.0",
         "android.hardware.audio.common@2.0-util",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=2",
         "-DMINOR_VERSION=0",
@@ -69,7 +67,6 @@
         "android.hardware.audio.common@4.0",
         "android.hardware.audio.common@4.0-util",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=4",
         "-DMINOR_VERSION=0",
@@ -80,16 +77,29 @@
 cc_library_shared {
     name: "android.hardware.audio@5.0-impl",
     defaults: ["android.hardware.audio-impl_default"],
-
     shared_libs: [
         "android.hardware.audio@5.0",
         "android.hardware.audio.common@5.0",
         "android.hardware.audio.common@5.0-util",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=5",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
     ]
 }
+
+cc_library_shared {
+    name: "android.hardware.audio@6.0-impl",
+    defaults: ["android.hardware.audio-impl_default"],
+    shared_libs: [
+        "android.hardware.audio@6.0",
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.common@6.0-util",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
diff --git a/audio/core/all-versions/default/Conversions.cpp b/audio/core/all-versions/default/Conversions.cpp
index 11872c0..eddff55 100644
--- a/audio/core/all-versions/default/Conversions.cpp
+++ b/audio/core/all-versions/default/Conversions.cpp
@@ -19,6 +19,7 @@
 #include <stdio.h>
 
 #include <log/log.h>
+#include <media/AudioContainers.h>
 
 namespace android {
 namespace hardware {
@@ -31,26 +32,22 @@
     char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
     memset(halAddress, 0, sizeof(halAddress));
     uint32_t halDevice = static_cast<uint32_t>(address.device);
-    const bool isInput = (halDevice & AUDIO_DEVICE_BIT_IN) != 0;
-    if (isInput) halDevice &= ~AUDIO_DEVICE_BIT_IN;
-    if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) ||
-        (isInput && (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+    if (getAudioDeviceOutAllA2dpSet().count(halDevice) > 0 ||
+        halDevice == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
         snprintf(halAddress, sizeof(halAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
                  address.address.mac[0], address.address.mac[1], address.address.mac[2],
                  address.address.mac[3], address.address.mac[4], address.address.mac[5]);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_IP) != 0) ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_IP) != 0)) {
+    } else if (halDevice == AUDIO_DEVICE_OUT_IP || halDevice == AUDIO_DEVICE_IN_IP) {
         snprintf(halAddress, sizeof(halAddress), "%d.%d.%d.%d", address.address.ipv4[0],
                  address.address.ipv4[1], address.address.ipv4[2], address.address.ipv4[3]);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0) ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0)) {
+    } else if (getAudioDeviceOutAllUsbSet().count(halDevice) > 0 ||
+               getAudioDeviceInAllUsbSet().count(halDevice) > 0) {
         snprintf(halAddress, sizeof(halAddress), "card=%d;device=%d", address.address.alsa.card,
                  address.address.alsa.device);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_BUS) != 0) ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_BUS) != 0)) {
+    } else if (halDevice == AUDIO_DEVICE_OUT_BUS || halDevice == AUDIO_DEVICE_IN_BUS) {
         snprintf(halAddress, sizeof(halAddress), "%s", address.busAddress.c_str());
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
+    } else if (halDevice == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ||
+               halDevice == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
         snprintf(halAddress, sizeof(halAddress), "%s", address.rSubmixAddress.c_str());
     }
     return halAddress;
@@ -67,32 +64,28 @@
         return OK;
     }
 
-    const bool isInput = (device & AUDIO_DEVICE_BIT_IN) != 0;
-    if (isInput) device &= ~AUDIO_DEVICE_BIT_IN;
-    if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) ||
-        (isInput && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+    if (getAudioDeviceOutAllA2dpSet().count(device) > 0 ||
+        device == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
         int status =
             sscanf(halAddress, "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", &address->address.mac[0],
                    &address->address.mac[1], &address->address.mac[2], &address->address.mac[3],
                    &address->address.mac[4], &address->address.mac[5]);
         return status == 6 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_IP) != 0) ||
-               (isInput && (device & AUDIO_DEVICE_IN_IP) != 0)) {
+    } else if (device == AUDIO_DEVICE_OUT_IP || device == AUDIO_DEVICE_IN_IP) {
         int status =
             sscanf(halAddress, "%hhu.%hhu.%hhu.%hhu", &address->address.ipv4[0],
                    &address->address.ipv4[1], &address->address.ipv4[2], &address->address.ipv4[3]);
         return status == 4 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_USB)) != 0 ||
-               (isInput && (device & AUDIO_DEVICE_IN_ALL_USB)) != 0) {
+    } else if (getAudioDeviceOutAllUsbSet().count(device) > 0 ||
+               getAudioDeviceInAllUsbSet().count(device) > 0) {
         int status = sscanf(halAddress, "card=%d;device=%d", &address->address.alsa.card,
                             &address->address.alsa.device);
         return status == 2 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_BUS) != 0) ||
-               (isInput && (device & AUDIO_DEVICE_IN_BUS) != 0)) {
+    } else if (device == AUDIO_DEVICE_OUT_BUS || device == AUDIO_DEVICE_IN_BUS) {
         address->busAddress = halAddress;
         return OK;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 ||
-               (isInput && (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
+    } else if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ||
+               device == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
         address->rSubmixAddress = halAddress;
         return OK;
     }
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index bec22df..21dab00 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -39,11 +39,10 @@
 
 using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
 
-Device::Device(audio_hw_device_t* device) : mDevice(device) {}
+Device::Device(audio_hw_device_t* device) : mIsClosed(false), mDevice(device) {}
 
 Device::~Device() {
-    int status = audio_hw_device_close(mDevice);
-    ALOGW_IF(status, "Error closing audio hw device %p: %s", mDevice, strerror(-status));
+    (void)doClose();
     mDevice = nullptr;
 }
 
@@ -54,10 +53,14 @@
 
 void Device::closeInputStream(audio_stream_in_t* stream) {
     mDevice->close_input_stream(mDevice, stream);
+    LOG_ALWAYS_FATAL_IF(mOpenedStreamsCount == 0, "mOpenedStreamsCount is already 0");
+    --mOpenedStreamsCount;
 }
 
 void Device::closeOutputStream(audio_stream_out_t* stream) {
     mDevice->close_output_stream(mDevice, stream);
+    LOG_ALWAYS_FATAL_IF(mOpenedStreamsCount == 0, "mOpenedStreamsCount is already 0");
+    --mOpenedStreamsCount;
 }
 
 char* Device::halGetParameters(const char* keys) {
@@ -159,6 +162,7 @@
     sp<IStreamOut> streamOut;
     if (status == OK) {
         streamOut = new StreamOut(this, halStream);
+        ++mOpenedStreamsCount;
     }
     HidlUtils::audioConfigFromHal(halConfig, suggestedConfig);
     return {analyzeStatus("open_output_stream", status, {EINVAL} /*ignore*/), streamOut};
@@ -185,6 +189,7 @@
     sp<IStreamIn> streamIn;
     if (status == OK) {
         streamIn = new StreamIn(this, halStream);
+        ++mOpenedStreamsCount;
     }
     HidlUtils::audioConfigFromHal(halConfig, suggestedConfig);
     return {analyzeStatus("open_input_stream", status, {EINVAL} /*ignore*/), streamIn};
@@ -378,11 +383,23 @@
 }
 
 Return<Result> Device::setConnectedState(const DeviceAddress& address, bool connected) {
-    auto key = connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect;
+    auto key = connected ? AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect;
     return setParam(key, address);
 }
 #endif
 
+Result Device::doClose() {
+    if (mIsClosed || mOpenedStreamsCount != 0) return Result::INVALID_STATE;
+    mIsClosed = true;
+    return analyzeStatus("close", audio_hw_device_close(mDevice));
+}
+
+#if MAJOR_VERSION >= 6
+Return<Result> Device::close() {
+    return doClose();
+}
+#endif
+
 }  // namespace implementation
 }  // namespace CPP_VERSION
 }  // namespace audio
diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp
index 99590b0..3cf0932 100644
--- a/audio/core/all-versions/default/PrimaryDevice.cpp
+++ b/audio/core/all-versions/default/PrimaryDevice.cpp
@@ -31,7 +31,11 @@
 
 PrimaryDevice::PrimaryDevice(audio_hw_device_t* device) : mDevice(new Device(device)) {}
 
-PrimaryDevice::~PrimaryDevice() {}
+PrimaryDevice::~PrimaryDevice() {
+    // Do not call mDevice->close here. If there are any unclosed streams,
+    // they only hold IDevice instance, not IPrimaryDevice, thus IPrimaryDevice
+    // "part" of a device can be destroyed before the streams.
+}
 
 // Methods from ::android::hardware::audio::CPP_VERSION::IDevice follow.
 Return<Result> PrimaryDevice::initCheck() {
@@ -160,6 +164,11 @@
     return mDevice->setConnectedState(address, connected);
 }
 #endif
+#if MAJOR_VERSION >= 6
+Return<Result> PrimaryDevice::close() {
+    return mDevice->close();
+}
+#endif
 
 // Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow.
 Return<Result> PrimaryDevice::setVoiceVolume(float volume) {
diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp
index b995657..74e5945 100644
--- a/audio/core/all-versions/default/Stream.cpp
+++ b/audio/core/all-versions/default/Stream.cpp
@@ -26,9 +26,8 @@
 #include <android/log.h>
 #include <hardware/audio.h>
 #include <hardware/audio_effect.h>
+#include <media/AudioContainers.h>
 #include <media/TypeConverter.h>
-#include <utils/SortedVector.h>
-#include <utils/Vector.h>
 
 namespace android {
 namespace hardware {
@@ -100,11 +99,11 @@
     Result result =
         getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue, context);
     hidl_vec<uint32_t> sampleRates;
-    SortedVector<uint32_t> halSampleRates;
+    SampleRateSet halSampleRates;
     if (result == Result::OK) {
         halSampleRates =
             samplingRatesFromString(halListValue.string(), AudioParameter::valueListSeparator);
-        sampleRates.setToExternal(halSampleRates.editArray(), halSampleRates.size());
+        sampleRates = hidl_vec<uint32_t>(halSampleRates.begin(), halSampleRates.end());
         // Legacy get_parameter does not return a status_t, thus can not advertise of failure.
         // Note that this method must succeed (non empty list) if the format is supported.
         if (sampleRates.size() == 0) {
@@ -126,13 +125,14 @@
     String8 halListValue;
     Result result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue, context);
     hidl_vec<AudioChannelBitfield> channelMasks;
-    SortedVector<audio_channel_mask_t> halChannelMasks;
+    ChannelMaskSet halChannelMasks;
     if (result == Result::OK) {
         halChannelMasks =
             channelMasksFromString(halListValue.string(), AudioParameter::valueListSeparator);
         channelMasks.resize(halChannelMasks.size());
-        for (size_t i = 0; i < halChannelMasks.size(); ++i) {
-            channelMasks[i] = AudioChannelBitfield(halChannelMasks[i]);
+        size_t i = 0;
+        for (auto channelMask : halChannelMasks) {
+            channelMasks[i++] = AudioChannelBitfield(channelMask);
         }
         // Legacy get_parameter does not return a status_t, thus can not advertise of failure.
         // Note that this method must succeed (non empty list) if the format is supported.
@@ -168,15 +168,24 @@
     String8 halListValue;
     Result result = getParam(AudioParameter::keyStreamSupportedFormats, &halListValue);
     hidl_vec<AudioFormat> formats;
-    Vector<audio_format_t> halFormats;
+    FormatVector halFormats;
     if (result == Result::OK) {
         halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator);
         formats.resize(halFormats.size());
         for (size_t i = 0; i < halFormats.size(); ++i) {
             formats[i] = AudioFormat(halFormats[i]);
         }
+        // Legacy get_parameter does not return a status_t, thus can not advertise of failure.
+        // Note that the method must not return an empty list if this capability is supported.
+        if (formats.size() == 0) {
+            result = Result::NOT_SUPPORTED;
+        }
     }
+#if MAJOR_VERSION <= 5
     _hidl_cb(formats);
+#elif MAJOR_VERSION >= 6
+    _hidl_cb(result, formats);
+#endif
     return Void();
 }
 
@@ -243,8 +252,8 @@
 
 Return<Result> Stream::setConnectedState(const DeviceAddress& address, bool connected) {
     return setParam(
-        connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect,
-        address);
+            connected ? AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect,
+            address);
 }
 #elif MAJOR_VERSION >= 4
 Return<void> Stream::getDevices(getDevices_cb _hidl_cb) {
diff --git a/audio/core/all-versions/default/StreamIn.cpp b/audio/core/all-versions/default/StreamIn.cpp
index d316f83..f1152ca 100644
--- a/audio/core/all-versions/default/StreamIn.cpp
+++ b/audio/core/all-versions/default/StreamIn.cpp
@@ -139,8 +139,7 @@
 }  // namespace
 
 StreamIn::StreamIn(const sp<Device>& device, audio_stream_in_t* stream)
-    : mIsClosed(false),
-      mDevice(device),
+    : mDevice(device),
       mStream(stream),
       mStreamCommon(new Stream(&stream->common)),
       mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
@@ -159,7 +158,9 @@
         status_t status = EventFlag::deleteEventFlag(&mEfGroup);
         ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
     }
+#if MAJOR_VERSION <= 5
     mDevice->closeInputStream(mStream);
+#endif
     mStream = nullptr;
 }
 
@@ -303,14 +304,16 @@
 }
 
 Return<Result> StreamIn::close() {
-    if (mIsClosed) return Result::INVALID_STATE;
-    mIsClosed = true;
-    if (mReadThread.get()) {
-        mStopReadThread.store(true, std::memory_order_release);
+    if (mStopReadThread.load(std::memory_order_relaxed)) {  // only this thread writes
+        return Result::INVALID_STATE;
     }
+    mStopReadThread.store(true, std::memory_order_release);
     if (mEfGroup) {
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
     }
+#if MAJOR_VERSION >= 6
+    mDevice->closeInputStream(mStream);
+#endif
     return Result::OK;
 }
 
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 82cc408..396d354 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -138,8 +138,7 @@
 }  // namespace
 
 StreamOut::StreamOut(const sp<Device>& device, audio_stream_out_t* stream)
-    : mIsClosed(false),
-      mDevice(device),
+    : mDevice(device),
       mStream(stream),
       mStreamCommon(new Stream(&stream->common)),
       mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)),
@@ -148,7 +147,7 @@
 
 StreamOut::~StreamOut() {
     ATRACE_CALL();
-    close();
+    (void)close();
     if (mWriteThread.get()) {
         ATRACE_NAME("mWriteThread->join");
         status_t status = mWriteThread->join();
@@ -159,10 +158,12 @@
         ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status));
     }
     mCallback.clear();
+#if MAJOR_VERSION <= 5
     mDevice->closeOutputStream(mStream);
     // Closing the output stream in the HAL waits for the callback to finish,
     // and joins the callback thread. Thus is it guaranteed that the callback
     // thread will not be accessing our object anymore.
+#endif
     mStream = nullptr;
 }
 
@@ -291,14 +292,16 @@
 #endif
 
 Return<Result> StreamOut::close() {
-    if (mIsClosed) return Result::INVALID_STATE;
-    mIsClosed = true;
-    if (mWriteThread.get()) {
-        mStopWriteThread.store(true, std::memory_order_release);
+    if (mStopWriteThread.load(std::memory_order_relaxed)) {  // only this thread writes
+        return Result::INVALID_STATE;
     }
+    mStopWriteThread.store(true, std::memory_order_release);
     if (mEfGroup) {
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
     }
+#if MAJOR_VERSION >= 6
+    mDevice->closeOutputStream(mStream);
+#endif
     return Result::OK;
 }
 
diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h
index e64f00f..11ab607 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -114,6 +114,9 @@
     Return<void> getMicrophones(getMicrophones_cb _hidl_cb) override;
     Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override;
 #endif
+#if MAJOR_VERSION >= 6
+    Return<Result> close() override;
+#endif
 
     Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
@@ -124,11 +127,15 @@
     void closeOutputStream(audio_stream_out_t* stream);
     audio_hw_device_t* device() const { return mDevice; }
 
-   private:
+  private:
+    bool mIsClosed;
     audio_hw_device_t* mDevice;
+    int mOpenedStreamsCount = 0;
 
     virtual ~Device();
 
+    Result doClose();
+
     // Methods from ParametersUtil.
     char* halGetParameters(const char* keys) override;
     int halSetParameters(const char* keysAndValues) override;
diff --git a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
index 9d69cb0..f5f3848 100644
--- a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
+++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
@@ -96,6 +96,9 @@
     Return<void> getMicrophones(getMicrophones_cb _hidl_cb) override;
     Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override;
 #endif
+#if MAJOR_VERSION >= 6
+    Return<Result> close() override;
+#endif
 
     Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
diff --git a/audio/core/all-versions/default/include/core/default/StreamIn.h b/audio/core/all-versions/default/include/core/default/StreamIn.h
index 6209b8f..24f9944 100644
--- a/audio/core/all-versions/default/include/core/default/StreamIn.h
+++ b/audio/core/all-versions/default/include/core/default/StreamIn.h
@@ -120,7 +120,6 @@
                                          uint64_t* time);
 
    private:
-    bool mIsClosed;
     const sp<Device> mDevice;
     audio_stream_in_t* mStream;
     const sp<Stream> mStreamCommon;
diff --git a/audio/core/all-versions/default/include/core/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h
index b098005..6334785 100644
--- a/audio/core/all-versions/default/include/core/default/StreamOut.h
+++ b/audio/core/all-versions/default/include/core/default/StreamOut.h
@@ -126,7 +126,6 @@
                                               TimeSpec* timeStamp);
 
    private:
-    bool mIsClosed;
     const sp<Device> mDevice;
     audio_stream_out_t* mStream;
     const sp<Stream> mStreamCommon;
diff --git a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
index 7906bf1..c189464 100644
--- a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
@@ -60,19 +60,20 @@
                "deconnection",
                testConnectedState(stream.get()))
 
-TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync()));
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail",
+               ASSERT_IS_OK(getDevice()->getHwAvSync()));
 
-TEST_F(AudioPrimaryHidlTest, setMode) {
+TEST_P(AudioPrimaryHidlTest, setMode) {
     doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
     // Test Invalid values
     for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) {
         SCOPED_TRACE("mode=" + toString(mode));
-        ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode));
+        ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(mode));
     }
     // Test valid values
     for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
                            AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
         SCOPED_TRACE("mode=" + toString(mode));
-        ASSERT_OK(device->setMode(mode));
+        ASSERT_OK(getDevice()->setMode(mode));
     }
 }
diff --git a/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h
new file mode 100644
index 0000000..6373e39
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
+#define ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+
+#include "utility/EnvironmentTearDown.h"
+
+class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown,
+                    public ::testing::VtsHalHidlTargetTestEnvBase {
+  private:
+    void HidlTearDown() override {
+        executeAllTearDowns();
+        VtsHalHidlTargetTestEnvBase::HidlTearDown();
+    }
+};
+
+#endif  // ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
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 022f75e..709b7cd 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -16,41 +16,35 @@
 
 #include "AudioPrimaryHidlHalTest.h"
 
-static void waitForDeviceDestruction() {
-    // FIXME: there is no way to know when the remote IDevice 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);
-}
-
-TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
+TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
     doc::test("Calling openDevice(\"primary\") should return the primary device.");
-    {
-        Result result;
-        sp<IDevice> baseDevice;
-        ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
-        ASSERT_OK(result);
-        ASSERT_TRUE(baseDevice != nullptr);
+    if (getDeviceName() != DeviceManager::kPrimaryDevice) {
+        GTEST_SKIP() << "No primary device on this factory";  // returns
+    }
 
+    {  // Scope for device SPs
+        sp<IDevice> baseDevice =
+                DeviceManager::getInstance().get(getFactoryName(), DeviceManager::kPrimaryDevice);
+        ASSERT_TRUE(baseDevice != nullptr);
         Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
-        ASSERT_TRUE(primaryDevice.isOk());
-        ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
-    }  // Destroy local IDevice proxy
-    waitForDeviceDestruction();
+        EXPECT_TRUE(primaryDevice.isOk());
+        EXPECT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
+    }
+    EXPECT_TRUE(
+            DeviceManager::getInstance().reset(getFactoryName(), DeviceManager::kPrimaryDevice));
 }
 
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////////// get(Active)Microphones ///////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) {
+TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) {
     doc::test("Make sure getMicrophones always succeeds");
     hidl_vec<MicrophoneInfo> microphones;
-    ASSERT_OK(device->getMicrophones(returnIn(res, microphones)));
+    ASSERT_OK(getDevice()->getMicrophones(returnIn(res, microphones)));
+    if (res == Result::NOT_SUPPORTED) {
+        GTEST_SKIP() << "getMicrophones is not supported";  // returns
+    }
     ASSERT_OK(res);
     if (microphones.size() > 0) {
         // When there is microphone on the phone, try to open an input stream
@@ -58,7 +52,6 @@
         doc::test(
             "Make sure getMicrophones always succeeds"
             "and getActiveMicrophones always succeeds when recording from these microphones.");
-        AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
         AudioConfig config{};
         config.channelMask = mkEnumBitfield(AudioChannelMask::IN_MONO);
         config.sampleRateHz = 8000;
@@ -71,18 +64,14 @@
                 continue;
             }
             sp<IStreamIn> stream;
+            StreamHelper<IStreamIn> helper(stream);
             AudioConfig suggestedConfig{};
-            ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, config, flags,
-                                              initMetadata,
-                                              returnIn(res, stream, suggestedConfig)));
-            if (res != Result::OK) {
-                ASSERT_TRUE(stream == nullptr);
-                AudioConfig suggestedConfigRetry{};
-                ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress,
-                                                  suggestedConfig, flags, initMetadata,
-                                                  returnIn(res, stream, suggestedConfigRetry)));
-            }
-            ASSERT_OK(res);
+            ASSERT_NO_FATAL_FAILURE(helper.open(
+                    [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                        return getDevice()->openInputStream(handle, microphone.deviceAddress,
+                                                            config, flags, initMetadata, cb);
+                    },
+                    config, &res, &suggestedConfig));
             hidl_vec<MicrophoneInfo> activeMicrophones;
             Result readRes;
             typedef MessageQueue<IStreamIn::ReadParameters, kSynchronizedReadWrite> CommandMQ;
@@ -116,7 +105,8 @@
                 ASSERT_OK(res);
                 ASSERT_NE(0U, activeMicrophones.size());
             }
-            stream->close();
+            helper.close(true /*clear*/, &res);
+            ASSERT_OK(res);
             if (efGroup) {
                 EventFlag::deleteEventFlag(&efGroup);
             }
@@ -124,7 +114,7 @@
     }
 }
 
-TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
+TEST_P(AudioHidlDeviceTest, SetConnectedState) {
     doc::test("Check that the HAL can be notified of device connection and deconnection");
     using AD = AudioDevice;
     for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
@@ -133,7 +123,7 @@
             SCOPED_TRACE("state=" + ::testing::PrintToString(state));
             DeviceAddress address = {};
             address.device = deviceType;
-            auto ret = device->setConnectedState(address, state);
+            auto ret = getDevice()->setConnectedState(address, state);
             ASSERT_TRUE(ret.isOk());
             if (ret == Result::NOT_SUPPORTED) {
                 doc::partialTest("setConnectedState is not supported");
@@ -146,8 +136,7 @@
     // Because there is no way of knowing if the devices were connected before
     // calling setConnectedState, there is no way to restore the HAL to its
     // initial state. To workaround this, destroy the HAL at the end of this test.
-    device.clear();
-    waitForDeviceDestruction();
+    ASSERT_TRUE(resetDevice());
 }
 
 static void testGetDevices(IStream* stream, AudioDevice expectedDevice) {
@@ -173,9 +162,10 @@
     DeviceAddress otherAddress = address;
     otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER
                                                                       : AudioDevice::IN_BUILTIN_MIC;
-    EXPECT_OK(stream->setDevices({otherAddress}));
+    EXPECT_RESULT(okOrNotSupported, stream->setDevices({otherAddress}));
 
-    ASSERT_OK(stream->setDevices({address}));  // Go back to the original value
+    ASSERT_RESULT(okOrNotSupported,
+                  stream->setDevices({address}));  // Go back to the original value
 }
 
 TEST_IO_STREAM(SetDevices, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC",
@@ -191,7 +181,7 @@
     }
     ASSERT_OK(res);
 }
-TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(device.get()));
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(getDevice().get()));
 
 TEST_P(InputStreamTest, updateSinkMetadata) {
     doc::test("The HAL should not crash on metadata change");
@@ -251,58 +241,58 @@
     ASSERT_OK(stream->updateSourceMetadata(initMetadata));
 }
 
-TEST_F(AudioPrimaryHidlTest, setMode) {
+TEST_P(AudioPrimaryHidlTest, setMode) {
     doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
     // Test Invalid values
     for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) {
-        ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode)))
-            << "mode=" << mode;
+        ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
+                << "mode=" << mode;
     }
     // Test valid values
     for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
                            AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
-        ASSERT_OK(device->setMode(mode)) << "mode=" << toString(mode);
+        ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
     }
 }
 
-TEST_F(AudioPrimaryHidlTest, setBtHfpSampleRate) {
+TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) {
     doc::test(
         "Make sure setBtHfpSampleRate either succeeds or "
         "indicates that it is not supported at all, or that the provided value is invalid");
     for (auto samplingRate : {8000, 16000, 22050, 24000}) {
-        ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, device->setBtHfpSampleRate(samplingRate));
+        ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setBtHfpSampleRate(samplingRate));
     }
 }
 
-TEST_F(AudioPrimaryHidlTest, setBtHfpVolume) {
+TEST_P(AudioPrimaryHidlTest, setBtHfpVolume) {
     doc::test(
         "Make sure setBtHfpVolume is either not supported or "
         "only succeed if volume is in [0,1]");
-    auto ret = device->setBtHfpVolume(0.0);
+    auto ret = getDevice()->setBtHfpVolume(0.0);
     ASSERT_TRUE(ret.isOk());
     if (ret == Result::NOT_SUPPORTED) {
         doc::partialTest("setBtHfpVolume is not supported");
         return;
     }
-    testUnitaryGain([](float volume) { return device->setBtHfpVolume(volume); });
+    testUnitaryGain([this](float volume) { return getDevice()->setBtHfpVolume(volume); });
 }
 
-TEST_F(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) {
+TEST_P(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) {
     doc::test(
         "Make sure setBtScoHeadsetDebugName either succeeds or "
         "indicates that it is not supported");
-    ASSERT_RESULT(okOrNotSupported, device->setBtScoHeadsetDebugName("test"));
+    ASSERT_RESULT(okOrNotSupported, getDevice()->setBtScoHeadsetDebugName("test"));
 }
 
-TEST_F(AudioPrimaryHidlTest, updateRotation) {
+TEST_P(AudioPrimaryHidlTest, updateRotation) {
     doc::test("Check that the hal can receive the current rotation");
     for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180,
                               Rotation::DEG_270, Rotation::DEG_0}) {
-        ASSERT_RESULT(okOrNotSupported, device->updateRotation(rotation));
+        ASSERT_RESULT(okOrNotSupported, getDevice()->updateRotation(rotation));
     }
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) {
     doc::test("Query and set the BT HFP state");
     testAccessors<OPTIONAL>("BtHfpEnabled", Initial{false, OPTIONAL}, {true},
                             &IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled);
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h
index 8415053..7a52d0e 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h
@@ -75,11 +75,18 @@
         return res;
     }
 
+#if MAJOR_VERSION <= 5
     static Result formats(IStream* stream, hidl_vec<AudioFormat>& capabilities) {
         EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities)));
-        // TODO: this should be an optional function
         return Result::OK;
     }
+#elif MAJOR_VERSION >= 6
+    static Result formats(IStream* stream, hidl_vec<AudioFormat>& capabilities) {
+        Result res;
+        EXPECT_OK(stream->getSupportedFormats(returnIn(res, capabilities)));
+        return res;
+    }
+#endif
 };
 
 template <class T>
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
new file mode 100644
index 0000000..2afbbb8
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+// pull in all the <= 5.0 tests
+#include "5.0/AudioPrimaryHidlHalTest.cpp"
+
+const std::vector<DeviceParameter>& getDeviceParametersForFactoryTests() {
+    static std::vector<DeviceParameter> parameters = [] {
+        std::vector<DeviceParameter> result;
+        const auto factories =
+                ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor);
+        for (const auto& factoryName : factories) {
+            result.emplace_back(factoryName,
+                                DeviceManager::getInstance().getPrimary(factoryName) != nullptr
+                                        ? DeviceManager::kPrimaryDevice
+                                        : "");
+        }
+        return result;
+    }();
+    return parameters;
+}
+
+const std::vector<DeviceParameter>& getDeviceParametersForPrimaryDeviceTests() {
+    static std::vector<DeviceParameter> parameters = [] {
+        std::vector<DeviceParameter> result;
+        const auto primary = std::find_if(
+                getDeviceParameters().begin(), getDeviceParameters().end(), [](const auto& elem) {
+                    return std::get<PARAM_DEVICE_NAME>(elem) == DeviceManager::kPrimaryDevice;
+                });
+        if (primary != getDeviceParameters().end()) result.push_back(*primary);
+        return result;
+    }();
+    return parameters;
+}
+
+const std::vector<DeviceParameter>& getDeviceParameters() {
+    static std::vector<DeviceParameter> parameters = [] {
+        std::vector<DeviceParameter> result;
+        const auto factories =
+                ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor);
+        const auto devices = getCachedPolicyConfig().getModulesWithDevicesNames();
+        result.reserve(devices.size());
+        for (const auto& factoryName : factories) {
+            for (const auto& deviceName : devices) {
+                if (DeviceManager::getInstance().get(factoryName, deviceName) != nullptr) {
+                    result.emplace_back(factoryName, deviceName);
+                }
+            }
+        }
+        return result;
+    }();
+    return parameters;
+}
+
+const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
+    static std::vector<DeviceConfigParameter> parameters = [] {
+        std::vector<DeviceConfigParameter> result;
+        for (const auto& device : getDeviceParameters()) {
+            auto module =
+                    getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
+            for (const auto& ioProfile : module->getOutputProfiles()) {
+                for (const auto& profile : ioProfile->getAudioProfiles()) {
+                    const auto& channels = profile->getChannels();
+                    const auto& sampleRates = profile->getSampleRates();
+                    auto configs = ConfigHelper::combineAudioConfig(
+                            vector<audio_channel_mask_t>(channels.begin(), channels.end()),
+                            vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
+                            profile->getFormat());
+                    auto flags = ioProfile->getFlags();
+                    for (auto& config : configs) {
+                        // Some combinations of flags declared in the config file require special
+                        // treatment.
+                        if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+                            config.offloadInfo.sampleRateHz = config.sampleRateHz;
+                            config.offloadInfo.channelMask = config.channelMask;
+                            config.offloadInfo.format = config.format;
+                            config.offloadInfo.streamType = AudioStreamType::MUSIC;
+                            config.offloadInfo.bitRatePerSecond = 320;
+                            config.offloadInfo.durationMicroseconds = -1;
+                            config.offloadInfo.bitWidth = 16;
+                            config.offloadInfo.bufferSize = 256;  // arbitrary value
+                            config.offloadInfo.usage = AudioUsage::MEDIA;
+                            result.emplace_back(device, config,
+                                                AudioOutputFlag(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+                                                                AUDIO_OUTPUT_FLAG_DIRECT));
+                        } else {
+                            if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {  // ignore the flag
+                                flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY;
+                            }
+                            result.emplace_back(device, config, AudioOutputFlag(flags));
+                        }
+                    }
+                }
+            }
+        }
+        return result;
+    }();
+    return parameters;
+}
+
+const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
+    static std::vector<DeviceConfigParameter> parameters = [] {
+        std::vector<DeviceConfigParameter> result;
+        for (const auto& device : getDeviceParameters()) {
+            auto module =
+                    getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
+            for (const auto& ioProfile : module->getInputProfiles()) {
+                for (const auto& profile : ioProfile->getAudioProfiles()) {
+                    const auto& channels = profile->getChannels();
+                    const auto& sampleRates = profile->getSampleRates();
+                    auto configs = ConfigHelper::combineAudioConfig(
+                            vector<audio_channel_mask_t>(channels.begin(), channels.end()),
+                            vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
+                            profile->getFormat());
+                    for (const auto& config : configs) {
+                        result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags()));
+                    }
+                }
+            }
+        }
+        return result;
+    }();
+    return parameters;
+}
+
+TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) {
+    doc::test("Verify that a device can't be closed if there are streams opened");
+    DeviceAddress address{.device = AudioDevice::OUT_DEFAULT};
+    AudioConfig config{};
+    auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
+    SourceMetadata initMetadata = {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 1 /* gain */}}};
+    sp<IStreamOut> stream;
+    StreamHelper<IStreamOut> helper(stream);
+    AudioConfig suggestedConfig{};
+    ASSERT_NO_FATAL_FAILURE(helper.open(
+            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                return getDevice()->openOutputStream(handle, address, config, flags, initMetadata,
+                                                     cb);
+            },
+            config, &res, &suggestedConfig));
+    ASSERT_RESULT(Result::INVALID_STATE, getDevice()->close());
+    ASSERT_NO_FATAL_FAILURE(helper.close(true /*clear*/, &res));
+    ASSERT_OK(getDevice()->close());
+    ASSERT_TRUE(resetDevice());
+}
+
+TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) {
+    doc::test("Verify that a device can't be closed if there are streams opened");
+    auto module = getCachedPolicyConfig().getModuleFromName(getDeviceName());
+    if (module->getInputProfiles().empty()) {
+        GTEST_SKIP() << "Device doesn't have input profiles";
+    }
+    DeviceAddress address{.device = AudioDevice::IN_DEFAULT};
+    AudioConfig config{};
+    auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
+    SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}};
+    sp<IStreamIn> stream;
+    StreamHelper<IStreamIn> helper(stream);
+    AudioConfig suggestedConfig{};
+    ASSERT_NO_FATAL_FAILURE(helper.open(
+            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                return getDevice()->openInputStream(handle, address, config, flags, initMetadata,
+                                                    cb);
+            },
+            config, &res, &suggestedConfig));
+    ASSERT_RESULT(Result::INVALID_STATE, getDevice()->close());
+    ASSERT_NO_FATAL_FAILURE(helper.close(true /*clear*/, &res));
+    ASSERT_OK(getDevice()->close());
+    ASSERT_TRUE(resetDevice());
+}
diff --git a/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h
new file mode 100644
index 0000000..593759f
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
+#define ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
+
+#include <gtest/gtest.h>
+
+#include "utility/EnvironmentTearDown.h"
+
+class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown,
+                    public ::testing::Environment {
+  public:
+    void init(int* /*argc*/, char** /*argv*/) {}  // emulate VtsHalHidlTargetTestEnvBase
+  private:
+    void TearDown() override { executeAllTearDowns(); }
+};
+
+// FIXME: Will be removed while making getDeviceParameters to use the config
+static constexpr const char* kDefaultServiceName = "default";
+
+#endif  // ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 88fdb5a..73af7f4 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -24,6 +24,7 @@
         "libxml2",
     ],
     shared_libs: [
+        "libaudiofoundation",
         "libfmq",
     ],
     header_libs: [
@@ -82,3 +83,20 @@
         "-include common/all-versions/VersionMacro.h",
     ]
 }
+
+cc_test {
+    name: "VtsHalAudioV6_0TargetTest",
+    defaults: ["VtsHalAudioTargetTest_defaults"],
+    srcs: [
+        "6.0/AudioPrimaryHidlHalTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.audio@6.0",
+        "android.hardware.audio.common@6.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 7f8b6a0..d0d39e8 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -23,7 +23,10 @@
 #include <initializer_list>
 #include <limits>
 #include <list>
+#include <map>
+#include <set>
 #include <string>
+#include <variant>
 #include <vector>
 
 #include <fcntl.h>
@@ -31,7 +34,9 @@
 
 #include <hwbinder/IPCThreadState.h>
 
+#if MAJOR_VERSION <= 5
 #include <VtsHalHidlTargetTestBase.h>
+#endif
 
 #include <android-base/logging.h>
 
@@ -44,16 +49,24 @@
 #include <Serializer.h>
 #include <fmq/EventFlag.h>
 #include <fmq/MessageQueue.h>
+#if MAJOR_VERSION >= 6
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#endif
 
 #include <common/all-versions/VersionUtils.h>
 
 #include "utility/AssertOk.h"
 #include "utility/Documentation.h"
-#include "utility/EnvironmentTearDown.h"
-#include "utility/PrettyPrintAudioTypes.h"
 #include "utility/ReturnIn.h"
 #include "utility/ValidateXml.h"
 
+#if MAJOR_VERSION <= 5
+#include "2.0/EnvironmentTearDown.h"
+#elif MAJOR_VERSION >= 6
+#include "6.0/EnvironmentTearDown.h"
+#endif
+
 /** Provide version specific functions that are used in the generic tests */
 #if MAJOR_VERSION == 2
 #include "2.0/AudioPrimaryHidlHalUtils.h"
@@ -84,7 +97,9 @@
 using ::android::hardware::MessageQueue;
 using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::Return;
+using ::android::hardware::audio::common::utils::EnumBitfield;
 using ::android::hardware::audio::common::utils::mkEnumBitfield;
+using ::android::hardware::details::toHexString;
 
 using namespace ::android::hardware::audio::common::CPP_VERSION;
 using namespace ::android::hardware::audio::common::test::utility;
@@ -105,14 +120,43 @@
 
 class AudioHidlTestEnvironment : public ::Environment {
    public:
-    virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+#if MAJOR_VERSION <= 5
+     void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+#endif
 };
 
 // Instance to register global tearDown
 static AudioHidlTestEnvironment* environment;
 
-class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+#define AUDIO_PRIMARY_HIDL_HAL_TEST
+#include "DeviceManager.h"
+
+#if MAJOR_VERSION <= 5
+using HidlTestBase = ::testing::VtsHalHidlTargetTestBase;
+#elif MAJOR_VERSION >= 6
+using HidlTestBase = ::testing::Test;
+#endif
+
+class HidlTest : public HidlTestBase {
+  public:
+    virtual ~HidlTest() = default;
+
+  protected:
+    // Factory and device name getters to be overridden in subclasses.
+    virtual const std::string& getFactoryName() const = 0;
+    virtual const std::string& getDeviceName() const = 0;
+
+    sp<IDevicesFactory> getDevicesFactory() const {
+        return DevicesFactoryManager::getInstance().get(getFactoryName());
+    }
+    sp<IDevice> getDevice() const {
+        return DeviceManager::getInstance().get(getFactoryName(), getDeviceName());
+    }
+    bool resetDevice() const {
+        return DeviceManager::getInstance().reset(getFactoryName(), getDeviceName());
+    }
+    bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); }
+
     // Convenient member to store results
     Result res;
 };
@@ -158,7 +202,25 @@
         }
         mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this);
         if (mStatus == OK) {
-            mPrimaryModule = getHwModules().getModuleFromName("primary");
+            mPrimaryModule = getHwModules().getModuleFromName(DeviceManager::kPrimaryDevice);
+            // Available devices are not 'attached' to modules at this moment.
+            // Need to go over available devices and find their module.
+            for (const auto& device : availableOutputDevices) {
+                for (const auto& module : hwModules) {
+                    if (module->getDeclaredDevices().indexOf(device) >= 0) {
+                        mModulesWithDevicesNames.insert(module->getName());
+                        break;
+                    }
+                }
+            }
+            for (const auto& device : availableInputDevices) {
+                for (const auto& module : hwModules) {
+                    if (module->getDeclaredDevices().indexOf(device) >= 0) {
+                        mModulesWithDevicesNames.insert(module->getName());
+                        break;
+                    }
+                }
+            }
         }
     }
     status_t getStatus() const { return mStatus; }
@@ -171,12 +233,19 @@
         }
     }
     const std::string& getFilePath() const { return mFilePath; }
+    sp<const HwModule> getModuleFromName(const std::string& name) const {
+        return getHwModules().getModuleFromName(name.c_str());
+    }
     sp<const HwModule> getPrimaryModule() const { return mPrimaryModule; }
+    const std::set<std::string>& getModulesWithDevicesNames() const {
+        return mModulesWithDevicesNames;
+    }
 
    private:
     status_t mStatus = NO_INIT;
     std::string mFilePath;
     sp<HwModule> mPrimaryModule = nullptr;
+    std::set<std::string> mModulesWithDevicesNames;
 };
 
 // Cached policy config after parsing for faster test startup
@@ -189,54 +258,113 @@
     return *policyConfig;
 }
 
-class AudioPolicyConfigTest : public HidlTest {
-   public:
+class AudioPolicyConfigTest : public HidlTestBase {
+  public:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp());  // setup base
-
+        ASSERT_NO_FATAL_FAILURE(HidlTestBase::SetUp());  // setup base
         auto& policyConfig = getCachedPolicyConfig();
         ASSERT_EQ(0, policyConfig.getStatus()) << policyConfig.getError();
-
-        mPrimaryConfig = policyConfig.getPrimaryModule();
-        ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: "
-                                    << policyConfig.getFilePath();
     }
-    sp<const HwModule> mPrimaryConfig = nullptr;
 };
 
 TEST_F(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) {
     doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)");
 }
 
+TEST_F(AudioPolicyConfigTest, HasPrimaryModule) {
+    auto& policyConfig = getCachedPolicyConfig();
+    ASSERT_TRUE(policyConfig.getPrimaryModule() != nullptr)
+            << "Could not find primary module in configuration file: "
+            << policyConfig.getFilePath();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////// Test parameter types and definitions ////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+enum { PARAM_FACTORY_NAME, PARAM_DEVICE_NAME };
+using DeviceParameter = std::tuple<std::string, std::string>;
+
+static inline std::string DeviceParameterToString(
+        const ::testing::TestParamInfo<DeviceParameter>& info) {
+    const auto& deviceName = std::get<PARAM_DEVICE_NAME>(info.param);
+#if MAJOR_VERSION <= 5
+    return !deviceName.empty() ? deviceName : std::to_string(info.index);
+#elif MAJOR_VERSION >= 6
+    const auto factoryName =
+            ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo<std::string>{
+                    std::get<PARAM_FACTORY_NAME>(info.param), info.index});
+    return !deviceName.empty() ? factoryName + "_" + deviceName : factoryName;
+#endif
+}
+
+#if MAJOR_VERSION <= 5
+// For V2..5 the factory is looked up using the instance name passed
+// in the environment, only one factory is returned. This is because the VTS
+// framework will call the test for each instance. Only the primary device of
+// the default service factory can be tested.
+
+// Return a pair of <"default", "primary"> or <[non-default name], "">
+// This is used to parametrize device factory tests.
+// The device name is used to indicate whether IPrimaryDevice is required.
+const std::vector<DeviceParameter>& getDeviceParametersForFactoryTests() {
+    static std::vector<DeviceParameter> parameters = {
+            {environment->getServiceName<IDevicesFactory>(),
+             environment->getServiceName<IDevicesFactory>() == kDefaultServiceName
+                     ? DeviceManager::kPrimaryDevice
+                     : ""}};
+    return parameters;
+}
+// Return a pair of <"default", "primary"> or nothing.
+// This is used to parametrize primary device tests.
+const std::vector<DeviceParameter>& getDeviceParametersForPrimaryDeviceTests() {
+    static std::vector<DeviceParameter> parameters =
+            !std::get<PARAM_DEVICE_NAME>(*getDeviceParametersForFactoryTests().begin()).empty()
+                    ? getDeviceParametersForFactoryTests()
+                    : std::vector<DeviceParameter>{};
+    return parameters;
+}
+// In V2..5 device tests must only test the primary device.
+// No device tests are executed for non-primary devices.
+const std::vector<DeviceParameter>& getDeviceParameters() {
+    return getDeviceParametersForPrimaryDeviceTests();
+}
+#elif MAJOR_VERSION >= 6
+// For V6 and above these functions are implemented in 6.0/AudioPrimaryHidlHalTest.cpp
+const std::vector<DeviceParameter>& getDeviceParametersForFactoryTests();
+const std::vector<DeviceParameter>& getDeviceParametersForPrimaryDeviceTests();
+const std::vector<DeviceParameter>& getDeviceParameters();
+#endif
+
+class AudioHidlTestWithDeviceParameter : public HidlTest,
+                                         public ::testing::WithParamInterface<DeviceParameter> {
+  protected:
+    const std::string& getFactoryName() const override {
+        return std::get<PARAM_FACTORY_NAME>(GetParam());
+    }
+    const std::string& getDeviceName() const override {
+        return std::get<PARAM_DEVICE_NAME>(GetParam());
+    }
+};
+
 //////////////////////////////////////////////////////////////////////////////
 ////////////////////// getService audio_devices_factory //////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-// Test all audio devices
-class AudioHidlTest : public AudioPolicyConfigTest {
-   public:
+// Test audio devices factory
+class AudioHidlTest : public AudioHidlTestWithDeviceParameter {
+  public:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp());  // setup base
-
-        if (devicesFactory == nullptr) {
-            environment->registerTearDown([] { devicesFactory.clear(); });
-            devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(
-                environment->getServiceName<IDevicesFactory>("default"));
-        }
-        ASSERT_TRUE(devicesFactory != nullptr);
+        ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceParameter::SetUp());  // setup base
+        ASSERT_TRUE(getDevicesFactory() != nullptr);
     }
-
-   protected:
-    // Cache the devicesFactory retrieval to speed up each test by ~0.5s
-    static sp<IDevicesFactory> devicesFactory;
 };
-sp<IDevicesFactory> AudioHidlTest::devicesFactory;
 
-TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
-    doc::test("Test the getService (called in SetUp)");
+TEST_P(AudioHidlTest, GetAudioDevicesFactoryService) {
+    doc::test("Test the getService");
 }
 
-TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
+TEST_P(AudioHidlTest, OpenDeviceInvalidParameter) {
     doc::test("Test passing an invalid parameter to openDevice");
     Result result;
     sp<IDevice> device;
@@ -245,74 +373,80 @@
 #elif MAJOR_VERSION >= 4
     auto invalidDevice = "Non existing device";
 #endif
-    ASSERT_OK(devicesFactory->openDevice(invalidDevice, returnIn(result, device)));
+    ASSERT_OK(getDevicesFactory()->openDevice(invalidDevice, returnIn(result, device)));
     ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
     ASSERT_TRUE(device == nullptr);
 }
 
+INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest,
+                        ::testing::ValuesIn(getDeviceParametersForFactoryTests()),
+                        &DeviceParameterToString);
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// openDevice ///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Test all audio devices
+class AudioHidlDeviceTest : public AudioHidlTest {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp());  // setup base
+        ASSERT_TRUE(getDevice() != nullptr);
+    }
+};
+
+TEST_P(AudioHidlDeviceTest, OpenDevice) {
+    doc::test("Test openDevice (called during setup)");
+}
+
+TEST_P(AudioHidlDeviceTest, Init) {
+    doc::test("Test that the audio hal initialized correctly");
+    ASSERT_OK(getDevice()->initCheck());
+}
+
+INSTANTIATE_TEST_CASE_P(AudioHidlDevice, AudioHidlDeviceTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////////////// openDevice primary ///////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
 // Test the primary device
-class AudioPrimaryHidlTest : public AudioHidlTest {
-   public:
-    /** Primary HAL test are NOT thread safe. */
+class AudioPrimaryHidlTest : public AudioHidlDeviceTest {
+  public:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp());  // setup base
-
-        if (device == nullptr) {
-            initPrimaryDevice();
-            ASSERT_TRUE(device != nullptr);
-            environment->registerTearDown([] { device.clear(); });
-        }
+        ASSERT_NO_FATAL_FAILURE(AudioHidlDeviceTest::SetUp());  // setup base
+        ASSERT_TRUE(getDevice() != nullptr);
     }
 
-   protected:
-    // Cache the device opening to speed up each test by ~0.5s
-    static sp<IPrimaryDevice> device;
-
-   private:
-    void initPrimaryDevice() {
-        Result result;
-#if MAJOR_VERSION == 2
-        sp<IDevice> baseDevice;
-        ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
-                                             returnIn(result, baseDevice)));
-        ASSERT_OK(result);
-        ASSERT_TRUE(baseDevice != nullptr);
-
-        device = IPrimaryDevice::castFrom(baseDevice);
-#elif MAJOR_VERSION >= 4
-        ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device)));
-        ASSERT_OK(result);
-#endif
+  protected:
+    sp<IPrimaryDevice> getDevice() const {
+        return DeviceManager::getInstance().getPrimary(getFactoryName());
     }
 };
-sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
 
-TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
-    doc::test("Test the openDevice (called in SetUp)");
+TEST_P(AudioPrimaryHidlTest, OpenPrimaryDevice) {
+    doc::test("Test openPrimaryDevice (called during setup)");
 }
 
-TEST_F(AudioPrimaryHidlTest, Init) {
-    doc::test("Test that the audio primary hal initialized correctly");
-    ASSERT_OK(device->initCheck());
-}
+INSTANTIATE_TEST_CASE_P(AudioPrimaryHidl, AudioPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                        &DeviceParameterToString);
 
 //////////////////////////////////////////////////////////////////////////////
 ///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-template <class Property>
-class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
-   protected:
+template <class Property, class BaseTestClass = AudioHidlDeviceTest>
+class AccessorHidlTest : public BaseTestClass {
+  protected:
     enum Optionality { REQUIRED, OPTIONAL };
     struct Initial {  // Initial property value
         Initial(Property value, Optionality check = REQUIRED) : value(value), check(check) {}
         Property value;
         Optionality check;  // If this initial value should be checked
     };
+    using BaseTestClass::res;
     /** Test a property getter and setter.
      *  The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL.
      */
@@ -324,7 +458,7 @@
                                       optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
 
         Property initialValue = expectedInitial.value;
-        ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+        ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, initialValue)));
         ASSERT_RESULT(expectedResults, res);
         if (res == Result::OK && expectedInitial.check == REQUIRED) {
             EXPECT_EQ(expectedInitial.value, initialValue);
@@ -335,7 +469,7 @@
         for (Property setValue : valuesToTest) {
             SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
                          testing::PrintToString(setValue));
-            auto ret = (device.get()->*setter)(setValue);
+            auto ret = (BaseTestClass::getDevice().get()->*setter)(setValue);
             ASSERT_RESULT(expectedResults, ret);
             if (ret == Result::NOT_SUPPORTED) {
                 doc::partialTest(propertyName + " setter is not supported");
@@ -343,7 +477,7 @@
             }
             Property getValue;
             // Make sure the getter returns the same value just set
-            ASSERT_OK((device.get()->*getter)(returnIn(res, getValue)));
+            ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, getValue)));
             ASSERT_RESULT(expectedResults, res);
             if (res == Result::NOT_SUPPORTED) {
                 doc::partialTest(propertyName + " getter is not supported");
@@ -355,31 +489,40 @@
         for (Property invalidValue : invalidValues) {
             SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
                          testing::PrintToString(invalidValue));
-            EXPECT_RESULT(invalidArgsOrNotSupported, (device.get()->*setter)(invalidValue));
+            EXPECT_RESULT(invalidArgsOrNotSupported,
+                          (BaseTestClass::getDevice().get()->*setter)(invalidValue));
         }
 
         // Restore initial value
-        EXPECT_RESULT(expectedResults, (device.get()->*setter)(initialValue));
+        EXPECT_RESULT(expectedResults, (BaseTestClass::getDevice().get()->*setter)(initialValue));
     }
 };
 
-using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>;
+using BoolAccessorHidlTest = AccessorHidlTest<bool>;
+using BoolAccessorPrimaryHidlTest = AccessorHidlTest<bool, AudioPrimaryHidlTest>;
 
-TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
+TEST_P(BoolAccessorHidlTest, MicMuteTest) {
     doc::test("Check that the mic can be muted and unmuted");
-    testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute);
+    testAccessors<OPTIONAL>("mic mute", Initial{false}, {true}, &IDevice::setMicMute,
+                            &IDevice::getMicMute);
     // TODO: check that the mic is really muted (all sample are 0)
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
+TEST_P(BoolAccessorHidlTest, MasterMuteTest) {
     doc::test("If master mute is supported, try to mute and unmute the master output");
     testAccessors<OPTIONAL>("master mute", Initial{false}, {true}, &IDevice::setMasterMute,
                             &IDevice::getMasterMute);
     // TODO: check that the master volume is really muted
 }
 
-using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
-TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
+INSTANTIATE_TEST_CASE_P(BoolAccessorHidl, BoolAccessorHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                        &DeviceParameterToString);
+
+using FloatAccessorHidlTest = AccessorHidlTest<float>;
+TEST_P(FloatAccessorHidlTest, MasterVolumeTest) {
     doc::test("Test the master volume if supported");
     testAccessors<OPTIONAL>(
         "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume,
@@ -387,125 +530,135 @@
     // TODO: check that the master volume is really changed
 }
 
+INSTANTIATE_TEST_CASE_P(FloatAccessorHidl, FloatAccessorHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////// AudioPatches ////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
-   protected:
-    bool areAudioPatchesSupported() {
-        auto result = device->supportsAudioPatches();
-        EXPECT_IS_OK(result);
-        return result;
+class AudioPatchHidlTest : public AudioHidlDeviceTest {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioHidlDeviceTest::SetUp());  // setup base
+        if (!areAudioPatchesSupported()) {
+            GTEST_SKIP() << "Audio patches are not supported";
+        }
     }
 };
 
-TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
+TEST_P(AudioPatchHidlTest, AudioPatches) {
     doc::test("Test if audio patches are supported");
-    if (!areAudioPatchesSupported()) {
-        doc::partialTest("Audio patches are not supported");
-        return;
-    }
     // TODO: test audio patches
 }
 
-//////////////////////////////////////////////////////////////////////////////
-//////////////// Required and recommended audio format support ///////////////
-// From:
-// https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording
-// From:
-// https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback
-/////////// TODO: move to the beginning of the file for easier update ////////
-//////////////////////////////////////////////////////////////////////////////
+INSTANTIATE_TEST_CASE_P(AudioPatchHidl, AudioPatchHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
 
-class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
-   public:
-    // for retro compatibility only test the primary device IN_BUILTIN_MIC
-    // FIXME: in the next audio HAL version, test all available devices
-    static bool primaryHasMic() {
-        auto& policyConfig = getCachedPolicyConfig();
-        if (policyConfig.getStatus() != OK || policyConfig.getPrimaryModule() == nullptr) {
-            return true;  // Could not get the information, run all tests
-        }
-        auto getMic = [](auto& devs) { return devs.getDevice(
-                AUDIO_DEVICE_IN_BUILTIN_MIC, {}, AUDIO_FORMAT_DEFAULT); };
-        auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices());
-        auto availableMic = getMic(policyConfig.getAvailableInputDevices());
+// Nesting a tuple in another tuple allows to use GTest Combine function to generate
+// all combinations of devices and configs.
+enum { PARAM_DEVICE, PARAM_CONFIG, PARAM_FLAGS };
+enum { INDEX_INPUT, INDEX_OUTPUT };
+using DeviceConfigParameter =
+        std::tuple<DeviceParameter, AudioConfig, std::variant<AudioInputFlag, AudioOutputFlag>>;
 
-        return primaryMic != nullptr && primaryMic->equals(availableMic);
-    }
+#if MAJOR_VERSION >= 6
+const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters();
+const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters();
+#endif
 
-    // Cache result ?
-    static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
-        return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
-                                  {8000, 11025, 16000, 22050, 32000, 44100},
-                                  {AudioFormat::PCM_16_BIT});
+#if MAJOR_VERSION >= 4
+static string SanitizeStringForGTestName(const string& s) {
+    string result = s;
+    for (size_t i = 0; i < result.size(); i++) {
+        // gtest test names must only contain alphanumeric characters
+        if (!std::isalnum(result[i])) result[i] = '_';
     }
-
-    static const vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() {
-        return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
-                                  {24000, 48000}, {AudioFormat::PCM_16_BIT});
-    }
-
-    static const vector<AudioConfig> getSupportedPlaybackAudioConfig() {
-        // TODO: retrieve audio config supported by the platform
-        // as declared in the policy configuration
-        return {};
-    }
-
-    static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
-        if (!primaryHasMic()) return {};
-        return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100},
-                                  {AudioFormat::PCM_16_BIT});
-    }
-    static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
-        if (!primaryHasMic()) return {};
-        return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000},
-                                  {AudioFormat::PCM_16_BIT});
-    }
-    static const vector<AudioConfig> getSupportedCaptureAudioConfig() {
-        // TODO: retrieve audio config supported by the platform
-        // as declared in the policy configuration
-        return {};
-    }
-
-   private:
-    static const vector<AudioConfig> combineAudioConfig(vector<AudioChannelMask> channelMasks,
-                                                        vector<uint32_t> sampleRates,
-                                                        vector<AudioFormat> formats) {
-        vector<AudioConfig> configs;
-        for (auto channelMask : channelMasks) {
-            for (auto sampleRate : sampleRates) {
-                for (auto format : formats) {
-                    AudioConfig config{};
-                    // leave offloadInfo to 0
-                    config.channelMask = mkEnumBitfield(channelMask);
-                    config.sampleRateHz = sampleRate;
-                    config.format = format;
-                    // FIXME: leave frameCount to 0 ?
-                    configs.push_back(config);
-                }
-            }
-        }
-        return configs;
-    }
-};
+    return result;
+}
+#endif
 
 /** Generate a test name based on an audio config.
  *
  * As the only parameter changing are channel mask and sample rate,
  * only print those ones in the test name.
  */
-static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) {
-    const AudioConfig& config = info.param;
-    return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" +
+static string DeviceConfigParameterToString(
+        const testing::TestParamInfo<DeviceConfigParameter>& info) {
+    const AudioConfig& config = std::get<PARAM_CONFIG>(info.param);
+    const auto deviceName = DeviceParameterToString(::testing::TestParamInfo<DeviceParameter>{
+            std::get<PARAM_DEVICE>(info.param), info.index});
+    return (deviceName.empty() ? "" : deviceName + "_") + to_string(info.index) + "__" +
+           to_string(config.sampleRateHz) + "_" +
            // "MONO" is more clear than "FRONT_LEFT"
            ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
              config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO))
-                ? "MONO"
-                : ::testing::PrintToString(config.channelMask));
+                    ? "MONO"
+#if MAJOR_VERSION == 2
+                    : ::testing::PrintToString(config.channelMask)
+#elif MAJOR_VERSION >= 4
+                    // In V4 and above the channel mask is a bitfield.
+                    // Printing its value using HIDL's toString for a bitfield emits a lot of extra
+                    // text due to overlapping constant values. Instead, we print the bitfield value
+                    // as if it was a single value + its hex representation
+                    : SanitizeStringForGTestName(
+                              ::testing::PrintToString(AudioChannelMask(config.channelMask)) + "_" +
+                              toHexString(config.channelMask))
+#endif
+                    ) +
+           "_" +
+#if MAJOR_VERSION == 2
+           std::visit([](auto&& arg) -> std::string { return ::testing::PrintToString(arg); },
+                      std::get<PARAM_FLAGS>(info.param));
+#elif MAJOR_VERSION >= 4
+           SanitizeStringForGTestName(std::visit(
+                   [](auto&& arg) -> std::string {
+                       using T = std::decay_t<decltype(arg)>;
+                       // Need to use FQN of toString to avoid confusing the compiler
+                       return ::android::hardware::audio::common::CPP_VERSION::toString<T>(
+                               hidl_bitfield<T>(arg));
+                   },
+                   std::get<PARAM_FLAGS>(info.param)));
+#endif
 }
 
+class AudioHidlTestWithDeviceConfigParameter
+    : public HidlTest,
+      public ::testing::WithParamInterface<DeviceConfigParameter> {
+  protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp());  // setup base
+        ASSERT_TRUE(getDevicesFactory() != nullptr);
+        ASSERT_TRUE(getDevice() != nullptr);
+    }
+    const std::string& getFactoryName() const override {
+        return std::get<PARAM_FACTORY_NAME>(std::get<PARAM_DEVICE>(GetParam()));
+    }
+    const std::string& getDeviceName() const override {
+        return std::get<PARAM_DEVICE_NAME>(std::get<PARAM_DEVICE>(GetParam()));
+    }
+    const AudioConfig& getConfig() const { return std::get<PARAM_CONFIG>(GetParam()); }
+#if MAJOR_VERSION == 2
+    AudioInputFlag getInputFlags() const {
+        return std::get<INDEX_INPUT>(std::get<PARAM_FLAGS>(GetParam()));
+    }
+    AudioOutputFlag getOutputFlags() const {
+        return std::get<INDEX_OUTPUT>(std::get<PARAM_FLAGS>(GetParam()));
+    }
+#elif MAJOR_VERSION >= 4
+    hidl_bitfield<AudioInputFlag> getInputFlags() const {
+        return hidl_bitfield<AudioInputFlag>(
+                std::get<INDEX_INPUT>(std::get<PARAM_FLAGS>(GetParam())));
+    }
+    hidl_bitfield<AudioOutputFlag> getOutputFlags() const {
+        return hidl_bitfield<AudioOutputFlag>(
+                std::get<INDEX_OUTPUT>(std::get<PARAM_FLAGS>(GetParam())));
+    }
+#endif
+};
+
+#include "ConfigHelper.h"
+
 //////////////////////////////////////////////////////////////////////////////
 ///////////////////////////// getInputBufferSize /////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
@@ -514,12 +667,11 @@
 // android.hardware.microphone
 //        how to get this value ? is it a property ???
 
-class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest,
-                                      public ::testing::WithParamInterface<AudioConfig> {
-   protected:
+class AudioCaptureConfigTest : public AudioHidlTestWithDeviceConfigParameter {
+  protected:
     void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
         uint64_t bufferSize;
-        ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
+        ASSERT_OK(getDevice()->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
 
         switch (res) {
             case Result::INVALID_ARGUMENTS:
@@ -538,44 +690,54 @@
 
 // Test that the required capture config and those declared in the policy are
 // indeed supported
-class RequiredInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
+class RequiredInputBufferSizeTest : public AudioCaptureConfigTest {};
 TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) {
     doc::test(
         "Input buffer size must be retrievable for a format with required "
         "support.");
-    inputBufferSizeTest(GetParam(), true);
+    inputBufferSizeTest(getConfig(), true);
 }
-INSTANTIATE_TEST_CASE_P(
-    RequiredInputBufferSize, RequiredInputBufferSizeTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
-    &generateTestName);
-INSTANTIATE_TEST_CASE_P(
-    SupportedInputBufferSize, RequiredInputBufferSizeTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
-    &generateTestName);
 
 // Test that the recommended capture config are supported or lead to a
 // INVALID_ARGUMENTS return
-class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
+class OptionalInputBufferSizeTest : public AudioCaptureConfigTest {};
 TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) {
     doc::test(
-        "Input buffer size should be retrievable for a format with recommended "
-        "support.");
-    inputBufferSizeTest(GetParam(), false);
+            "Input buffer size should be retrievable for a format with recommended "
+            "support.");
+    inputBufferSizeTest(getConfig(), false);
 }
+
+#if MAJOR_VERSION <= 5
+// For V2..5 test the primary device according to CDD requirements.
 INSTANTIATE_TEST_CASE_P(
-    RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
-    &generateTestName);
+        RequiredInputBufferSize, RequiredInputBufferSizeTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig()),
+                ::testing::Values(AudioInputFlag::NONE)),
+        &DeviceConfigParameterToString);
+INSTANTIATE_TEST_CASE_P(
+        RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig()),
+                ::testing::Values(AudioInputFlag::NONE)),
+        &DeviceConfigParameterToString);
+#elif MAJOR_VERSION >= 6
+INSTANTIATE_TEST_CASE_P(SupportedInputBufferSize, RequiredInputBufferSizeTest,
+                        ::testing::ValuesIn(getInputDeviceConfigParameters()),
+                        &DeviceConfigParameterToString);
+#endif
 
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////////////// setScreenState ///////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, setScreenState) {
+TEST_P(AudioHidlDeviceTest, setScreenState) {
     doc::test("Check that the hal can receive the screen state");
     for (bool turnedOn : {false, true, true, false, false}) {
-        ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn));
+        ASSERT_RESULT(okOrNotSupported, getDevice()->setScreenState(turnedOn));
     }
 }
 
@@ -583,15 +745,16 @@
 //////////////////////////// {get,set}Parameters /////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, getParameters) {
+TEST_P(AudioHidlDeviceTest, getParameters) {
     doc::test("Check that the hal can set and get parameters");
     hidl_vec<ParameterValue> context;
     hidl_vec<hidl_string> keys;
     hidl_vec<ParameterValue> values;
-    ASSERT_OK(Parameters::get(device, keys, returnIn(res, values)));
-    ASSERT_OK(Parameters::set(device, values));
+    ASSERT_OK(Parameters::get(getDevice(), keys, returnIn(res, values)));
+    ASSERT_RESULT(okOrNotSupported, res);
+    ASSERT_RESULT(okOrNotSupported, Parameters::set(getDevice(), values));
     values.resize(0);
-    ASSERT_OK(Parameters::set(device, values));
+    ASSERT_RESULT(okOrNotSupported, Parameters::set(getDevice(), values));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -632,93 +795,132 @@
     EXPECT_EQ(0, close(fds[1])) << errno;
 }
 
-TEST_F(AudioPrimaryHidlTest, DebugDump) {
+TEST_P(AudioHidlDeviceTest, DebugDump) {
     doc::test("Check that the hal can dump its state without error");
-    testDebugDump([](const auto& handle) { return dump(device, handle); });
+    testDebugDump([this](const auto& handle) { return dump(getDevice(), handle); });
 }
 
-TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
+TEST_P(AudioHidlDeviceTest, DebugDumpInvalidArguments) {
     doc::test("Check that the hal dump doesn't crash on invalid arguments");
-    ASSERT_OK(dump(device, hidl_handle()));
+    ASSERT_OK(dump(getDevice(), hidl_handle()));
 }
 
 //////////////////////////////////////////////////////////////////////////////
 ////////////////////////// open{Output,Input}Stream //////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
+// This class is also used by some device tests.
 template <class Stream>
-class OpenStreamTest : public AudioConfigPrimaryTest,
-                       public ::testing::WithParamInterface<AudioConfig> {
-   protected:
+class StreamHelper {
+  public:
+    // StreamHelper doesn't own the stream, this is for simpler stream lifetime management.
+    explicit StreamHelper(sp<Stream>& stream) : mStream(stream) {}
     template <class Open>
-    void testOpen(Open openStream, const AudioConfig& config) {
+    void open(Open openStream, const AudioConfig& config, Result* res,
+              AudioConfig* suggestedConfigPtr) {
         // FIXME: Open a stream without an IOHandle
         //        This is not required to be accepted by hal implementations
         AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
         AudioConfig suggestedConfig{};
-        ASSERT_OK(openStream(ioHandle, config, returnIn(res, stream, suggestedConfig)));
-
-        // TODO: only allow failure for RecommendedPlaybackAudioConfig
-        switch (res) {
+        bool retryWithSuggestedConfig = true;
+        if (suggestedConfigPtr == nullptr) {
+            suggestedConfigPtr = &suggestedConfig;
+            retryWithSuggestedConfig = false;
+        }
+        ASSERT_OK(openStream(ioHandle, config, returnIn(*res, mStream, *suggestedConfigPtr)));
+        switch (*res) {
             case Result::OK:
-                ASSERT_TRUE(stream != nullptr);
-                audioConfig = config;
+                ASSERT_TRUE(mStream != nullptr);
+                *suggestedConfigPtr = config;
                 break;
             case Result::INVALID_ARGUMENTS:
-                ASSERT_TRUE(stream == nullptr);
-                AudioConfig suggestedConfigRetry;
-                // Could not open stream with config, try again with the
-                // suggested one
-                ASSERT_OK(openStream(ioHandle, suggestedConfig,
-                                     returnIn(res, stream, suggestedConfigRetry)));
-                // This time it must succeed
-                ASSERT_OK(res);
-                ASSERT_TRUE(stream != nullptr);
-                audioConfig = suggestedConfig;
+                ASSERT_TRUE(mStream == nullptr);
+                if (retryWithSuggestedConfig) {
+                    AudioConfig suggestedConfigRetry;
+                    ASSERT_OK(openStream(ioHandle, *suggestedConfigPtr,
+                                         returnIn(*res, mStream, suggestedConfigRetry)));
+                    ASSERT_OK(*res);
+                    ASSERT_TRUE(mStream != nullptr);
+                }
                 break;
             default:
-                FAIL() << "Invalid return status: " << ::testing::PrintToString(res);
+                FAIL() << "Invalid return status: " << ::testing::PrintToString(*res);
         }
+    }
+    void close(bool clear, Result* res) {
+        auto ret = mStream->close();
+        EXPECT_TRUE(ret.isOk());
+        *res = ret;
+        if (clear) {
+            mStream.clear();
+#if MAJOR_VERSION <= 5
+            // 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);
+#endif
+        }
+    }
+
+  private:
+    sp<Stream>& mStream;
+};
+
+template <class Stream>
+class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
+  protected:
+    OpenStreamTest() : AudioHidlTestWithDeviceConfigParameter(), helper(stream) {}
+    template <class Open>
+    void testOpen(Open openStream, const AudioConfig& config) {
+        // TODO: only allow failure for RecommendedPlaybackAudioConfig
+        ASSERT_NO_FATAL_FAILURE(helper.open(openStream, config, &res, &audioConfig));
         open = true;
     }
 
-    Return<Result> closeStream() {
+    Result closeStream(bool clear = true) {
         open = false;
-        return stream->close();
+        helper.close(clear, &res);
+        return res;
     }
 
-   private:
+  private:
     void TearDown() override {
         if (open) {
-            ASSERT_OK(stream->close());
+            ASSERT_OK(closeStream());
         }
+        AudioHidlTestWithDeviceConfigParameter::TearDown();
     }
 
    protected:
     AudioConfig audioConfig;
     DeviceAddress address = {};
     sp<Stream> stream;
+    StreamHelper<Stream> helper;
     bool open = false;
 };
 
 ////////////////////////////// openOutputStream //////////////////////////////
 
 class OutputStreamTest : public OpenStreamTest<IStreamOut> {
-    virtual void SetUp() override {
+    void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
         address.device = AudioDevice::OUT_DEFAULT;
-        const AudioConfig& config = GetParam();
-        // TODO: test all flag combination
-        auto flags = mkEnumBitfield(AudioOutputFlag::NONE);
+        const AudioConfig& config = getConfig();
+        auto flags = getOutputFlags();
         testOpen(
-            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                [&](AudioIoHandle handle, AudioConfig config, auto cb) {
 #if MAJOR_VERSION == 2
-                return device->openOutputStream(handle, address, config, flags, cb);
+                    return getDevice()->openOutputStream(handle, address, config, flags, cb);
 #elif MAJOR_VERSION >= 4
-                return device->openOutputStream(handle, address, config, flags, initMetadata, cb);
+                    return getDevice()->openOutputStream(handle, address, config, flags,
+                                                         initMetadata, cb);
 #endif
-            },
-            config);
+                },
+                config);
     }
 #if MAJOR_VERSION >= 4
 
@@ -735,34 +937,46 @@
         "recommended config");
     // Open done in SetUp
 }
-INSTANTIATE_TEST_CASE_P(
-    RequiredOutputStreamConfigSupport, OutputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
-    &generateTestName);
-INSTANTIATE_TEST_CASE_P(
-    SupportedOutputStreamConfig, OutputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
-    &generateTestName);
 
+#if MAJOR_VERSION <= 5
+// For V2..5 test the primary device according to CDD requirements.
 INSTANTIATE_TEST_CASE_P(
-    RecommendedOutputStreamConfigSupport, OutputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
-    &generateTestName);
+        RequiredOutputStreamConfigSupport, OutputStreamTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig()),
+                ::testing::Values(AudioOutputFlag::NONE)),
+        &DeviceConfigParameterToString);
+INSTANTIATE_TEST_CASE_P(
+        RecommendedOutputStreamConfigSupport, OutputStreamTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig()),
+                ::testing::Values(AudioOutputFlag::NONE)),
+        &DeviceConfigParameterToString);
+#elif MAJOR_VERSION >= 6
+// For V6 and above test according to the audio policy manager configuration.
+// This is more correct as CDD is written from the apps perspective.
+// Audio system provides necessary format conversions for missing configurations.
+INSTANTIATE_TEST_CASE_P(DeclaredOutputStreamConfigSupport, OutputStreamTest,
+                        ::testing::ValuesIn(getOutputDeviceConfigParameters()),
+                        &DeviceConfigParameterToString);
+#endif
 
 ////////////////////////////// openInputStream //////////////////////////////
 
 class InputStreamTest : public OpenStreamTest<IStreamIn> {
-    virtual void SetUp() override {
+    void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
         address.device = AudioDevice::IN_DEFAULT;
-        const AudioConfig& config = GetParam();
-        // TODO: test all supported flags and source
-        auto flags = mkEnumBitfield(AudioInputFlag::NONE);
+        const AudioConfig& config = getConfig();
+        auto flags = getInputFlags();
         testOpen(
-            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
-                return device->openInputStream(handle, address, config, flags, initMetadata, cb);
-            },
-            config);
+                [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                    return getDevice()->openInputStream(handle, address, config, flags,
+                                                        initMetadata, cb);
+                },
+                config);
     }
 
    protected:
@@ -779,35 +993,35 @@
         "recommended config");
     // Open done in setup
 }
+#if MAJOR_VERSION <= 5
+// For V2..5 test the primary device according to CDD requirements.
 INSTANTIATE_TEST_CASE_P(
-    RequiredInputStreamConfigSupport, InputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
-    &generateTestName);
+        RequiredInputStreamConfigSupport, InputStreamTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig()),
+                ::testing::Values(AudioInputFlag::NONE)),
+        &DeviceConfigParameterToString);
 INSTANTIATE_TEST_CASE_P(
-    SupportedInputStreamConfig, InputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
-    &generateTestName);
-
-INSTANTIATE_TEST_CASE_P(
-    RecommendedInputStreamConfigSupport, InputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
-    &generateTestName);
+        RecommendedInputStreamConfigSupport, InputStreamTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig()),
+                ::testing::Values(AudioInputFlag::NONE)),
+        &DeviceConfigParameterToString);
+#elif MAJOR_VERSION >= 6
+// For V6 and above test according to the audio policy manager configuration.
+// This is more correct as CDD is written from the apps perspective.
+// Audio system provides necessary format conversions for missing configurations.
+INSTANTIATE_TEST_CASE_P(DeclaredInputStreamConfigSupport, InputStreamTest,
+                        ::testing::ValuesIn(getInputDeviceConfigParameters()),
+                        &DeviceConfigParameterToString);
+#endif
 
 //////////////////////////////////////////////////////////////////////////////
 ////////////////////////////// IStream getters ///////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-/** Unpack the provided result.
- * If the result is not OK, register a failure and return an undefined value. */
-template <class R>
-static R extract(Return<R> ret) {
-    if (!ret.isOk()) {
-        EXPECT_IS_OK(ret);
-        return R{};
-    }
-    return ret;
-}
-
 /* Could not find a way to write a test for two parametrized class fixure
  * thus use this macro do duplicate tests for Input and Output stream */
 #define TEST_IO_STREAM(test_name, documentation, code) \
@@ -985,22 +1199,23 @@
                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",
+        ASSERT_OK(closeStream(false /*clear*/));
+        ASSERT_EQ(Result::INVALID_STATE, closeStream()))
+// clang-format on
 
-static void testCreateTooBigMmapBuffer(IStream* stream) {
-    MmapBufferInfo info;
-    Result res;
-    // Assume that int max is a value too big to be allocated
-    // This is true currently with a 32bit media server, but might not when it
-    // will run in 64 bit
-    auto minSizeFrames = std::numeric_limits<int32_t>::max();
-    ASSERT_OK(stream->createMmapBuffer(minSizeFrames, returnIn(res, info)));
-    ASSERT_RESULT(invalidArgsOrNotSupported, res);
+static void testMmapBufferOfInvalidSize(IStream* stream) {
+    for (int32_t value : {-1, 0, std::numeric_limits<int32_t>::max()}) {
+        MmapBufferInfo info;
+        Result res;
+        EXPECT_OK(stream->createMmapBuffer(value, returnIn(res, info)));
+        EXPECT_RESULT(invalidArgsOrNotSupported, res) << "value=" << value;
+    }
 }
 
-TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer too big should fail",
-               testCreateTooBigMmapBuffer(stream.get()))
+TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer of invalid size must fail",
+               testMmapBufferOfInvalidSize(stream.get()))
 
 static void testGetMmapPositionOfNonMmapedStream(IStream* stream) {
     Result res;
@@ -1151,11 +1366,7 @@
 struct Capability {
     Capability(IStreamOut* stream) {
         EXPECT_OK(stream->supportsPauseAndResume(returnIn(pause, resume)));
-        auto ret = stream->supportsDrain();
-        EXPECT_IS_OK(ret);
-        if (ret.isOk()) {
-            drain = ret;
-        }
+        drain = extract(stream->supportsDrain());
     }
     bool pause = false;
     bool resume = false;
@@ -1167,19 +1378,6 @@
     Capability(stream.get());
 }
 
-template <class Value>
-static void checkInvalidStateOr0(Result res, Value value) {
-    switch (res) {
-        case Result::INVALID_STATE:
-            break;
-        case Result::OK:
-            ASSERT_EQ(0U, value);
-            break;
-        default:
-            FAIL() << "Unexpected result " << toString(res);
-    }
-}
-
 TEST_P(OutputStreamTest, GetRenderPosition) {
     doc::test("A new stream render position should be 0 or INVALID_STATE");
     uint32_t dspFrames;
@@ -1188,7 +1386,7 @@
         doc::partialTest("getRenderPosition is not supported");
         return;
     }
-    checkInvalidStateOr0(res, dspFrames);
+    expectValueOrFailure(res, 0U, dspFrames, Result::INVALID_STATE);
 }
 
 TEST_P(OutputStreamTest, GetNextWriteTimestamp) {
@@ -1199,7 +1397,7 @@
         doc::partialTest("getNextWriteTimestamp is not supported");
         return;
     }
-    checkInvalidStateOr0(res, timestampUs);
+    expectValueOrFailure(res, uint64_t{0}, timestampUs, Result::INVALID_STATE);
 }
 
 /** Stub implementation of out stream callback. */
@@ -1326,35 +1524,39 @@
 /////////////////////////////// PrimaryDevice ////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
+TEST_P(AudioPrimaryHidlTest, setVoiceVolume) {
     doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
-    testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); });
+    testUnitaryGain([this](float volume) { return getDevice()->setVoiceVolume(volume); });
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
     doc::test("Query and set the BT SCO NR&EC state");
     testAccessors<OPTIONAL>("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true},
                             &IPrimaryDevice::setBtScoNrecEnabled,
                             &IPrimaryDevice::getBtScoNrecEnabled);
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
     doc::test("Query and set the SCO whideband state");
     testAccessors<OPTIONAL>("BtScoWideband", Initial{false, OPTIONAL}, {true},
                             &IPrimaryDevice::setBtScoWidebandEnabled,
                             &IPrimaryDevice::getBtScoWidebandEnabled);
 }
 
-using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<IPrimaryDevice::TtyMode>;
-TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
+using TtyModeAccessorPrimaryHidlTest =
+        AccessorHidlTest<IPrimaryDevice::TtyMode, AudioPrimaryHidlTest>;
+TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
     doc::test("Query and set the TTY mode state");
     testAccessors<OPTIONAL>(
         "TTY mode", Initial{IPrimaryDevice::TtyMode::OFF},
         {IPrimaryDevice::TtyMode::HCO, IPrimaryDevice::TtyMode::VCO, IPrimaryDevice::TtyMode::FULL},
         &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
 }
+INSTANTIATE_TEST_CASE_P(TtyModeAccessorPrimaryHidl, TtyModeAccessorPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                        &DeviceParameterToString);
 
-TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) {
     doc::test("Query and set the HAC state");
     testAccessors<OPTIONAL>("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled,
                             &IPrimaryDevice::getHacEnabled);
@@ -1366,9 +1568,13 @@
 
 int main(int argc, char** argv) {
     environment = new AudioHidlTestEnvironment;
+    // For V2..5 it's critical to initialize environment before GTest.
+    // The environment parses the service name from the command line,
+    // then it can be used in GTest parameter generators which are
+    // initialized during the call to InitGoogleTest.
+    environment->init(&argc, argv);
     ::testing::AddGlobalTestEnvironment(environment);
     ::testing::InitGoogleTest(&argc, argv);
-    environment->init(&argc, argv);
     int status = RUN_ALL_TESTS();
     return status;
 }
diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h
new file mode 100644
index 0000000..a2f4116
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/ConfigHelper.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+// Code in this file uses 'getCachedPolicyConfig'
+#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST
+#error Must be included from AudioPrimaryHidlTest.h
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////// Required and recommended audio format support ///////////////
+// From:
+// https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording
+// From:
+// https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback
+/////////// TODO: move to the beginning of the file for easier update ////////
+//////////////////////////////////////////////////////////////////////////////
+
+struct ConfigHelper {
+    // for retro compatibility only test the primary device IN_BUILTIN_MIC
+    // FIXME: in the next audio HAL version, test all available devices
+    static bool primaryHasMic() {
+        auto& policyConfig = getCachedPolicyConfig();
+        if (policyConfig.getStatus() != OK || policyConfig.getPrimaryModule() == nullptr) {
+            return true;  // Could not get the information, run all tests
+        }
+        auto getMic = [](auto& devs) {
+            return devs.getDevice(AUDIO_DEVICE_IN_BUILTIN_MIC, {}, AUDIO_FORMAT_DEFAULT);
+        };
+        auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices());
+        auto availableMic = getMic(policyConfig.getAvailableInputDevices());
+
+        return primaryMic != nullptr && primaryMic->equals(availableMic);
+    }
+
+    // Cache result ?
+    static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
+        return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
+                                  {8000, 11025, 16000, 22050, 32000, 44100},
+                                  {AudioFormat::PCM_16_BIT});
+    }
+
+    static const vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() {
+        return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
+                                  {24000, 48000}, {AudioFormat::PCM_16_BIT});
+    }
+
+    static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
+        if (!primaryHasMic()) return {};
+        return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100},
+                                  {AudioFormat::PCM_16_BIT});
+    }
+    static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
+        if (!primaryHasMic()) return {};
+        return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000},
+                                  {AudioFormat::PCM_16_BIT});
+    }
+
+    static vector<AudioConfig> combineAudioConfig(vector<audio_channel_mask_t> channelMasks,
+                                                  vector<uint32_t> sampleRates,
+                                                  audio_format_t format) {
+        vector<AudioConfig> configs;
+        configs.reserve(channelMasks.size() * sampleRates.size());
+        for (auto channelMask : channelMasks) {
+            for (auto sampleRate : sampleRates) {
+                AudioConfig config{};
+                // leave offloadInfo to 0
+                config.channelMask = EnumBitfield<AudioChannelMask>(channelMask);
+                config.sampleRateHz = sampleRate;
+                config.format = AudioFormat(format);
+                configs.push_back(config);
+            }
+        }
+        return configs;
+    }
+
+    static vector<AudioConfig> combineAudioConfig(vector<AudioChannelMask> channelMasks,
+                                                  vector<uint32_t> sampleRates,
+                                                  vector<AudioFormat> formats) {
+        vector<AudioConfig> configs;
+        configs.reserve(channelMasks.size() * sampleRates.size() * formats.size());
+        for (auto channelMask : channelMasks) {
+            for (auto sampleRate : sampleRates) {
+                for (auto format : formats) {
+                    AudioConfig config{};
+                    // leave offloadInfo to 0
+                    config.channelMask = mkEnumBitfield(channelMask);
+                    config.sampleRateHz = sampleRate;
+                    config.format = format;
+                    // FIXME: leave frameCount to 0 ?
+                    configs.push_back(config);
+                }
+            }
+        }
+        return configs;
+    }
+};
diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h
new file mode 100644
index 0000000..cb6584d
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/DeviceManager.h
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+// Code in this file uses 'environment'
+#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST
+#error Must be included from AudioPrimaryHidlTest.h
+#endif
+
+template <class Derived, class Key, class Interface>
+class InterfaceManager {
+  public:
+    sp<Interface> getExisting(const Key& name) {
+        auto existing = instances.find(name);
+        return existing != instances.end() ? existing->second : sp<Interface>();
+    }
+
+    sp<Interface> get(const Key& name) {
+        auto existing = instances.find(name);
+        if (existing != instances.end()) return existing->second;
+        auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name));
+        if (inserted->second) {
+            environment->registerTearDown(
+                    [name]() { (void)Derived::getInstance().reset(name, false); });
+        }
+        return inserted->second;
+    }
+
+    // The test must check that reset was successful. Reset failure means that the test code
+    // is holding a strong reference to the device.
+    bool reset(const Key& name, bool waitForDestruction) __attribute__((warn_unused_result)) {
+        auto iter = instances.find(name);
+        if (iter == instances.end()) return true;
+        ::android::wp<Interface> weak = iter->second;
+        instances.erase(iter);
+        if (weak.promote() != nullptr) return false;
+        if (waitForDestruction) {
+            waitForInstanceDestruction();
+        }
+        return true;
+    }
+
+    static void waitForInstanceDestruction() {
+        // FIXME: there is no way to know when the remote IDevice 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);
+    }
+
+  protected:
+    std::map<Key, sp<Interface>> instances;
+};
+
+class DevicesFactoryManager
+    : public InterfaceManager<DevicesFactoryManager, std::string, IDevicesFactory> {
+  public:
+    static DevicesFactoryManager& getInstance() {
+        static DevicesFactoryManager instance;
+        return instance;
+    }
+    static sp<IDevicesFactory> createInterfaceInstance(const std::string& name) {
+#if MAJOR_VERSION <= 5
+        return ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(name);
+#elif MAJOR_VERSION >= 6
+        return IDevicesFactory::getService(name);
+#endif
+    }
+};
+
+using FactoryAndDevice = std::tuple<std::string, std::string>;
+class DeviceManager : public InterfaceManager<DeviceManager, FactoryAndDevice, IDevice> {
+  public:
+    static DeviceManager& getInstance() {
+        static DeviceManager instance;
+        return instance;
+    }
+    static sp<IDevice> createInterfaceInstance(const FactoryAndDevice& factoryAndDevice) {
+        auto [factoryName, name] = factoryAndDevice;
+        sp<IDevicesFactory> factory = DevicesFactoryManager::getInstance().get(factoryName);
+        return name == kPrimaryDevice ? openPrimaryDevice(factory) : openDevice(factory, name);
+    }
+    using InterfaceManager::reset;
+
+    static constexpr const char* kPrimaryDevice = "primary";
+
+    sp<IDevice> get(const std::string& factoryName, const std::string& name) {
+        return InterfaceManager::get(std::make_tuple(factoryName, name));
+    }
+    sp<IPrimaryDevice> getPrimary(const std::string& factoryName) {
+        sp<IDevice> device = get(factoryName, kPrimaryDevice);
+        return device != nullptr ? IPrimaryDevice::castFrom(device) : nullptr;
+    }
+    bool reset(const std::string& factoryName, const std::string& name)
+            __attribute__((warn_unused_result)) {
+#if MAJOR_VERSION <= 5
+        return InterfaceManager::reset(std::make_tuple(factoryName, name), true);
+#elif MAJOR_VERSION >= 6
+        {
+            sp<IDevice> device = getExisting(std::make_tuple(factoryName, name));
+            if (device != nullptr) {
+                auto ret = device->close();
+                ALOGE_IF(!ret.isOk(), "Device %s::%s close failed: %s", factoryName.c_str(),
+                         name.c_str(), ret.description().c_str());
+            }
+        }
+        return InterfaceManager::reset(std::make_tuple(factoryName, name), false);
+#endif
+    }
+    bool resetPrimary(const std::string& factoryName) __attribute__((warn_unused_result)) {
+        return reset(factoryName, kPrimaryDevice);
+    }
+
+  private:
+    static sp<IDevice> openDevice(const sp<IDevicesFactory>& factory, const std::string& name) {
+        if (factory == nullptr) return nullptr;
+        sp<IDevice> device;
+#if MAJOR_VERSION >= 4
+        Result result;
+        auto ret = factory->openDevice(name, returnIn(result, device));
+        if (!ret.isOk() || result != Result::OK || device == nullptr) {
+            ALOGW("Device %s can not be opened, transaction: %s, result %d, device %p",
+                  name.c_str(), ret.description().c_str(), result, device.get());
+            return nullptr;
+        }
+#else
+        (void)name;
+#endif
+        return device;
+    }
+
+    static sp<IDevice> openPrimaryDevice(const sp<IDevicesFactory>& factory) {
+        if (factory == nullptr) return nullptr;
+        Result result;
+        sp<IDevice> device;
+#if MAJOR_VERSION == 2
+        auto ret = factory->openDevice(IDevicesFactory::Device::PRIMARY, returnIn(result, device));
+#elif MAJOR_VERSION >= 4
+        auto ret = factory->openPrimaryDevice(returnIn(result, device));
+#endif
+        if (!ret.isOk() || result != Result::OK || device == nullptr) {
+            ALOGW("Primary device can not be opened, transaction: %s, result %d, device %p",
+                  ret.description().c_str(), result, device.get());
+            return nullptr;
+        }
+        return device;
+    }
+};
diff --git a/audio/effect/2.0/Android.bp b/audio/effect/2.0/Android.bp
index 2dd1a0c..d4482c2 100644
--- a/audio/effect/2.0/Android.bp
+++ b/audio/effect/2.0/Android.bp
@@ -30,4 +30,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/effect/4.0/Android.bp b/audio/effect/4.0/Android.bp
index 2c32bcb..8c1900f 100644
--- a/audio/effect/4.0/Android.bp
+++ b/audio/effect/4.0/Android.bp
@@ -30,4 +30,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/effect/5.0/Android.bp b/audio/effect/5.0/Android.bp
index 32fe652..b7dad8d 100644
--- a/audio/effect/5.0/Android.bp
+++ b/audio/effect/5.0/Android.bp
@@ -31,4 +31,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/effect/5.0/xml/Android.bp b/audio/effect/5.0/xml/Android.bp
index 967135c..eb2bcee 100644
--- a/audio/effect/5.0/xml/Android.bp
+++ b/audio/effect/5.0/xml/Android.bp
@@ -1,6 +1,6 @@
 
 xsd_config {
-    name: "audio_effects_conf",
+    name: "audio_effects_conf_V5_0",
     srcs: ["audio_effects_conf.xsd"],
     package_name: "audio.effects.V5_0",
 }
diff --git a/audio/effect/6.0/Android.bp b/audio/effect/6.0/Android.bp
new file mode 100644
index 0000000..b6184f3
--- /dev/null
+++ b/audio/effect/6.0/Android.bp
@@ -0,0 +1,33 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio.effect@6.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IAcousticEchoCancelerEffect.hal",
+        "IAutomaticGainControlEffect.hal",
+        "IBassBoostEffect.hal",
+        "IDownmixEffect.hal",
+        "IEffect.hal",
+        "IEffectBufferProviderCallback.hal",
+        "IEffectsFactory.hal",
+        "IEnvironmentalReverbEffect.hal",
+        "IEqualizerEffect.hal",
+        "ILoudnessEnhancerEffect.hal",
+        "INoiseSuppressionEffect.hal",
+        "IPresetReverbEffect.hal",
+        "IVirtualizerEffect.hal",
+        "IVisualizerEffect.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@6.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/audio/effect/6.0/IAcousticEchoCancelerEffect.hal b/audio/effect/6.0/IAcousticEchoCancelerEffect.hal
new file mode 100644
index 0000000..f7d769f
--- /dev/null
+++ b/audio/effect/6.0/IAcousticEchoCancelerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IAcousticEchoCancelerEffect extends IEffect {
+    /**
+     * Sets echo delay value in milliseconds.
+     */
+    setEchoDelay(uint32_t echoDelayMs) generates (Result retval);
+
+    /**
+     * Gets echo delay value in milliseconds.
+     */
+    getEchoDelay() generates (Result retval, uint32_t echoDelayMs);
+};
diff --git a/audio/effect/6.0/IAutomaticGainControlEffect.hal b/audio/effect/6.0/IAutomaticGainControlEffect.hal
new file mode 100644
index 0000000..d264cd4
--- /dev/null
+++ b/audio/effect/6.0/IAutomaticGainControlEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IAutomaticGainControlEffect extends IEffect {
+    /**
+     * Sets target level in millibels.
+     */
+    setTargetLevel(int16_t targetLevelMb) generates (Result retval);
+
+    /**
+     * Gets target level.
+     */
+    getTargetLevel() generates (Result retval, int16_t targetLevelMb);
+
+    /**
+     * Sets gain in the compression range in millibels.
+     */
+    setCompGain(int16_t compGainMb) generates (Result retval);
+
+    /**
+     * Gets gain in the compression range.
+     */
+    getCompGain() generates (Result retval, int16_t compGainMb);
+
+    /**
+     * Enables or disables limiter.
+     */
+    setLimiterEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Returns whether limiter is enabled.
+     */
+    isLimiterEnabled() generates (Result retval, bool enabled);
+
+    struct AllProperties {
+        int16_t targetLevelMb;
+        int16_t compGainMb;
+        bool limiterEnabled;
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IBassBoostEffect.hal b/audio/effect/6.0/IBassBoostEffect.hal
new file mode 100644
index 0000000..91c4092
--- /dev/null
+++ b/audio/effect/6.0/IBassBoostEffect.hal
@@ -0,0 +1,48 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IBassBoostEffect extends IEffect {
+    /**
+     * Returns whether setting bass boost strength is supported.
+     */
+    isStrengthSupported() generates (Result retval, bool strengthSupported);
+
+    enum StrengthRange : uint16_t {
+        MIN = 0,
+        MAX = 1000
+    };
+
+    /**
+     * Sets bass boost strength.
+     *
+     * @param strength strength of the effect. The valid range for strength
+     *                 strength is [0, 1000], where 0 per mille designates the
+     *                 mildest effect and 1000 per mille designates the
+     *                 strongest.
+     * @return retval operation completion status.
+     */
+    setStrength(uint16_t strength) generates (Result retval);
+
+    /**
+     * Gets virtualization strength.
+     */
+    getStrength() generates (Result retval, uint16_t strength);
+};
diff --git a/audio/effect/6.0/IDownmixEffect.hal b/audio/effect/6.0/IDownmixEffect.hal
new file mode 100644
index 0000000..e3a38e2
--- /dev/null
+++ b/audio/effect/6.0/IDownmixEffect.hal
@@ -0,0 +1,37 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IDownmixEffect extends IEffect {
+    enum Type : int32_t {
+        STRIP, // throw away the extra channels
+        FOLD   // mix the extra channels with FL/FR
+    };
+
+    /**
+     * Sets the current downmix preset.
+     */
+    setType(Type preset) generates (Result retval);
+
+    /**
+     * Gets the current downmix preset.
+     */
+    getType() generates (Result retval, Type preset);
+};
diff --git a/audio/effect/6.0/IEffect.hal b/audio/effect/6.0/IEffect.hal
new file mode 100644
index 0000000..f4c50a2
--- /dev/null
+++ b/audio/effect/6.0/IEffect.hal
@@ -0,0 +1,421 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffectBufferProviderCallback;
+
+interface IEffect {
+    /**
+     * Initialize effect engine--all configurations return to default.
+     *
+     * @return retval operation completion status.
+     */
+    @entry
+    init() generates (Result retval);
+
+    /**
+     * Apply new audio parameters configurations for input and output buffers.
+     * The provider callbacks may be empty, but in this case the buffer
+     * must be provided in the EffectConfig structure.
+     *
+     * @param config configuration descriptor.
+     * @param inputBufferProvider optional buffer provider reference.
+     * @param outputBufferProvider optional buffer provider reference.
+     * @return retval operation completion status.
+     */
+    setConfig(EffectConfig config,
+            IEffectBufferProviderCallback inputBufferProvider,
+            IEffectBufferProviderCallback outputBufferProvider)
+            generates (Result retval);
+
+    /**
+     * Reset the effect engine. Keep configuration but resets state and buffer
+     * content.
+     *
+     * @return retval operation completion status.
+     */
+    reset() generates (Result retval);
+
+    /**
+     * Enable processing.
+     *
+     * @return retval operation completion status.
+     */
+    @callflow(next={"prepareForProcessing"})
+    enable() generates (Result retval);
+
+    /**
+     * Disable processing.
+     *
+     * @return retval operation completion status.
+     */
+    @callflow(next={"close"})
+    disable() generates (Result retval);
+
+    /**
+     * Set the rendering device the audio output path is connected to.  The
+     * effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its
+     * descriptor to receive this command when the device changes.
+     *
+     * Note: this method is only supported for effects inserted into
+     *       the output chain.
+     *
+     * @param device output device specification.
+     * @return retval operation completion status.
+     */
+    setDevice(bitfield<AudioDevice> device) generates (Result retval);
+
+    /**
+     * Set and get volume. Used by audio framework to delegate volume control to
+     * effect engine. The effect implementation must set EFFECT_FLAG_VOLUME_CTRL
+     * flag in its descriptor to receive this command. The effect engine must
+     * return the volume that should be applied before the effect is
+     * processed. The overall volume (the volume actually applied by the effect
+     * engine multiplied by the returned value) should match the value indicated
+     * in the command.
+     *
+     * @param volumes vector containing volume for each channel defined in
+     *                EffectConfig for output buffer expressed in 8.24 fixed
+     *                point format.
+     * @return result updated volume values.
+     * @return retval operation completion status.
+     */
+    setAndGetVolume(vec<uint32_t> volumes)
+            generates (Result retval, vec<uint32_t> result);
+
+    /**
+     * Notify the effect of the volume change. The effect implementation must
+     * set EFFECT_FLAG_VOLUME_IND flag in its descriptor to receive this
+     * command.
+     *
+     * @param volumes vector containing volume for each channel defined in
+     *                EffectConfig for output buffer expressed in 8.24 fixed
+     *                point format.
+     * @return retval operation completion status.
+     */
+    volumeChangeNotification(vec<uint32_t> volumes)
+            generates (Result retval);
+
+    /**
+     * Set the audio mode. The effect implementation must set
+     * EFFECT_FLAG_AUDIO_MODE_IND flag in its descriptor to receive this command
+     * when the audio mode changes.
+     *
+     * @param mode desired audio mode.
+     * @return retval operation completion status.
+     */
+    setAudioMode(AudioMode mode) generates (Result retval);
+
+    /**
+     * Apply new audio parameters configurations for input and output buffers of
+     * reverse stream.  An example of reverse stream is the echo reference
+     * supplied to an Acoustic Echo Canceler.
+     *
+     * @param config configuration descriptor.
+     * @param inputBufferProvider optional buffer provider reference.
+     * @param outputBufferProvider optional buffer provider reference.
+     * @return retval operation completion status.
+     */
+    setConfigReverse(EffectConfig config,
+            IEffectBufferProviderCallback inputBufferProvider,
+            IEffectBufferProviderCallback outputBufferProvider)
+            generates (Result retval);
+
+    /**
+     * Set the capture device the audio input path is connected to. The effect
+     * implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to
+     * receive this command when the device changes.
+     *
+     * Note: this method is only supported for effects inserted into
+     *       the input chain.
+     *
+     * @param device input device specification.
+     * @return retval operation completion status.
+     */
+    setInputDevice(bitfield<AudioDevice> device) generates (Result retval);
+
+    /**
+     * Read audio parameters configurations for input and output buffers.
+     *
+     * @return retval operation completion status.
+     * @return config configuration descriptor.
+     */
+    getConfig() generates (Result retval, EffectConfig config);
+
+    /**
+     * Read audio parameters configurations for input and output buffers of
+     * reverse stream.
+     *
+     * @return retval operation completion status.
+     * @return config configuration descriptor.
+     */
+    getConfigReverse() generates (Result retval, EffectConfig config);
+
+    /**
+     * Queries for supported combinations of main and auxiliary channels
+     * (e.g. for a multi-microphone noise suppressor).
+     *
+     * @param maxConfigs maximum number of the combinations to return.
+     * @return retval absence of the feature support is indicated using
+     *                NOT_SUPPORTED code. RESULT_TOO_BIG is returned if
+     *                the number of supported combinations exceeds 'maxConfigs'.
+     * @return result list of configuration descriptors.
+     */
+    getSupportedAuxChannelsConfigs(uint32_t maxConfigs)
+            generates (Result retval, vec<EffectAuxChannelsConfig> result);
+
+    /**
+     * Retrieves the current configuration of main and auxiliary channels.
+     *
+     * @return retval absence of the feature support is indicated using
+     *                NOT_SUPPORTED code.
+     * @return result configuration descriptor.
+     */
+    getAuxChannelsConfig()
+            generates (Result retval, EffectAuxChannelsConfig result);
+
+    /**
+     * Sets the current configuration of main and auxiliary channels.
+     *
+     * @return retval operation completion status; absence of the feature
+     *                support is indicated using NOT_SUPPORTED code.
+     */
+    setAuxChannelsConfig(EffectAuxChannelsConfig config)
+            generates (Result retval);
+
+    /**
+     * Set the audio source the capture path is configured for (Camcorder, voice
+     * recognition...).
+     *
+     * Note: this method is only supported for effects inserted into
+     *       the input chain.
+     *
+     * @param source source descriptor.
+     * @return retval operation completion status.
+     */
+    setAudioSource(AudioSource source) generates (Result retval);
+
+    /**
+     * This command indicates if the playback thread the effect is attached to
+     * is offloaded or not, and updates the I/O handle of the playback thread
+     * the effect is attached to.
+     *
+     * @param param effect offload descriptor.
+     * @return retval operation completion status.
+     */
+    offload(EffectOffloadParameter param) generates (Result retval);
+
+    /**
+     * Returns the effect descriptor.
+     *
+     * @return retval operation completion status.
+     * @return descriptor effect descriptor.
+     */
+    getDescriptor() generates (Result retval, EffectDescriptor descriptor);
+
+    /**
+     * Set up required transports for passing audio buffers to the effect.
+     *
+     * The transport consists of shared memory and a message queue for reporting
+     * effect processing operation status. The shared memory is set up
+     * separately using 'setProcessBuffers' method.
+     *
+     * Processing is requested by setting 'REQUEST_PROCESS' or
+     * 'REQUEST_PROCESS_REVERSE' EventFlags associated with the status message
+     * queue. The result of processing may be one of the following:
+     *   OK if there were no errors during processing;
+     *   INVALID_ARGUMENTS if audio buffers are invalid;
+     *   INVALID_STATE if the engine has finished the disable phase;
+     *   NOT_INITIALIZED if the audio buffers were not set;
+     *   NOT_SUPPORTED if the requested processing type is not supported by
+     *                 the effect.
+     *
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queue.
+     * @return statusMQ a message queue used for passing status from the effect.
+     */
+    @callflow(next={"setProcessBuffers"})
+    prepareForProcessing() generates (Result retval, fmq_sync<Result> statusMQ);
+
+    /**
+     * Set up input and output buffers for processing audio data. The effect
+     * may modify both the input and the output buffer during the operation.
+     * Buffers may be set multiple times during effect lifetime.
+     *
+     * The input and the output buffer may be reused between different effects,
+     * and the input buffer may be used as an output buffer. Buffers are
+     * distinguished using 'AudioBuffer.id' field.
+     *
+     * @param inBuffer input audio buffer.
+     * @param outBuffer output audio buffer.
+     * @return retval OK if both buffers were mapped successfully.
+     *                INVALID_ARGUMENTS if there was a problem with mapping
+     *                                  any of the buffers.
+     */
+    setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer)
+            generates (Result retval);
+
+    /**
+     * Execute a vendor specific command on the effect. The command code
+     * and data, as well as result data are not interpreted by Android
+     * Framework and are passed as-is between the application and the effect.
+     *
+     * The effect must use standard POSIX.1-2001 error codes for the operation
+     * completion status.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it. This method only works for effects
+     * implemented in software.
+     *
+     * @param commandId the ID of the command.
+     * @param data command data.
+     * @param resultMaxSize maximum size in bytes of the result; can be 0.
+     * @return status command completion status.
+     * @return result result data.
+     */
+    command(uint32_t commandId, vec<uint8_t> data, uint32_t resultMaxSize)
+            generates (int32_t status, vec<uint8_t> result);
+
+    /**
+     * Set a vendor-specific parameter and apply it immediately. The parameter
+     * code and data are not interpreted by Android Framework and are passed
+     * as-is between the application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+     * unknown or if provided parameter data is invalid. If the effect does not
+     * support setting vendor-specific parameters, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it. This method only works for effects
+     * implemented in software.
+     *
+     * @param parameter identifying data of the parameter.
+     * @param value the value of the parameter.
+     * @return retval operation completion status.
+     */
+    setParameter(vec<uint8_t> parameter, vec<uint8_t> value)
+            generates (Result retval);
+
+    /**
+     * Get a vendor-specific parameter value. The parameter code and returned
+     * data are not interpreted by Android Framework and are passed as-is
+     * between the application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+     * unknown. If the effect does not support setting vendor-specific
+     * parameters, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param parameter identifying data of the parameter.
+     * @param valueMaxSize maximum size in bytes of the value.
+     * @return retval operation completion status.
+     * @return result the value of the parameter.
+     */
+    getParameter(vec<uint8_t> parameter, uint32_t valueMaxSize)
+            generates (Result retval, vec<uint8_t> value);
+
+    /**
+     * Get supported configs for a vendor-specific feature. The configs returned
+     * are not interpreted by Android Framework and are passed as-is between the
+     * application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+     * unknown. If the effect does not support getting vendor-specific feature
+     * configs, it must return NOT_SUPPORTED. If the feature is supported but
+     * the total number of supported configurations exceeds the maximum number
+     * indicated by the caller, the method must return RESULT_TOO_BIG.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param featureId feature identifier.
+     * @param maxConfigs maximum number of configs to return.
+     * @param configSize size of each config in bytes.
+     * @return retval operation completion status.
+     * @return configsCount number of configs returned.
+     * @return configsData data for all the configs returned.
+     */
+    getSupportedConfigsForFeature(
+            uint32_t featureId,
+            uint32_t maxConfigs,
+            uint32_t configSize) generates (
+                    Result retval,
+                    uint32_t configsCount,
+                    vec<uint8_t> configsData);
+
+    /**
+     * Get the current config for a vendor-specific feature. The config returned
+     * is not interpreted by Android Framework and is passed as-is between the
+     * application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+     * unknown. If the effect does not support getting vendor-specific
+     * feature configs, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param featureId feature identifier.
+     * @param configSize size of the config in bytes.
+     * @return retval operation completion status.
+     * @return configData config data.
+     */
+    getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize)
+            generates (Result retval, vec<uint8_t> configData);
+
+    /**
+     * Set the current config for a vendor-specific feature. The config data
+     * is not interpreted by Android Framework and is passed as-is between the
+     * application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+     * unknown. If the effect does not support getting vendor-specific
+     * feature configs, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param featureId feature identifier.
+     * @param configData config data.
+     * @return retval operation completion status.
+     */
+    setCurrentConfigForFeature(uint32_t featureId, vec<uint8_t> configData)
+            generates (Result retval);
+
+    /**
+     * Called by the framework to deinitialize the effect and free up
+     * all currently allocated resources. It is recommended to close
+     * the effect on the client side as soon as it is becomes unused.
+     *
+     * The client must ensure that this function is not called while
+     * audio data is being transferred through the effect's message queues.
+     *
+     * @return retval OK in case the success.
+     *                INVALID_STATE if the effect was already closed.
+     */
+    @exit
+    close() generates (Result retval);
+};
diff --git a/audio/effect/6.0/IEffectBufferProviderCallback.hal b/audio/effect/6.0/IEffectBufferProviderCallback.hal
new file mode 100644
index 0000000..097528d
--- /dev/null
+++ b/audio/effect/6.0/IEffectBufferProviderCallback.hal
@@ -0,0 +1,38 @@
+/*
+ * 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.audio.effect@6.0;
+
+/**
+ * This callback interface contains functions that can be used by the effect
+ * engine 'process' function to exchange input and output audio buffers.
+ */
+interface IEffectBufferProviderCallback {
+    /**
+     * Called to retrieve a buffer where data should read from by 'process'
+     * function.
+     *
+     * @return buffer audio buffer for processing
+     */
+    getBuffer() generates (AudioBuffer buffer);
+
+    /**
+     * Called to provide a buffer with the data written by 'process' function.
+     *
+     * @param buffer audio buffer for processing
+     */
+    putBuffer(AudioBuffer buffer);
+};
diff --git a/audio/effect/6.0/IEffectsFactory.hal b/audio/effect/6.0/IEffectsFactory.hal
new file mode 100644
index 0000000..e08b2de
--- /dev/null
+++ b/audio/effect/6.0/IEffectsFactory.hal
@@ -0,0 +1,58 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEffectsFactory {
+    /**
+     * Returns descriptors of different effects in all loaded libraries.
+     *
+     * @return retval operation completion status.
+     * @return result list of effect descriptors.
+     */
+    getAllDescriptors() generates(Result retval, vec<EffectDescriptor> result);
+
+    /**
+     * Returns a descriptor of a particular effect.
+     *
+     * @return retval operation completion status.
+     * @return result effect descriptor.
+     */
+    getDescriptor(Uuid uid) generates(Result retval, EffectDescriptor result);
+
+    /**
+     * Creates an effect engine of the specified type.  To release the effect
+     * engine, it is necessary to release references to the returned effect
+     * object.
+     *
+     * @param uid effect uuid.
+     * @param session audio session to which this effect instance will be
+     *                attached.  All effects created with the same session ID
+     *                are connected in series and process the same signal
+     *                stream.
+     * @param ioHandle identifies the output or input stream this effect is
+     *                 directed to in audio HAL.
+     * @return retval operation completion status.
+     * @return result the interface for the created effect.
+     * @return effectId the unique ID of the effect to be used with
+     *                  IStream::addEffect and IStream::removeEffect methods.
+     */
+    createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle)
+        generates (Result retval, IEffect result, uint64_t effectId);
+};
diff --git a/audio/effect/6.0/IEnvironmentalReverbEffect.hal b/audio/effect/6.0/IEnvironmentalReverbEffect.hal
new file mode 100644
index 0000000..8887533
--- /dev/null
+++ b/audio/effect/6.0/IEnvironmentalReverbEffect.hal
@@ -0,0 +1,178 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEnvironmentalReverbEffect extends IEffect {
+    /**
+     * Sets whether the effect should be bypassed.
+     */
+    setBypass(bool bypass) generates (Result retval);
+
+    /**
+     * Gets whether the effect should be bypassed.
+     */
+    getBypass() generates (Result retval, bool bypass);
+
+    enum ParamRange : int16_t {
+        ROOM_LEVEL_MIN = -6000,
+        ROOM_LEVEL_MAX = 0,
+        ROOM_HF_LEVEL_MIN = -4000,
+        ROOM_HF_LEVEL_MAX = 0,
+        DECAY_TIME_MIN = 100,
+        DECAY_TIME_MAX = 20000,
+        DECAY_HF_RATIO_MIN = 100,
+        DECAY_HF_RATIO_MAX = 1000,
+        REFLECTIONS_LEVEL_MIN = -6000,
+        REFLECTIONS_LEVEL_MAX = 0,
+        REFLECTIONS_DELAY_MIN = 0,
+        REFLECTIONS_DELAY_MAX = 65,
+        REVERB_LEVEL_MIN = -6000,
+        REVERB_LEVEL_MAX = 0,
+        REVERB_DELAY_MIN = 0,
+        REVERB_DELAY_MAX = 65,
+        DIFFUSION_MIN = 0,
+        DIFFUSION_MAX = 1000,
+        DENSITY_MIN = 0,
+        DENSITY_MAX = 1000
+    };
+
+    /**
+     * Sets the room level.
+     */
+    setRoomLevel(int16_t roomLevel) generates (Result retval);
+
+    /**
+     * Gets the room level.
+     */
+    getRoomLevel() generates (Result retval, int16_t roomLevel);
+
+    /**
+     * Sets the room high frequencies level.
+     */
+    setRoomHfLevel(int16_t roomHfLevel) generates (Result retval);
+
+    /**
+     * Gets the room high frequencies level.
+     */
+    getRoomHfLevel() generates (Result retval, int16_t roomHfLevel);
+
+    /**
+     * Sets the room decay time.
+     */
+    setDecayTime(uint32_t decayTime) generates (Result retval);
+
+    /**
+     * Gets the room decay time.
+     */
+    getDecayTime() generates (Result retval, uint32_t decayTime);
+
+    /**
+     * Sets the ratio of high frequencies decay.
+     */
+    setDecayHfRatio(int16_t decayHfRatio) generates (Result retval);
+
+    /**
+     * Gets the ratio of high frequencies decay.
+     */
+    getDecayHfRatio() generates (Result retval, int16_t decayHfRatio);
+
+    /**
+     * Sets the level of reflections in the room.
+     */
+    setReflectionsLevel(int16_t reflectionsLevel) generates (Result retval);
+
+    /**
+     * Gets the level of reflections in the room.
+     */
+    getReflectionsLevel() generates (Result retval, int16_t reflectionsLevel);
+
+    /**
+     * Sets the reflections delay in the room.
+     */
+    setReflectionsDelay(uint32_t reflectionsDelay) generates (Result retval);
+
+    /**
+     * Gets the reflections delay in the room.
+     */
+    getReflectionsDelay() generates (Result retval, uint32_t reflectionsDelay);
+
+    /**
+     * Sets the reverb level of the room.
+     */
+    setReverbLevel(int16_t reverbLevel) generates (Result retval);
+
+    /**
+     * Gets the reverb level of the room.
+     */
+    getReverbLevel() generates (Result retval, int16_t reverbLevel);
+
+    /**
+     * Sets the reverb delay of the room.
+     */
+    setReverbDelay(uint32_t reverDelay) generates (Result retval);
+
+    /**
+     * Gets the reverb delay of the room.
+     */
+    getReverbDelay() generates (Result retval, uint32_t reverbDelay);
+
+    /**
+     * Sets room diffusion.
+     */
+    setDiffusion(int16_t diffusion) generates (Result retval);
+
+    /**
+     * Gets room diffusion.
+     */
+    getDiffusion() generates (Result retval, int16_t diffusion);
+
+    /**
+     * Sets room wall density.
+     */
+    setDensity(int16_t density) generates (Result retval);
+
+    /**
+     * Gets room wall density.
+     */
+    getDensity() generates (Result retval, int16_t density);
+
+    struct AllProperties {
+        int16_t  roomLevel;         // in millibels,    range -6000 to 0
+        int16_t  roomHfLevel;       // in millibels,    range -4000 to 0
+        uint32_t decayTime;         // in milliseconds, range 100 to 20000
+        int16_t  decayHfRatio;      // in permilles,    range 100 to 1000
+        int16_t  reflectionsLevel;  // in millibels,    range -6000 to 0
+        uint32_t reflectionsDelay;  // in milliseconds, range 0 to 65
+        int16_t  reverbLevel;       // in millibels,    range -6000 to 0
+        uint32_t reverbDelay;       // in milliseconds, range 0 to 65
+        int16_t  diffusion;         // in permilles,    range 0 to 1000
+        int16_t  density;           // in permilles,    range 0 to 1000
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IEqualizerEffect.hal b/audio/effect/6.0/IEqualizerEffect.hal
new file mode 100644
index 0000000..962d518
--- /dev/null
+++ b/audio/effect/6.0/IEqualizerEffect.hal
@@ -0,0 +1,93 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEqualizerEffect extends IEffect {
+    /**
+     * Gets the number of frequency bands that the equalizer supports.
+     */
+    getNumBands() generates (Result retval, uint16_t numBands);
+
+    /**
+     * Returns the minimum and maximum band levels supported.
+     */
+    getLevelRange()
+            generates (Result retval, int16_t minLevel, int16_t maxLevel);
+
+    /**
+     * Sets the gain for the given equalizer band.
+     */
+    setBandLevel(uint16_t band, int16_t level) generates (Result retval);
+
+    /**
+     * Gets the gain for the given equalizer band.
+     */
+    getBandLevel(uint16_t band) generates (Result retval, int16_t level);
+
+    /**
+     * Gets the center frequency of the given band, in milliHertz.
+     */
+    getBandCenterFrequency(uint16_t band)
+            generates (Result retval, uint32_t centerFreqmHz);
+
+    /**
+     * Gets the frequency range of the given frequency band, in milliHertz.
+     */
+    getBandFrequencyRange(uint16_t band)
+            generates (Result retval, uint32_t minFreqmHz, uint32_t maxFreqmHz);
+
+    /**
+     * Gets the band that has the most effect on the given frequency
+     * in milliHertz.
+     */
+    getBandForFrequency(uint32_t freqmHz)
+            generates (Result retval, uint16_t band);
+
+    /**
+     * Gets the names of all presets the equalizer supports.
+     */
+    getPresetNames() generates (Result retval, vec<string> names);
+
+    /**
+     * Sets the current preset using the index of the preset in the names
+     * vector returned via 'getPresetNames'.
+     */
+    setCurrentPreset(uint16_t preset) generates (Result retval);
+
+    /**
+     * Gets the current preset.
+     */
+    getCurrentPreset() generates (Result retval, uint16_t preset);
+
+    struct AllProperties {
+        uint16_t curPreset;
+        vec<int16_t> bandLevels;
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/ILoudnessEnhancerEffect.hal b/audio/effect/6.0/ILoudnessEnhancerEffect.hal
new file mode 100644
index 0000000..73dc818
--- /dev/null
+++ b/audio/effect/6.0/ILoudnessEnhancerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface ILoudnessEnhancerEffect extends IEffect {
+    /**
+     * Sets target gain expressed in millibels.
+     */
+    setTargetGain(int32_t targetGainMb) generates (Result retval);
+
+    /**
+     * Gets target gain expressed in millibels.
+     */
+    getTargetGain() generates (Result retval, int32_t targetGainMb);
+};
diff --git a/audio/effect/6.0/INoiseSuppressionEffect.hal b/audio/effect/6.0/INoiseSuppressionEffect.hal
new file mode 100644
index 0000000..16dee57
--- /dev/null
+++ b/audio/effect/6.0/INoiseSuppressionEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface INoiseSuppressionEffect extends IEffect {
+    enum Level : int32_t {
+        LOW,
+        MEDIUM,
+        HIGH
+    };
+
+    /**
+     * Sets suppression level.
+     */
+    setSuppressionLevel(Level level) generates (Result retval);
+
+    /**
+     * Gets suppression level.
+     */
+    getSuppressionLevel() generates (Result retval, Level level);
+
+    enum Type : int32_t {
+        SINGLE_CHANNEL,
+        MULTI_CHANNEL
+    };
+
+    /**
+     * Set suppression type.
+     */
+    setSuppressionType(Type type) generates (Result retval);
+
+    /**
+     * Get suppression type.
+     */
+    getSuppressionType() generates (Result retval, Type type);
+
+    struct AllProperties {
+        Level level;
+        Type type;
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IPresetReverbEffect.hal b/audio/effect/6.0/IPresetReverbEffect.hal
new file mode 100644
index 0000000..d00c8af
--- /dev/null
+++ b/audio/effect/6.0/IPresetReverbEffect.hal
@@ -0,0 +1,43 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IPresetReverbEffect extends IEffect {
+    enum Preset : int32_t {
+        NONE,        // no reverb or reflections
+        SMALLROOM,   // a small room less than five meters in length
+        MEDIUMROOM,  // a medium room with a length of ten meters or less
+        LARGEROOM,   // a large-sized room suitable for live performances
+        MEDIUMHALL,  // a medium-sized hall
+        LARGEHALL,   // a large-sized hall suitable for a full orchestra
+        PLATE,       // synthesis of the traditional plate reverb
+        LAST = PLATE
+    };
+
+    /**
+     * Sets the current preset.
+     */
+    setPreset(Preset preset) generates (Result retval);
+
+    /**
+     * Gets the current preset.
+     */
+    getPreset() generates (Result retval, Preset preset);
+};
diff --git a/audio/effect/6.0/IVirtualizerEffect.hal b/audio/effect/6.0/IVirtualizerEffect.hal
new file mode 100644
index 0000000..5967b33
--- /dev/null
+++ b/audio/effect/6.0/IVirtualizerEffect.hal
@@ -0,0 +1,77 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IVirtualizerEffect extends IEffect {
+    /**
+     * Returns whether setting virtualization strength is supported.
+     */
+    isStrengthSupported() generates (bool strengthSupported);
+
+    enum StrengthRange : uint16_t {
+        MIN = 0,
+        MAX = 1000
+    };
+
+    /**
+     * Sets virtualization strength.
+     *
+     * @param strength strength of the effect. The valid range for strength
+     *                 strength is [0, 1000], where 0 per mille designates the
+     *                 mildest effect and 1000 per mille designates the
+     *                 strongest.
+     * @return retval operation completion status.
+     */
+    setStrength(uint16_t strength) generates (Result retval);
+
+    /**
+     * Gets virtualization strength.
+     */
+    getStrength() generates (Result retval, uint16_t strength);
+
+    struct SpeakerAngle {
+        /** Speaker channel mask */
+        bitfield<AudioChannelMask> mask;
+        // all angles are expressed in degrees and
+        // are relative to the listener.
+        int16_t azimuth; // 0 is the direction the listener faces
+                         // 180 is behind the listener
+                         // -90 is to their left
+        int16_t elevation; // 0 is the horizontal plane
+                           // +90 is above the listener, -90 is below
+    };
+    /**
+     * Retrieves virtual speaker angles for the given channel mask on the
+     * specified device.
+     */
+    getVirtualSpeakerAngles(bitfield<AudioChannelMask> mask, AudioDevice device)
+            generates (Result retval, vec<SpeakerAngle> speakerAngles);
+
+    /**
+     * Forces the virtualizer effect for the given output device.
+     */
+    forceVirtualizationMode(AudioDevice device) generates (Result retval);
+
+    /**
+     * Returns audio device reflecting the current virtualization mode,
+     * AUDIO_DEVICE_NONE when not virtualizing.
+     */
+    getVirtualizationMode() generates (Result retval, AudioDevice device);
+};
diff --git a/audio/effect/6.0/IVisualizerEffect.hal b/audio/effect/6.0/IVisualizerEffect.hal
new file mode 100644
index 0000000..3df3e6f
--- /dev/null
+++ b/audio/effect/6.0/IVisualizerEffect.hal
@@ -0,0 +1,110 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IVisualizerEffect extends IEffect {
+    enum CaptureSizeRange : int32_t {
+        MAX = 1024,  // maximum capture size in samples
+        MIN = 128    // minimum capture size in samples
+    };
+
+    /**
+     * Sets the number PCM samples in the capture.
+     */
+    setCaptureSize(uint16_t captureSize) generates (Result retval);
+
+    /**
+     * Gets the number PCM samples in the capture.
+     */
+    getCaptureSize() generates (Result retval, uint16_t captureSize);
+
+    enum ScalingMode : int32_t {
+        // Keep in sync with SCALING_MODE_... in
+        // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+        NORMALIZED = 0,
+        AS_PLAYED = 1
+    };
+
+    /**
+     * Specifies the way the captured data is scaled.
+     */
+    setScalingMode(ScalingMode scalingMode) generates (Result retval);
+
+    /**
+     * Retrieves the way the captured data is scaled.
+     */
+    getScalingMode() generates (Result retval, ScalingMode scalingMode);
+
+    /**
+     * Informs the visualizer about the downstream latency.
+     */
+    setLatency(uint32_t latencyMs) generates (Result retval);
+
+    /**
+     * Gets the downstream latency.
+     */
+    getLatency() generates (Result retval, uint32_t latencyMs);
+
+    enum MeasurementMode : int32_t {
+        // Keep in sync with MEASUREMENT_MODE_... in
+        // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+        NONE = 0x0,
+        PEAK_RMS = 0x1
+    };
+
+    /**
+     * Specifies which measurements are to be made.
+     */
+    setMeasurementMode(MeasurementMode measurementMode)
+            generates (Result retval);
+
+    /**
+     * Retrieves which measurements are to be made.
+     */
+    getMeasurementMode() generates (
+            Result retval, MeasurementMode measurementMode);
+
+    /**
+     * Retrieves the latest PCM snapshot captured by the visualizer engine.  The
+     * number of samples to capture is specified by 'setCaptureSize' parameter.
+     *
+     * @return retval operation completion status.
+     * @return samples samples in 8 bit unsigned format (0 = 0x80)
+     */
+    capture() generates (Result retval, vec<uint8_t> samples);
+
+    struct Measurement {
+        MeasurementMode mode;    // discriminator
+        union Values {
+            struct PeakAndRms {
+                int32_t peakMb;  // millibels
+                int32_t rmsMb;   // millibels
+            } peakAndRms;
+        } value;
+    };
+    /**
+     * Retrieves the latest measurements. The measurements to be made
+     * are specified by 'setMeasurementMode' parameter.
+     *
+     * @return retval operation completion status.
+     * @return result measurement.
+     */
+    measure() generates (Result retval, Measurement result);
+};
diff --git a/audio/effect/6.0/types.hal b/audio/effect/6.0/types.hal
new file mode 100644
index 0000000..dd5a4ad
--- /dev/null
+++ b/audio/effect/6.0/types.hal
@@ -0,0 +1,301 @@
+/*
+ * 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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+
+enum Result : int32_t {
+    OK,
+    NOT_INITIALIZED,
+    INVALID_ARGUMENTS,
+    INVALID_STATE,
+    NOT_SUPPORTED,
+    RESULT_TOO_BIG
+};
+
+/**
+ * Effect engine capabilities/requirements flags.
+ *
+ * Definitions for flags field of effect descriptor.
+ *
+ * +----------------+--------+--------------------------------------------------
+ * | description    | bits   | values
+ * +----------------+--------+--------------------------------------------------
+ * | connection     | 0..2   | 0 insert: after track process
+ * | mode           |        | 1 auxiliary: connect to track auxiliary
+ * |                |        |  output and use send level
+ * |                |        | 2 replace: replaces track process function;
+ * |                |        |   must implement SRC, volume and mono to stereo.
+ * |                |        | 3 pre processing: applied below audio HAL on in
+ * |                |        | 4 post processing: applied below audio HAL on out
+ * |                |        | 5 - 7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | insertion      | 3..5   | 0 none
+ * | preference     |        | 1 first of the chain
+ * |                |        | 2 last of the chain
+ * |                |        | 3 exclusive (only effect in the insert chain)
+ * |                |        | 4..7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Volume         | 6..8   | 0 none
+ * | management     |        | 1 implements volume control
+ * |                |        | 2 requires volume indication
+ * |                |        | 3 monitors requested volume
+ * |                |        | 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Device         | 9..11  | 0 none
+ * | indication     |        | 1 requires device updates
+ * |                |        | 2, 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Sample input   | 12..13 | 1 direct: process() function or
+ * | mode           |        |   EFFECT_CMD_SET_CONFIG command must specify
+ * |                |        |   a buffer descriptor
+ * |                |        | 2 provider: process() function uses the
+ * |                |        |   bufferProvider indicated by the
+ * |                |        |   EFFECT_CMD_SET_CONFIG command to request input.
+ * |                |        |   buffers.
+ * |                |        | 3 both: both input modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Sample output  | 14..15 | 1 direct: process() function or
+ * | mode           |        |   EFFECT_CMD_SET_CONFIG command must specify
+ * |                |        |   a buffer descriptor
+ * |                |        | 2 provider: process() function uses the
+ * |                |        |   bufferProvider indicated by the
+ * |                |        |   EFFECT_CMD_SET_CONFIG command to request output
+ * |                |        |   buffers.
+ * |                |        | 3 both: both output modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Hardware       | 16..17 | 0 No hardware acceleration
+ * | acceleration   |        | 1 non tunneled hw acceleration: the process()
+ * |                |        |   function reads the samples, send them to HW
+ * |                |        |   accelerated effect processor, reads back
+ * |                |        |   the processed samples and returns them
+ * |                |        |   to the output buffer.
+ * |                |        | 2 tunneled hw acceleration: the process()
+ * |                |        |   function is transparent. The effect interface
+ * |                |        |   is only used to control the effect engine.
+ * |                |        |   This mode is relevant for global effects
+ * |                |        |   actually applied by the audio hardware on
+ * |                |        |   the output stream.
+ * +----------------+--------+--------------------------------------------------
+ * | Audio Mode     | 18..19 | 0 none
+ * | indication     |        | 1 requires audio mode updates
+ * |                |        | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Audio source   | 20..21 | 0 none
+ * | indication     |        | 1 requires audio source updates
+ * |                |        | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Effect offload | 22     | 0 The effect cannot be offloaded to an audio DSP
+ * | supported      |        | 1 The effect can be offloaded to an audio DSP
+ * +----------------+--------+--------------------------------------------------
+ * | Process        | 23     | 0 The effect implements a process function.
+ * | function       |        | 1 The effect does not implement a process
+ * | not            |        |   function: enabling the effect has no impact
+ * | implemented    |        |   on latency or CPU load.
+ * |                |        |   Effect implementations setting this flag do not
+ * |                |        |   have to implement a process function.
+ * +----------------+--------+--------------------------------------------------
+ */
+@export(name="", value_prefix="EFFECT_FLAG_")
+enum EffectFlags : int32_t {
+    // Insert mode
+    TYPE_SHIFT = 0,
+    TYPE_SIZE = 3,
+    TYPE_MASK = ((1 << TYPE_SIZE) -1) << TYPE_SHIFT,
+    TYPE_INSERT = 0 << TYPE_SHIFT,
+    TYPE_AUXILIARY = 1 << TYPE_SHIFT,
+    TYPE_REPLACE = 2 << TYPE_SHIFT,
+    TYPE_PRE_PROC = 3 << TYPE_SHIFT,
+    TYPE_POST_PROC = 4 << TYPE_SHIFT,
+
+    // Insert preference
+    INSERT_SHIFT = TYPE_SHIFT + TYPE_SIZE,
+    INSERT_SIZE = 3,
+    INSERT_MASK = ((1 << INSERT_SIZE) -1) << INSERT_SHIFT,
+    INSERT_ANY = 0 << INSERT_SHIFT,
+    INSERT_FIRST = 1 << INSERT_SHIFT,
+    INSERT_LAST = 2 << INSERT_SHIFT,
+    INSERT_EXCLUSIVE = 3 << INSERT_SHIFT,
+
+    // Volume control
+    VOLUME_SHIFT = INSERT_SHIFT + INSERT_SIZE,
+    VOLUME_SIZE = 3,
+    VOLUME_MASK = ((1 << VOLUME_SIZE) -1) << VOLUME_SHIFT,
+    VOLUME_CTRL = 1 << VOLUME_SHIFT,
+    VOLUME_IND = 2 << VOLUME_SHIFT,
+    VOLUME_MONITOR = 3 << VOLUME_SHIFT,
+    VOLUME_NONE = 0 << VOLUME_SHIFT,
+
+    // Device indication
+    DEVICE_SHIFT = VOLUME_SHIFT + VOLUME_SIZE,
+    DEVICE_SIZE = 3,
+    DEVICE_MASK = ((1 << DEVICE_SIZE) -1) << DEVICE_SHIFT,
+    DEVICE_IND = 1 << DEVICE_SHIFT,
+    DEVICE_NONE = 0 << DEVICE_SHIFT,
+
+    // Sample input modes
+    INPUT_SHIFT = DEVICE_SHIFT + DEVICE_SIZE,
+    INPUT_SIZE = 2,
+    INPUT_MASK = ((1 << INPUT_SIZE) -1) << INPUT_SHIFT,
+    INPUT_DIRECT = 1 << INPUT_SHIFT,
+    INPUT_PROVIDER = 2 << INPUT_SHIFT,
+    INPUT_BOTH = 3 << INPUT_SHIFT,
+
+    // Sample output modes
+    OUTPUT_SHIFT = INPUT_SHIFT + INPUT_SIZE,
+    OUTPUT_SIZE = 2,
+    OUTPUT_MASK = ((1 << OUTPUT_SIZE) -1) << OUTPUT_SHIFT,
+    OUTPUT_DIRECT = 1 << OUTPUT_SHIFT,
+    OUTPUT_PROVIDER = 2 << OUTPUT_SHIFT,
+    OUTPUT_BOTH = 3 << OUTPUT_SHIFT,
+
+    // Hardware acceleration mode
+    HW_ACC_SHIFT = OUTPUT_SHIFT + OUTPUT_SIZE,
+    HW_ACC_SIZE = 2,
+    HW_ACC_MASK = ((1 << HW_ACC_SIZE) -1) << HW_ACC_SHIFT,
+    HW_ACC_SIMPLE = 1 << HW_ACC_SHIFT,
+    HW_ACC_TUNNEL = 2 << HW_ACC_SHIFT,
+
+    // Audio mode indication
+    AUDIO_MODE_SHIFT = HW_ACC_SHIFT + HW_ACC_SIZE,
+    AUDIO_MODE_SIZE = 2,
+    AUDIO_MODE_MASK = ((1 << AUDIO_MODE_SIZE) -1) << AUDIO_MODE_SHIFT,
+    AUDIO_MODE_IND = 1 << AUDIO_MODE_SHIFT,
+    AUDIO_MODE_NONE = 0 << AUDIO_MODE_SHIFT,
+
+    // Audio source indication
+    AUDIO_SOURCE_SHIFT = AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE,
+    AUDIO_SOURCE_SIZE = 2,
+    AUDIO_SOURCE_MASK = ((1 << AUDIO_SOURCE_SIZE) -1) << AUDIO_SOURCE_SHIFT,
+    AUDIO_SOURCE_IND = 1 << AUDIO_SOURCE_SHIFT,
+    AUDIO_SOURCE_NONE = 0 << AUDIO_SOURCE_SHIFT,
+
+    // Effect offload indication
+    OFFLOAD_SHIFT = AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE,
+    OFFLOAD_SIZE = 1,
+    OFFLOAD_MASK = ((1 << OFFLOAD_SIZE) -1) << OFFLOAD_SHIFT,
+    OFFLOAD_SUPPORTED = 1 << OFFLOAD_SHIFT,
+
+    // Effect has no process indication
+    NO_PROCESS_SHIFT = OFFLOAD_SHIFT + OFFLOAD_SIZE,
+    NO_PROCESS_SIZE = 1,
+    NO_PROCESS_MASK = ((1 << NO_PROCESS_SIZE) -1) << NO_PROCESS_SHIFT,
+    NO_PROCESS = 1 << NO_PROCESS_SHIFT
+};
+
+/**
+ * The effect descriptor contains necessary information to facilitate the
+ * enumeration of the effect engines present in a library.
+ */
+struct EffectDescriptor {
+    Uuid type;                   // UUID of to the OpenSL ES interface implemented
+                                 // by this effect
+    Uuid uuid;                   // UUID for this particular implementation
+    bitfield<EffectFlags> flags; // effect engine capabilities/requirements flags
+    uint16_t cpuLoad;            // CPU load indication expressed in 0.1 MIPS units
+                                 // as estimated on an ARM9E core (ARMv5TE) with 0 WS
+    uint16_t memoryUsage;        // data memory usage expressed in KB and includes
+                                 // only dynamically allocated memory
+    uint8_t[64] name;            // human readable effect name
+    uint8_t[64] implementor;     // human readable effect implementor name
+};
+
+/**
+ * A buffer is a chunk of audio data for processing.  Multi-channel audio is
+ * always interleaved. The channel order is from LSB to MSB with regard to the
+ * channel mask definition in audio.h, audio_channel_mask_t, e.g.:
+ * Stereo: L, R; 5.1: FL, FR, FC, LFE, BL, BR.
+ *
+ * The buffer size is expressed in frame count, a frame being composed of
+ * samples for all channels at a given time. Frame size for unspecified format
+ * (AUDIO_FORMAT_OTHER) is 8 bit by definition.
+ */
+struct AudioBuffer {
+    uint64_t id;
+    uint32_t frameCount;
+    memory data;
+};
+
+@export(name="effect_buffer_access_e", value_prefix="EFFECT_BUFFER_")
+enum EffectBufferAccess : int32_t {
+    ACCESS_WRITE,
+    ACCESS_READ,
+    ACCESS_ACCUMULATE
+};
+
+/**
+ * Determines what fields of EffectBufferConfig need to be considered.
+ */
+@export(name="", value_prefix="EFFECT_CONFIG_")
+enum EffectConfigParameters : int32_t {
+    BUFFER = 0x0001,    // buffer field
+    SMP_RATE = 0x0002,  // samplingRate
+    CHANNELS = 0x0004,  // channels
+    FORMAT = 0x0008,    // format
+    ACC_MODE = 0x0010,  // accessMode
+    // Note that the 2.0 ALL have been moved to an helper function
+};
+
+/**
+ * The buffer config structure specifies the input or output audio format
+ * to be used by the effect engine.
+ */
+struct EffectBufferConfig {
+    AudioBuffer buffer;
+    uint32_t samplingRateHz;
+    bitfield<AudioChannelMask> channels;
+    AudioFormat format;
+    EffectBufferAccess accessMode;
+    bitfield<EffectConfigParameters> mask;
+};
+
+struct EffectConfig {
+    EffectBufferConfig inputCfg;
+    EffectBufferConfig outputCfg;
+};
+
+@export(name="effect_feature_e", value_prefix="EFFECT_FEATURE_")
+enum EffectFeature : int32_t {
+    AUX_CHANNELS, // supports auxiliary channels
+                  // (e.g. dual mic noise suppressor)
+    CNT
+};
+
+struct EffectAuxChannelsConfig {
+    bitfield<AudioChannelMask> mainChannels;  // channel mask for main channels
+    bitfield<AudioChannelMask> auxChannels;   // channel mask for auxiliary channels
+};
+
+struct EffectOffloadParameter {
+    bool isOffload;          // true if the playback thread the effect
+                             // is attached to is offloaded
+    AudioIoHandle ioHandle;  // io handle of the playback thread
+                             // the effect is attached to
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * the status message queue used by effects.
+ */
+enum MessageQueueFlagBits : uint32_t {
+    DONE_PROCESSING = 1 << 0,
+    REQUEST_PROCESS = 1 << 1,
+    REQUEST_PROCESS_REVERSE = 1 << 2,
+    REQUEST_QUIT = 1 << 3,
+    REQUEST_PROCESS_ALL =
+        REQUEST_PROCESS | REQUEST_PROCESS_REVERSE | REQUEST_QUIT
+};
diff --git a/audio/effect/6.0/xml/Android.bp b/audio/effect/6.0/xml/Android.bp
new file mode 100644
index 0000000..353686b
--- /dev/null
+++ b/audio/effect/6.0/xml/Android.bp
@@ -0,0 +1,6 @@
+
+xsd_config {
+    name: "audio_effects_conf_V6_0",
+    srcs: ["audio_effects_conf.xsd"],
+    package_name: "audio.effects.V6_0",
+}
diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt
new file mode 100644
index 0000000..2021639
--- /dev/null
+++ b/audio/effect/6.0/xml/api/current.txt
@@ -0,0 +1,132 @@
+// Signature format: 2.0
+package audio.effects.V6_0 {
+
+  public class AudioEffectsConf {
+    ctor public AudioEffectsConf();
+    method public audio.effects.V6_0.EffectsType getEffects();
+    method public audio.effects.V6_0.LibrariesType getLibraries();
+    method public audio.effects.V6_0.AudioEffectsConf.Postprocess getPostprocess();
+    method public audio.effects.V6_0.AudioEffectsConf.Preprocess getPreprocess();
+    method public audio.effects.V6_0.VersionType getVersion();
+    method public void setEffects(audio.effects.V6_0.EffectsType);
+    method public void setLibraries(audio.effects.V6_0.LibrariesType);
+    method public void setPostprocess(audio.effects.V6_0.AudioEffectsConf.Postprocess);
+    method public void setPreprocess(audio.effects.V6_0.AudioEffectsConf.Preprocess);
+    method public void setVersion(audio.effects.V6_0.VersionType);
+  }
+
+  public static class AudioEffectsConf.Postprocess {
+    ctor public AudioEffectsConf.Postprocess();
+    method public java.util.List<audio.effects.V6_0.StreamPostprocessType> getStream();
+  }
+
+  public static class AudioEffectsConf.Preprocess {
+    ctor public AudioEffectsConf.Preprocess();
+    method public java.util.List<audio.effects.V6_0.StreamPreprocessType> getStream();
+  }
+
+  public class EffectImplType {
+    ctor public EffectImplType();
+    method public String getLibrary();
+    method public String getUuid();
+    method public void setLibrary(String);
+    method public void setUuid(String);
+  }
+
+  public class EffectProxyType extends audio.effects.V6_0.EffectType {
+    ctor public EffectProxyType();
+    method public audio.effects.V6_0.EffectImplType getLibhw();
+    method public audio.effects.V6_0.EffectImplType getLibsw();
+    method public void setLibhw(audio.effects.V6_0.EffectImplType);
+    method public void setLibsw(audio.effects.V6_0.EffectImplType);
+  }
+
+  public class EffectType extends audio.effects.V6_0.EffectImplType {
+    ctor public EffectType();
+    method public String getName();
+    method public void setName(String);
+  }
+
+  public class EffectsType {
+    ctor public EffectsType();
+    method public java.util.List<audio.effects.V6_0.EffectProxyType> getEffectProxy_optional();
+    method public java.util.List<audio.effects.V6_0.EffectType> getEffect_optional();
+  }
+
+  public class LibrariesType {
+    ctor public LibrariesType();
+    method public java.util.List<audio.effects.V6_0.LibrariesType.Library> getLibrary();
+  }
+
+  public static class LibrariesType.Library {
+    ctor public LibrariesType.Library();
+    method public String getName();
+    method public String getPath();
+    method public void setName(String);
+    method public void setPath(String);
+  }
+
+  public enum StreamInputType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V6_0.StreamInputType camcorder;
+    enum_constant public static final audio.effects.V6_0.StreamInputType mic;
+    enum_constant public static final audio.effects.V6_0.StreamInputType unprocessed;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_call;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_communication;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_downlink;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_performance;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_recognition;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_uplink;
+  }
+
+  public enum StreamOutputType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V6_0.StreamOutputType alarm;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType bluetooth_sco;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType dtmf;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType enforced_audible;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType music;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType notification;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType ring;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType system;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType tts;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType voice_call;
+  }
+
+  public class StreamPostprocessType extends audio.effects.V6_0.StreamProcessingType {
+    ctor public StreamPostprocessType();
+    method public audio.effects.V6_0.StreamOutputType getType();
+    method public void setType(audio.effects.V6_0.StreamOutputType);
+  }
+
+  public class StreamPreprocessType extends audio.effects.V6_0.StreamProcessingType {
+    ctor public StreamPreprocessType();
+    method public audio.effects.V6_0.StreamInputType getType();
+    method public void setType(audio.effects.V6_0.StreamInputType);
+  }
+
+  public class StreamProcessingType {
+    ctor public StreamProcessingType();
+    method public java.util.List<audio.effects.V6_0.StreamProcessingType.Apply> getApply();
+  }
+
+  public static class StreamProcessingType.Apply {
+    ctor public StreamProcessingType.Apply();
+    method public String getEffect();
+    method public void setEffect(String);
+  }
+
+  public enum VersionType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V6_0.VersionType _2_0;
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static audio.effects.V6_0.AudioEffectsConf read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/tests/pointer/1.0/.hidl_for_test b/audio/effect/6.0/xml/api/last_current.txt
similarity index 100%
copy from tests/pointer/1.0/.hidl_for_test
copy to audio/effect/6.0/xml/api/last_current.txt
diff --git a/tests/pointer/1.0/.hidl_for_test b/audio/effect/6.0/xml/api/last_removed.txt
similarity index 100%
copy from tests/pointer/1.0/.hidl_for_test
copy to audio/effect/6.0/xml/api/last_removed.txt
diff --git a/audio/effect/6.0/xml/api/removed.txt b/audio/effect/6.0/xml/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/effect/6.0/xml/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
new file mode 120000
index 0000000..9d85fa7
--- /dev/null
+++ b/audio/effect/6.0/xml/audio_effects_conf.xsd
@@ -0,0 +1 @@
+../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/audio/effect/all-versions/default/Android.bp b/audio/effect/all-versions/default/Android.bp
index f23a463..d9bb78b 100644
--- a/audio/effect/all-versions/default/Android.bp
+++ b/audio/effect/all-versions/default/Android.bp
@@ -28,7 +28,6 @@
         "libfmq",
         "libhidlbase",
         "libhidlmemory",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.audio.common-util",
@@ -53,7 +52,6 @@
         "android.hardware.audio.common@2.0-util",
         "android.hardware.audio.effect@2.0",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=2",
         "-DMINOR_VERSION=0",
@@ -69,7 +67,6 @@
         "android.hardware.audio.common@4.0-util",
         "android.hardware.audio.effect@4.0",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=4",
         "-DMINOR_VERSION=0",
@@ -85,10 +82,24 @@
         "android.hardware.audio.common@5.0-util",
         "android.hardware.audio.effect@5.0",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=5",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
     ]
 }
+
+cc_library_shared {
+    name: "android.hardware.audio.effect@6.0-impl",
+    defaults: ["android.hardware.audio.effect-impl_default"],
+    shared_libs: [
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.common@6.0-util",
+        "android.hardware.audio.effect@6.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index 3c0d878..33ec996 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -138,11 +138,11 @@
 const char* Effect::sContextCallFunction = sContextCallToCommand;
 
 Effect::Effect(effect_handle_t handle)
-    : mIsClosed(false), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {}
+    : mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {}
 
 Effect::~Effect() {
     ATRACE_CALL();
-    close();
+    (void)close();
     if (mProcessThread.get()) {
         ATRACE_NAME("mProcessThread->join");
         status_t status = mProcessThread->join();
@@ -154,8 +154,10 @@
     }
     mInBuffer.clear();
     mOutBuffer.clear();
+#if MAJOR_VERSION <= 5
     int status = EffectRelease(mHandle);
     ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
+#endif
     EffectMap::getInstance().remove(mHandle);
     mHandle = 0;
 }
@@ -699,15 +701,23 @@
 }
 
 Return<Result> Effect::close() {
-    if (mIsClosed) return Result::INVALID_STATE;
-    mIsClosed = true;
-    if (mProcessThread.get()) {
-        mStopProcessThread.store(true, std::memory_order_release);
+    if (mStopProcessThread.load(std::memory_order_relaxed)) {  // only this thread modifies
+        return Result::INVALID_STATE;
     }
+    mStopProcessThread.store(true, std::memory_order_release);
     if (mEfGroup) {
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT));
     }
+#if MAJOR_VERSION <= 5
     return Result::OK;
+#elif MAJOR_VERSION >= 6
+    // No need to join the processing thread, it is part of the API contract that the client
+    // must finish processing before closing the effect.
+    Result retval =
+            analyzeStatus("EffectRelease", "", sContextCallFunction, EffectRelease(mHandle));
+    EffectMap::getInstance().remove(mHandle);
+    return retval;
+#endif
 }
 
 Return<void> Effect::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /* options */) {
diff --git a/audio/effect/all-versions/default/Effect.h b/audio/effect/all-versions/default/Effect.h
index 3d99a0e..181e542 100644
--- a/audio/effect/all-versions/default/Effect.h
+++ b/audio/effect/all-versions/default/Effect.h
@@ -170,7 +170,6 @@
     static const char* sContextCallToCommand;
     static const char* sContextCallFunction;
 
-    bool mIsClosed;
     effect_handle_t mHandle;
     sp<AudioBufferWrapper> mInBuffer;
     sp<AudioBufferWrapper> mOutBuffer;
diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp
index cccb5c8..edc9076 100644
--- a/audio/effect/all-versions/vts/functional/Android.bp
+++ b/audio/effect/all-versions/vts/functional/Android.bp
@@ -76,3 +76,16 @@
     ]
 }
 
+cc_test {
+    name: "VtsHalAudioEffectV6_0TargetTest",
+    defaults: ["VtsHalAudioEffectTargetTest_default"],
+    static_libs: [
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.effect@6.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index c4c7f7c..3c712b5 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -28,8 +28,14 @@
 
 #include <common/all-versions/VersionUtils.h>
 
+#if MAJOR_VERSION <= 5
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
+#elif MAJOR_VERSION >= 6
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#endif
 
 using ::android::sp;
 using ::android::hardware::hidl_handle;
@@ -49,6 +55,11 @@
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 #endif
 
+#if MAJOR_VERSION <= 5
+// For HAL versions 2..5 Vts Environment and Test base classes are used.
+// The tests are non-parametrized.
+#define EFFECT_TEST TEST_F
+
 // Test environment for Audio Effects Factory HIDL HAL.
 class AudioEffectsFactoryHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
    public:
@@ -71,6 +82,18 @@
         ASSERT_NE(effectsFactory, nullptr);
     }
 
+#elif MAJOR_VERSION >= 6
+// For HAL version 6 and above, standard GTest Environment and Test base classes are used.
+// The tests are parametrized by the IEffectsFactory instance name.
+#define EFFECT_TEST TEST_P
+
+class AudioEffectsFactoryHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        effectsFactory = IEffectsFactory::getService(GetParam());
+        ASSERT_NE(effectsFactory, nullptr);
+    }
+#endif  // The rest of the AudioEffectsFactoryHidlTest class definition is the same.
     void TearDown() override { effectsFactory.clear(); }
 
    protected:
@@ -81,7 +104,7 @@
     sp<IEffectsFactory> effectsFactory;
 };
 
-TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, EnumerateEffects) {
     description("Verify that EnumerateEffects returns at least one effect");
     Result retval = Result::NOT_INITIALIZED;
     size_t effectCount = 0;
@@ -95,7 +118,7 @@
     EXPECT_GT(effectCount, 0u);
 }
 
-TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, CreateEffect) {
     description("Verify that an effect can be created via CreateEffect");
     bool gotEffect = false;
     Uuid effectUuid;
@@ -123,7 +146,7 @@
     EXPECT_NE(nullptr, effect.get());
 }
 
-TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, GetDescriptor) {
     description(
         "Verify that effects factory can provide an effect descriptor via "
         "GetDescriptor");
@@ -146,7 +169,7 @@
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) {
     description("Verify that debugDump doesn't crash on invalid arguments");
 #if MAJOR_VERSION == 2
     Return<void> ret = effectsFactory->debugDump(hidl_handle());
@@ -168,10 +191,17 @@
     std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}};
 
 // The main test class for Audio Effect HIDL HAL.
+#if MAJOR_VERSION <= 5
 class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    public:
     void SetUp() override {
         effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>();
+#elif MAJOR_VERSION >= 6
+class AudioEffectHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        effectsFactory = IEffectsFactory::getService(GetParam());
+#endif
         ASSERT_NE(nullptr, effectsFactory.get());
 
         findAndCreateEffect(getEffectType());
@@ -250,14 +280,14 @@
         static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels));
 }
 
-TEST_F(AudioEffectHidlTest, Close) {
+EFFECT_TEST(AudioEffectHidlTest, Close) {
     description("Verify that an effect can be closed");
     Return<Result> ret = effect->close();
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
 
-TEST_F(AudioEffectHidlTest, GetDescriptor) {
+EFFECT_TEST(AudioEffectHidlTest, GetDescriptor) {
     description("Verify that an effect can return its own descriptor via GetDescriptor");
     Result retval = Result::NOT_INITIALIZED;
     Uuid actualType;
@@ -272,7 +302,7 @@
     EXPECT_EQ(getEffectType(), actualType);
 }
 
-TEST_F(AudioEffectHidlTest, GetSetConfig) {
+EFFECT_TEST(AudioEffectHidlTest, GetSetConfig) {
     description(
         "Verify that it is possible to manipulate effect config via Get / "
         "SetConfig");
@@ -291,26 +321,26 @@
     EXPECT_EQ(Result::OK, ret2);
 }
 
-TEST_F(AudioEffectHidlTest, GetConfigReverse) {
+EFFECT_TEST(AudioEffectHidlTest, GetConfigReverse) {
     description("Verify that GetConfigReverse does not crash");
     Return<void> ret = effect->getConfigReverse([&](Result, const EffectConfig&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) {
+EFFECT_TEST(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) {
     description("Verify that GetSupportedAuxChannelsConfigs does not crash");
     Return<void> ret = effect->getSupportedAuxChannelsConfigs(
         0, [&](Result, const hidl_vec<EffectAuxChannelsConfig>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) {
+EFFECT_TEST(AudioEffectHidlTest, GetAuxChannelsConfig) {
     description("Verify that GetAuxChannelsConfig does not crash");
     Return<void> ret = effect->getAuxChannelsConfig([&](Result, const EffectAuxChannelsConfig&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) {
+EFFECT_TEST(AudioEffectHidlTest, SetAuxChannelsConfig) {
     description("Verify that SetAuxChannelsConfig does not crash");
     Return<Result> ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig());
     EXPECT_TRUE(ret.isOk());
@@ -349,7 +379,7 @@
 }  // namespace hardware
 }  // namespace android
 
-TEST_F(AudioEffectHidlTest, Reset) {
+EFFECT_TEST(AudioEffectHidlTest, Reset) {
     description("Verify that Reset preserves effect configuration");
     Result retval = Result::NOT_INITIALIZED;
     EffectConfig originalConfig;
@@ -374,7 +404,7 @@
     EXPECT_EQ(originalConfig, configAfterReset);
 }
 
-TEST_F(AudioEffectHidlTest, DisableEnableDisable) {
+EFFECT_TEST(AudioEffectHidlTest, DisableEnableDisable) {
     description("Verify Disable -> Enable -> Disable sequence for an effect");
     Return<Result> ret = effect->disable();
     EXPECT_TRUE(ret.isOk());
@@ -387,14 +417,14 @@
     EXPECT_EQ(Result::OK, ret);
 }
 
-TEST_F(AudioEffectHidlTest, SetDevice) {
+EFFECT_TEST(AudioEffectHidlTest, SetDevice) {
     description("Verify that SetDevice works for an output chain effect");
     Return<Result> ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER));
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
 
-TEST_F(AudioEffectHidlTest, SetAndGetVolume) {
+EFFECT_TEST(AudioEffectHidlTest, SetAndGetVolume) {
     description("Verify that SetAndGetVolume method works for an effect");
     uint32_t channelCount;
     getChannelCount(&channelCount);
@@ -410,7 +440,7 @@
     EXPECT_EQ(Result::OK, retval);
 }
 
-TEST_F(AudioEffectHidlTest, VolumeChangeNotification) {
+EFFECT_TEST(AudioEffectHidlTest, VolumeChangeNotification) {
     description("Verify that effect accepts VolumeChangeNotification");
     uint32_t channelCount;
     getChannelCount(&channelCount);
@@ -424,32 +454,32 @@
     EXPECT_EQ(Result::OK, ret);
 }
 
-TEST_F(AudioEffectHidlTest, SetAudioMode) {
+EFFECT_TEST(AudioEffectHidlTest, SetAudioMode) {
     description("Verify that SetAudioMode works for an effect");
     Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL);
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
 
-TEST_F(AudioEffectHidlTest, SetConfigReverse) {
+EFFECT_TEST(AudioEffectHidlTest, SetConfigReverse) {
     description("Verify that SetConfigReverse does not crash");
     Return<Result> ret = effect->setConfigReverse(EffectConfig(), nullptr, nullptr);
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, SetInputDevice) {
+EFFECT_TEST(AudioEffectHidlTest, SetInputDevice) {
     description("Verify that SetInputDevice does not crash");
     Return<Result> ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC));
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, SetAudioSource) {
+EFFECT_TEST(AudioEffectHidlTest, SetAudioSource) {
     description("Verify that SetAudioSource does not crash");
     Return<Result> ret = effect->setAudioSource(AudioSource::MIC);
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, Offload) {
+EFFECT_TEST(AudioEffectHidlTest, Offload) {
     description("Verify that calling Offload method does not crash");
     EffectOffloadParameter offloadParam;
     offloadParam.isOffload = false;
@@ -458,7 +488,7 @@
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, PrepareForProcessing) {
+EFFECT_TEST(AudioEffectHidlTest, PrepareForProcessing) {
     description("Verify that PrepareForProcessing method works for an effect");
     Result retval = Result::NOT_INITIALIZED;
     Return<void> ret = effect->prepareForProcessing(
@@ -467,7 +497,7 @@
     EXPECT_EQ(Result::OK, retval);
 }
 
-TEST_F(AudioEffectHidlTest, SetProcessBuffers) {
+EFFECT_TEST(AudioEffectHidlTest, SetProcessBuffers) {
     description("Verify that SetProcessBuffers works for an effect");
     sp<IAllocator> ashmem = IAllocator::getService("ashmem");
     ASSERT_NE(nullptr, ashmem.get());
@@ -486,41 +516,41 @@
     EXPECT_EQ(Result::OK, ret2);
 }
 
-TEST_F(AudioEffectHidlTest, Command) {
+EFFECT_TEST(AudioEffectHidlTest, Command) {
     description("Verify that Command does not crash");
     Return<void> ret =
         effect->command(0, hidl_vec<uint8_t>(), 0, [&](int32_t, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, SetParameter) {
+EFFECT_TEST(AudioEffectHidlTest, SetParameter) {
     description("Verify that SetParameter does not crash");
     Return<Result> ret = effect->setParameter(hidl_vec<uint8_t>(), hidl_vec<uint8_t>());
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, GetParameter) {
+EFFECT_TEST(AudioEffectHidlTest, GetParameter) {
     description("Verify that GetParameter does not crash");
     Return<void> ret =
         effect->getParameter(hidl_vec<uint8_t>(), 0, [&](Result, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
+EFFECT_TEST(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
     description("Verify that GetSupportedConfigsForFeature does not crash");
     Return<void> ret = effect->getSupportedConfigsForFeature(
         0, 0, 0, [&](Result, uint32_t, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) {
+EFFECT_TEST(AudioEffectHidlTest, GetCurrentConfigForFeature) {
     description("Verify that GetCurrentConfigForFeature does not crash");
     Return<void> ret =
         effect->getCurrentConfigForFeature(0, 0, [&](Result, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) {
+EFFECT_TEST(AudioEffectHidlTest, SetCurrentConfigForFeature) {
     description("Verify that SetCurrentConfigForFeature does not crash");
     Return<Result> ret = effect->setCurrentConfigForFeature(0, hidl_vec<uint8_t>());
     EXPECT_TRUE(ret.isOk());
@@ -606,21 +636,21 @@
     ASSERT_EQ(Result::OK, retval);
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetNumBands) {
     description("Verify that Equalizer effect reports at least one band");
     uint16_t numBands = 0;
     getNumBands(&numBands);
     EXPECT_GT(numBands, 0);
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetLevelRange) {
     description("Verify that Equalizer effect reports adequate band level range");
     int16_t minLevel = 0x7fff, maxLevel = 0;
     getLevelRange(&minLevel, &maxLevel);
     EXPECT_GT(maxLevel, minLevel);
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
     description("Verify that manipulating band levels works for Equalizer effect");
     uint16_t numBands = 0;
     getNumBands(&numBands);
@@ -649,7 +679,7 @@
     }
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
     description("Verify that Equalizer effect reports adequate band frequency range");
     uint16_t numBands = 0;
     getNumBands(&numBands);
@@ -664,7 +694,7 @@
     }
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
     description("Verify that Equalizer effect supports GetBandForFrequency correctly");
     uint16_t numBands = 0;
     getNumBands(&numBands);
@@ -693,14 +723,14 @@
     }
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetPresetNames) {
     description("Verify that Equalizer effect reports at least one preset");
     size_t presetCount;
     getPresetCount(&presetCount);
     EXPECT_GT(presetCount, 0u);
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
     description("Verify that manipulating the current preset for Equalizer effect");
     size_t presetCount;
     getPresetCount(&presetCount);
@@ -723,7 +753,7 @@
     }
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
     description(
         "Verify that setting band levels and presets works via Get / "
         "SetAllProperties for Equalizer effect");
@@ -787,7 +817,7 @@
     sp<ILoudnessEnhancerEffect> enhancer;
 };
 
-TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
+EFFECT_TEST(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
     description(
         "Verify that manipulating the target gain works for Loudness Enhancer "
         "effect");
@@ -808,6 +838,7 @@
     EXPECT_EQ(gain, actualGain);
 }
 
+#if MAJOR_VERSION <= 5
 int main(int argc, char** argv) {
     ::testing::AddGlobalTestEnvironment(AudioEffectsFactoryHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
@@ -816,3 +847,17 @@
     LOG(INFO) << "Test result = " << status;
     return status;
 }
+#elif MAJOR_VERSION >= 6
+INSTANTIATE_TEST_SUITE_P(
+        EffectsFactory, AudioEffectsFactoryHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(
+        Equalizer, EqualizerAudioEffectHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(
+        LoudnessEnhancer, LoudnessEnhancerAudioEffectHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+#endif
diff --git a/authsecret/1.0/Android.bp b/authsecret/1.0/Android.bp
index 9cde99a..3b84c3b 100644
--- a/authsecret/1.0/Android.bp
+++ b/authsecret/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/authsecret/1.0/default/Android.bp b/authsecret/1.0/default/Android.bp
index 5c3234f..b6ea3c4 100644
--- a/authsecret/1.0/default/Android.bp
+++ b/authsecret/1.0/default/Android.bp
@@ -13,7 +13,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.authsecret@1.0",
diff --git a/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc b/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc
index e82da7e..1a95cd0 100644
--- a/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc
+++ b/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.authsecret-1-0 /vendor/bin/hw/android.hardware.authsecret@1.0-service
+    interface android.hardware.authsecret@1.0::IAuthSecret default
     class hal
     user system
     group system
diff --git a/authsecret/1.0/vts/functional/Android.bp b/authsecret/1.0/vts/functional/Android.bp
index f2b3a8a..9ce9cda 100644
--- a/authsecret/1.0/vts/functional/Android.bp
+++ b/authsecret/1.0/vts/functional/Android.bp
@@ -19,5 +19,9 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalAuthSecretV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.authsecret@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+    require_root: true,
 }
diff --git a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
index 255d4de..0bff9df 100644
--- a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
+++ b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
@@ -16,36 +16,22 @@
 
 #include <android/hardware/authsecret/1.0/IAuthSecret.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 using ::android::hardware::hidl_vec;
 using ::android::hardware::authsecret::V1_0::IAuthSecret;
 using ::android::sp;
 
-// Test environment for Boot HIDL HAL.
-class AuthSecretHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static AuthSecretHidlEnvironment* Instance() {
-        static AuthSecretHidlEnvironment* instance = new AuthSecretHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IAuthSecret>(); }
-
-   private:
-    AuthSecretHidlEnvironment() {}
-};
-
 /**
  * There is no expected behaviour that can be tested so these tests check the
  * HAL doesn't crash with different execution orders.
  */
-struct AuthSecretHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class AuthSecretHidlTest : public testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override {
-        authsecret = ::testing::VtsHalHidlTargetTestBase::getService<IAuthSecret>(
-            AuthSecretHidlEnvironment::Instance()->getServiceName<IAuthSecret>());
+        authsecret = IAuthSecret::getService(GetParam());
         ASSERT_NE(authsecret, nullptr);
 
         // All tests must enroll the correct secret first as this cannot be changed
@@ -59,18 +45,18 @@
 };
 
 /* Provision the primary user with a secret. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredential) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredential) {
     // Secret provisioned by SetUp()
 }
 
 /* Provision the primary user with a secret and pass the secret again. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgain) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgain) {
     // Secret provisioned by SetUp()
     authsecret->primaryUserCredential(CORRECT_SECRET);
 }
 
 /* Provision the primary user with a secret and pass the secret again repeatedly. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgainMultipleTimes) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgainMultipleTimes) {
     // Secret provisioned by SetUp()
     constexpr int N = 5;
     for (int i = 0; i < N; ++i) {
@@ -82,16 +68,12 @@
  * should never happen and is an framework bug if it does. As the secret is
  * wrong, the HAL implementation may not be able to function correctly but it
  * should fail gracefully. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndWrongSecret) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredentialAndWrongSecret) {
     // Secret provisioned by SetUp()
     authsecret->primaryUserCredential(WRONG_SECRET);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(AuthSecretHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    AuthSecretHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, AuthSecretHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAuthSecret::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/automotive/audiocontrol/1.0/Android.bp b/automotive/audiocontrol/1.0/Android.bp
index 7c51cf7..7ef7909 100644
--- a/automotive/audiocontrol/1.0/Android.bp
+++ b/automotive/audiocontrol/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/automotive/audiocontrol/1.0/default/Android.bp b/automotive/audiocontrol/1.0/default/Android.bp
index 0e074dd..314830b 100644
--- a/automotive/audiocontrol/1.0/default/Android.bp
+++ b/automotive/audiocontrol/1.0/default/Android.bp
@@ -26,7 +26,6 @@
     shared_libs: [
         "android.hardware.automotive.audiocontrol@1.0",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
diff --git a/automotive/evs/1.0/Android.bp b/automotive/evs/1.0/Android.bp
index 3ac67ea..51f8e20 100644
--- a/automotive/evs/1.0/Android.bp
+++ b/automotive/evs/1.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/automotive/evs/1.0/default/Android.bp b/automotive/evs/1.0/default/Android.bp
index 7286478..69bb721 100644
--- a/automotive/evs/1.0/default/Android.bp
+++ b/automotive/evs/1.0/default/Android.bp
@@ -18,7 +18,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libui",
         "libutils",
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp
index 4163879..0e73d85 100644
--- a/automotive/vehicle/2.0/Android.bp
+++ b/automotive/vehicle/2.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index a11d452..ed09859 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -16,7 +16,6 @@
     name: "vhal_v2_0_defaults",
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.automotive.vehicle@2.0",
@@ -72,10 +71,10 @@
     whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"],
     shared_libs: [
         "libbase",
+        "libjsoncpp",
         "libprotobuf-cpp-lite",
     ],
     static_libs: [
-        "libjsoncpp",
         "libqemu_pipe",
         "android.hardware.automotive.vehicle@2.0-libproto-native",
     ],
@@ -107,13 +106,13 @@
     srcs: ["VehicleService.cpp"],
     shared_libs: [
         "libbase",
+        "libjsoncpp",
         "libprotobuf-cpp-lite",
     ],
     static_libs: [
         "android.hardware.automotive.vehicle@2.0-manager-lib",
         "android.hardware.automotive.vehicle@2.0-default-impl-lib",
         "android.hardware.automotive.vehicle@2.0-libproto-native",
-        "libjsoncpp",
         "libqemu_pipe",
     ],
 }
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 77053cf..8a89322 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,679 +162,718 @@
 };
 
 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::DISTANCE_DISPLAY_UNITS),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .configArray = {(int)VehicleUnit::KILOMETER, (int)VehicleUnit::MILE},
-                .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}},
-     .initialValue = {.int32Values = {(int)VehicleUnit::MILE}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::DISTANCE_DISPLAY_UNITS),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .configArray = {(int)VehicleUnit::KILOMETER, (int)VehicleUnit::MILE},
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}
+                 },
+         .initialValue = {.int32Values = {(int)VehicleUnit::MILE}}},
 
-    {.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::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/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
index a291351..4e3ade1 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
@@ -57,11 +57,11 @@
 };
 
 TEST_F(VehicleObjectPoolTest, valuePoolBasicCorrectness) {
-    void* raw = valuePool->obtain(VehiclePropertyType::INT32).get();
+    auto value = valuePool->obtain(VehiclePropertyType::INT32);
     // At this point, v1 should be recycled and the only object in the pool.
-    ASSERT_EQ(raw, valuePool->obtain(VehiclePropertyType::INT32).get());
+    ASSERT_EQ(value.get(), valuePool->obtain(VehiclePropertyType::INT32).get());
     // Obtaining value of another type - should return a new object
-    ASSERT_NE(raw, valuePool->obtain(VehiclePropertyType::FLOAT).get());
+    ASSERT_NE(value.get(), valuePool->obtain(VehiclePropertyType::FLOAT).get());
 
     ASSERT_EQ(3u, stats->Obtained);
     ASSERT_EQ(2u, stats->Created);
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index f6ebcdd..0f20dd1 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -1282,7 +1282,7 @@
 
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:WRITE
+     * @access VehiclePropertyAccess:READ_WRITE
      */
     AP_POWER_STATE_REPORT = (
         0x0A01
diff --git a/biometrics/face/1.0/Android.bp b/biometrics/face/1.0/Android.bp
index 222a09e..ebb8668 100644
--- a/biometrics/face/1.0/Android.bp
+++ b/biometrics/face/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/biometrics/face/1.0/vts/functional/Android.bp b/biometrics/face/1.0/vts/functional/Android.bp
index fa68c4e..f2598a7 100644
--- a/biometrics/face/1.0/vts/functional/Android.bp
+++ b/biometrics/face/1.0/vts/functional/Android.bp
@@ -19,6 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalBiometricsFaceV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.biometrics.face@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
index d3d7387..7ac44a4 100644
--- a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
+++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
@@ -20,9 +20,10 @@
 #include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <chrono>
 #include <cstdint>
@@ -64,7 +65,7 @@
     // The error passed to the last onError() callback.
     FaceError error;
 
-    // The userId passed to the last onRemoved() callback.
+    // The userId passed to the last callback.
     int32_t userId;
 };
 
@@ -74,24 +75,32 @@
 class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
                      public IBiometricsFaceClientCallback {
   public:
-    Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override {
-        NotifyFromCallback(kCallbackNameOnEnrollResult);
+    Return<void> onEnrollResult(uint64_t, uint32_t, int32_t userId, uint32_t) override {
+        FaceCallbackArgs args = {};
+        args.userId = userId;
+        NotifyFromCallback(kCallbackNameOnEnrollResult, args);
         return Void();
     }
 
-    Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
-        NotifyFromCallback(kCallbackNameOnAuthenticated);
+    Return<void> onAuthenticated(uint64_t, uint32_t, int32_t userId,
+                                 const hidl_vec<uint8_t>&) override {
+        FaceCallbackArgs args = {};
+        args.userId = userId;
+        NotifyFromCallback(kCallbackNameOnAuthenticated, args);
         return Void();
     }
 
-    Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
-        NotifyFromCallback(kCallbackNameOnAcquired);
+    Return<void> onAcquired(uint64_t, int32_t userId, FaceAcquiredInfo, int32_t) override {
+        FaceCallbackArgs args = {};
+        args.userId = userId;
+        NotifyFromCallback(kCallbackNameOnAcquired, args);
         return Void();
     }
 
-    Return<void> onError(uint64_t, int32_t, FaceError error, int32_t) override {
+    Return<void> onError(uint64_t, int32_t userId, FaceError error, int32_t) override {
         FaceCallbackArgs args = {};
         args.error = error;
+        args.userId = userId;
         NotifyFromCallback(kCallbackNameOnError, args);
         return Void();
     }
@@ -103,8 +112,10 @@
         return Void();
     }
 
-    Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
-        NotifyFromCallback(kCallbackNameOnEnumerate);
+    Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t userId) override {
+        FaceCallbackArgs args = {};
+        args.userId = userId;
+        NotifyFromCallback(kCallbackNameOnEnumerate, args);
         return Void();
     }
 
@@ -114,27 +125,11 @@
     }
 };
 
-// Test environment for the BiometricsFace HAL.
-class FaceHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-  public:
-    // Get the test environment singleton.
-    static FaceHidlEnvironment* Instance() {
-        static FaceHidlEnvironment* instance = new FaceHidlEnvironment;
-        return instance;
-    }
-
-    void registerTestServices() override { registerTestService<IBiometricsFace>(); }
-
-  private:
-    FaceHidlEnvironment() = default;
-};
-
 // Test class for the BiometricsFace HAL.
-class FaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class FaceHidlTest : public ::testing::TestWithParam<std::string> {
   public:
     void SetUp() override {
-        mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFace>(
-                FaceHidlEnvironment::Instance()->getServiceName<IBiometricsFace>());
+        mService = IBiometricsFace::getService(GetParam());
         ASSERT_NE(mService, nullptr);
         mCallback = new FaceCallback();
         mCallback->SetWaitTimeoutDefault(kTimeout);
@@ -157,7 +152,7 @@
 
 // generateChallenge should always return a unique, cryptographically secure,
 // non-zero number.
-TEST_F(FaceHidlTest, GenerateChallengeTest) {
+TEST_P(FaceHidlTest, GenerateChallengeTest) {
     std::map<uint64_t, int> m;
     for (int i = 0; i < kGenerateChallengeIterations; ++i) {
         Return<void> ret =
@@ -172,7 +167,7 @@
 }
 
 // enroll with an invalid (all zeroes) HAT should fail.
-TEST_F(FaceHidlTest, EnrollZeroHatTest) {
+TEST_P(FaceHidlTest, EnrollZeroHatTest) {
     // Filling HAT with zeros
     hidl_vec<uint8_t> token(69);
     for (size_t i = 0; i < 69; i++) {
@@ -185,11 +180,12 @@
     // onError should be called with a meaningful (nonzero) error.
     auto res = mCallback->WaitForCallback(kCallbackNameOnError);
     EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
     EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
 }
 
 // enroll with an invalid HAT should fail.
-TEST_F(FaceHidlTest, EnrollGarbageHatTest) {
+TEST_P(FaceHidlTest, EnrollGarbageHatTest) {
     // Filling HAT with pseudorandom invalid data.
     // Using default seed to make the test reproducible.
     std::mt19937 gen(std::mt19937::default_seed);
@@ -205,11 +201,12 @@
     // onError should be called with a meaningful (nonzero) error.
     auto res = mCallback->WaitForCallback(kCallbackNameOnError);
     EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
     EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
 }
 
 // setFeature with an invalid (all zeros) HAT should fail.
-TEST_F(FaceHidlTest, SetFeatureZeroHatTest) {
+TEST_P(FaceHidlTest, SetFeatureZeroHatTest) {
     hidl_vec<uint8_t> token(69);
     for (size_t i = 0; i < 69; i++) {
         token[i] = 0;
@@ -220,7 +217,7 @@
 }
 
 // setFeature with an invalid HAT should fail.
-TEST_F(FaceHidlTest, SetFeatureGarbageHatTest) {
+TEST_P(FaceHidlTest, SetFeatureGarbageHatTest) {
     // Filling HAT with pseudorandom invalid data.
     // Using default seed to make the test reproducible.
     std::mt19937 gen(std::mt19937::default_seed);
@@ -242,16 +239,16 @@
     ASSERT_TRUE(res.isOk());
 }
 
-TEST_F(FaceHidlTest, GetFeatureRequireAttentionTest) {
+TEST_P(FaceHidlTest, GetFeatureRequireAttentionTest) {
     assertGetFeatureFails(mService, 0 /* faceId */, Feature::REQUIRE_ATTENTION);
 }
 
-TEST_F(FaceHidlTest, GetFeatureRequireDiversityTest) {
+TEST_P(FaceHidlTest, GetFeatureRequireDiversityTest) {
     assertGetFeatureFails(mService, 0 /* faceId */, Feature::REQUIRE_DIVERSITY);
 }
 
 // revokeChallenge should always return within the timeout
-TEST_F(FaceHidlTest, RevokeChallengeTest) {
+TEST_P(FaceHidlTest, RevokeChallengeTest) {
     auto start = std::chrono::system_clock::now();
     Return<Status> ret = mService->revokeChallenge();
     auto elapsed = std::chrono::system_clock::now() - start;
@@ -260,36 +257,37 @@
 }
 
 // The call to getAuthenticatorId should succeed.
-TEST_F(FaceHidlTest, GetAuthenticatorIdTest) {
+TEST_P(FaceHidlTest, GetAuthenticatorIdTest) {
     Return<void> ret = mService->getAuthenticatorId(
             [](const OptionalUint64& res) { ASSERT_EQ(Status::OK, res.status); });
     ASSERT_TRUE(ret.isOk());
 }
 
 // The call to enumerate should succeed.
-TEST_F(FaceHidlTest, EnumerateTest) {
+TEST_P(FaceHidlTest, EnumerateTest) {
     Return<Status> ret = mService->enumerate();
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
     auto res = mCallback->WaitForCallback(kCallbackNameOnEnumerate);
+    EXPECT_EQ(kUserId, res.args->userId);
     EXPECT_TRUE(res.no_timeout);
 }
 
 // The call to remove should succeed for any faceId
-TEST_F(FaceHidlTest, RemoveFaceTest) {
+TEST_P(FaceHidlTest, RemoveFaceTest) {
     // Remove a face
     Return<Status> ret = mService->remove(kFaceId);
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
 }
 
 // Remove should accept 0 to delete all faces
-TEST_F(FaceHidlTest, RemoveAllFacesTest) {
+TEST_P(FaceHidlTest, RemoveAllFacesTest) {
     // Remove all faces
     Return<Status> ret = mService->remove(0);
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
 }
 
 // Active user should successfully set to a writable location.
-TEST_F(FaceHidlTest, SetActiveUserTest) {
+TEST_P(FaceHidlTest, SetActiveUserTest) {
     // Create an active user
     Return<Status> ret = mService->setActiveUser(2, kFacedataDir);
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
@@ -300,7 +298,7 @@
 }
 
 // Active user should fail to set to an unwritable location.
-TEST_F(FaceHidlTest, SetActiveUserUnwritableTest) {
+TEST_P(FaceHidlTest, SetActiveUserUnwritableTest) {
     // Create an active user to an unwritable location (device root dir)
     Return<Status> ret = mService->setActiveUser(3, "/");
     ASSERT_NE(Status::OK, static_cast<Status>(ret));
@@ -311,7 +309,7 @@
 }
 
 // Active user should fail to set to a null location.
-TEST_F(FaceHidlTest, SetActiveUserNullTest) {
+TEST_P(FaceHidlTest, SetActiveUserNullTest) {
     // Create an active user to a null location.
     Return<Status> ret = mService->setActiveUser(4, nullptr);
     ASSERT_NE(Status::OK, static_cast<Status>(ret));
@@ -323,17 +321,18 @@
 
 // Cancel should always return CANCELED from any starting state including
 // the IDLE state.
-TEST_F(FaceHidlTest, CancelTest) {
+TEST_P(FaceHidlTest, CancelTest) {
     Return<Status> ret = mService->cancel();
     // check that we were able to make an IPC request successfully
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
     auto res = mCallback->WaitForCallback(kCallbackNameOnError);
     // make sure callback was invoked within kRevokeChallengeTimeout
     EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
     EXPECT_EQ(FaceError::CANCELED, res.args->error);
 }
 
-TEST_F(FaceHidlTest, OnLockoutChangedTest) {
+TEST_P(FaceHidlTest, OnLockoutChangedTest) {
     // Update active user and ensure onLockoutChanged was called.
     Return<Status> ret = mService->setActiveUser(kUserId + 1, kFacedataDir);
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
@@ -345,11 +344,7 @@
 
 }  // anonymous namespace
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(FaceHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    FaceHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, FaceHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/fingerprint/2.1/Android.bp b/biometrics/fingerprint/2.1/Android.bp
index cff43c4..c8cc0f1 100644
--- a/biometrics/fingerprint/2.1/Android.bp
+++ b/biometrics/fingerprint/2.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/biometrics/fingerprint/2.1/default/Android.bp b/biometrics/fingerprint/2.1/default/Android.bp
index b12ce61..497fa3f 100644
--- a/biometrics/fingerprint/2.1/default/Android.bp
+++ b/biometrics/fingerprint/2.1/default/Android.bp
@@ -13,7 +13,6 @@
         "libcutils",
         "liblog",
         "libhidlbase",
-        "libhidltransport",
         "libhardware",
         "libutils",
         "android.hardware.biometrics.fingerprint@2.1",
diff --git a/biometrics/fingerprint/2.1/vts/functional/Android.bp b/biometrics/fingerprint/2.1/vts/functional/Android.bp
index 60228f2..c418032 100644
--- a/biometrics/fingerprint/2.1/vts/functional/Android.bp
+++ b/biometrics/fingerprint/2.1/vts/functional/Android.bp
@@ -19,6 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalBiometricsFingerprintV2_1TargetTest.cpp"],
     static_libs: ["android.hardware.biometrics.fingerprint@2.1"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
index d577ce4..bdbf72d 100644
--- a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
+++ b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
@@ -16,14 +16,15 @@
 
 #define LOG_TAG "fingerprint_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
 #include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
 #include <utils/Condition.h>
 
 #include <cinttypes>
@@ -183,315 +184,295 @@
   std::promise<void> promise;
 };
 
-// Test environment for Fingerprint HIDL HAL.
-class FingerprintHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static FingerprintHidlEnvironment* Instance() {
-    static FingerprintHidlEnvironment* instance = new FingerprintHidlEnvironment;
-    return instance;
-  }
+class FingerprintHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = IBiometricsFingerprint::getService(GetParam());
+        ASSERT_FALSE(mService == nullptr);
 
-  virtual void registerTestServices() override { registerTestService<IBiometricsFingerprint>(); }
-};
+        /*
+         * Devices shipped from now on will instead store
+         * fingerprint data under /data/vendor_de/<user-id>/fpdata.
+         * Support for /data/vendor_de and /data/vendor_ce has been added to vold.
+         */
 
-class FingerprintHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
-  virtual void SetUp() override {
-    mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFingerprint>(
-        FingerprintHidlEnvironment::Instance()->getServiceName<IBiometricsFingerprint>());
-    ASSERT_FALSE(mService == nullptr);
+        uint64_t api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+        if (api_level == 0) {
+            api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+        }
+        ASSERT_TRUE(api_level != 0);
 
-    /*
-     * Devices shipped from now on will instead store
-     * fingerprint data under /data/vendor_de/<user-id>/fpdata.
-     * Support for /data/vendor_de and /data/vendor_ce has been added to vold.
-     */
+        // 27 is the API number for O-MR1
+        if (api_level <= 27) {
+            kTmpDir = "/data/system/users/0/fpdata/";
+        } else {
+            kTmpDir = "/data/vendor_de/0/fpdata/";
+        }
 
-    uint64_t api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
-    if (api_level == 0) {
-      api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
-    }
-    ASSERT_TRUE(api_level != 0);
-
-    // 27 is the API number for O-MR1
-    if (api_level <= 27) {
-      kTmpDir = "/data/system/users/0/fpdata/";
-    } else {
-      kTmpDir = "/data/vendor_de/0/fpdata/";
+        Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
+        ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
     }
 
-    Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
-    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
-  }
+    virtual void TearDown() override {}
 
-  virtual void TearDown() override {}
-
-  sp<IBiometricsFingerprint> mService;
+    sp<IBiometricsFingerprint> mService;
 };
 
-
 // The service should be reachable.
-TEST_F(FingerprintHidlTest, ConnectTest) {
-  sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase();
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, ConnectTest) {
+    sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase();
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0UL, static_cast<uint64_t>(rc));
 }
 
 // Starting the service with null callback should succeed.
-TEST_F(FingerprintHidlTest, ConnectNullTest) {
-  Return<uint64_t> rc = mService->setNotify(NULL);
-  ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, ConnectNullTest) {
+    Return<uint64_t> rc = mService->setNotify(NULL);
+    ASSERT_NE(0UL, static_cast<uint64_t>(rc));
 }
 
 // Pre-enroll should always return unique, cryptographically secure, non-zero number
-TEST_F(FingerprintHidlTest, PreEnrollTest) {
-  std::map<uint64_t, uint64_t> m;
+TEST_P(FingerprintHidlTest, PreEnrollTest) {
+    std::map<uint64_t, uint64_t> m;
 
-  for(unsigned int i = 0; i < kIterations; ++i) {
-    uint64_t res = static_cast<uint64_t>(mService->preEnroll());
-    EXPECT_NE(0UL, res);
-    m[res]++;
-    EXPECT_EQ(1UL, m[res]);
-  }
+    for (unsigned int i = 0; i < kIterations; ++i) {
+        uint64_t res = static_cast<uint64_t>(mService->preEnroll());
+        EXPECT_NE(0UL, res);
+        m[res]++;
+        EXPECT_EQ(1UL, m[res]);
+    }
 }
 
 // Enroll with an invalid (all zeroes) HAT should fail.
-TEST_F(FingerprintHidlTest, EnrollInvalidHatTest) {
-  sp<ErrorCallback> cb = new ErrorCallback();
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, EnrollInvalidHatTest) {
+    sp<ErrorCallback> cb = new ErrorCallback();
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0UL, static_cast<uint64_t>(rc));
 
-  uint8_t token[69];
-  for(int i=0; i<69; i++) {
-    token[i] = 0;
-  }
+    uint8_t token[69];
+    for (int i = 0; i < 69; i++) {
+        token[i] = 0;
+    }
 
-  Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // At least one call to onError should occur
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
-  ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error);
+    // At least one call to onError should occur
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error);
 }
 
 // Enroll with an invalid (null) HAT should fail.
-TEST_F(FingerprintHidlTest, EnrollNullTest) {
-  sp<ErrorCallback> cb = new ErrorCallback();
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, EnrollNullTest) {
+    sp<ErrorCallback> cb = new ErrorCallback();
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0UL, static_cast<uint64_t>(rc));
 
-  uint8_t token[69];
-  Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    uint8_t token[69];
+    Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // At least one call to onError should occur
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
-  ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error);
+    // At least one call to onError should occur
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error);
 }
 
 // PostEnroll should always return within 3s
-TEST_F(FingerprintHidlTest, PostEnrollTest) {
-  sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase();
-  Return<uint64_t> rc = mService->setNotify(cb);
+TEST_P(FingerprintHidlTest, PostEnrollTest) {
+    sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase();
+    Return<uint64_t> rc = mService->setNotify(cb);
 
-  auto start = std::chrono::system_clock::now();
-  Return<RequestStatus> res = mService->postEnroll();
-  auto elapsed = std::chrono::system_clock::now() - start;
-  ASSERT_GE(kTimeoutInSeconds, elapsed);
+    auto start = std::chrono::system_clock::now();
+    Return<RequestStatus> res = mService->postEnroll();
+    auto elapsed = std::chrono::system_clock::now() - start;
+    ASSERT_GE(kTimeoutInSeconds, elapsed);
 }
 
 // getAuthenticatorId should always return non-zero numbers
-TEST_F(FingerprintHidlTest, GetAuthenticatorIdTest) {
-  Return<uint64_t> res = mService->getAuthenticatorId();
-  EXPECT_NE(0UL, static_cast<uint64_t>(res));
+TEST_P(FingerprintHidlTest, GetAuthenticatorIdTest) {
+    Return<uint64_t> res = mService->getAuthenticatorId();
+    EXPECT_NE(0UL, static_cast<uint64_t>(res));
 }
 
 // Enumerate should always trigger onEnumerated(fid=0, rem=0) when there are no fingerprints
-TEST_F(FingerprintHidlTest, EnumerateTest) {
-  sp<EnumerateCallback> cb = new EnumerateCallback();
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, EnumerateTest) {
+    sp<EnumerateCallback> cb = new EnumerateCallback();
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0UL, static_cast<uint64_t>(rc));
 
-  // Callback will return when rem=0 is found
-  Return<RequestStatus> res = mService->enumerate();
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
-  EXPECT_EQ(0UL, cb->fingerId);
-  EXPECT_EQ(0UL, cb->remaining);
-
+    // Callback will return when rem=0 is found
+    Return<RequestStatus> res = mService->enumerate();
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    EXPECT_EQ(0UL, cb->fingerId);
+    EXPECT_EQ(0UL, cb->remaining);
 }
 
 // Remove should succeed on any inputs
 // At least one callback with "remaining=0" should occur
-TEST_F(FingerprintHidlTest, RemoveFingerprintTest) {
-  // Register callback
-  sp<RemoveCallback> cb = new RemoveCallback(kGroupId);
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, RemoveFingerprintTest) {
+    // Register callback
+    sp<RemoveCallback> cb = new RemoveCallback(kGroupId);
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0UL, static_cast<uint64_t>(rc));
 
-  // Remove a fingerprint
-  Return<RequestStatus> res = mService->remove(kGroupId, 1);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    // Remove a fingerprint
+    Return<RequestStatus> res = mService->remove(kGroupId, 1);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // At least one call to onRemove with remaining=0 should occur
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    // At least one call to onRemove with remaining=0 should occur
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
 }
 
 // Remove should accept 0 to delete all fingerprints
 // At least one callback with "remaining=0" should occur.
-TEST_F(FingerprintHidlTest, RemoveAllFingerprintsTest) {
-  // Register callback
-  sp<RemoveCallback> cb = new RemoveCallback(kGroupId);
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, RemoveAllFingerprintsTest) {
+    // Register callback
+    sp<RemoveCallback> cb = new RemoveCallback(kGroupId);
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0UL, static_cast<uint64_t>(rc));
 
-  // Remove all fingerprints
-  Return<RequestStatus> res = mService->remove(kGroupId, 0);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    // Remove all fingerprints
+    Return<RequestStatus> res = mService->remove(kGroupId, 0);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
 }
 
 // Active group should successfully set to a writable location.
-TEST_F(FingerprintHidlTest, SetActiveGroupTest) {
-  // Create an active group
-  Return<RequestStatus> res = mService->setActiveGroup(2, kTmpDir);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+TEST_P(FingerprintHidlTest, SetActiveGroupTest) {
+    // Create an active group
+    Return<RequestStatus> res = mService->setActiveGroup(2, kTmpDir);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // Reset active group
-  res = mService->setActiveGroup(kGroupId, kTmpDir);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    // Reset active group
+    res = mService->setActiveGroup(kGroupId, kTmpDir);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 }
 
 // Active group should fail to set to an unwritable location.
-TEST_F(FingerprintHidlTest, SetActiveGroupUnwritableTest) {
-  // Create an active group to an unwritable location (device root dir)
-  Return<RequestStatus> res = mService->setActiveGroup(3, "/");
-  ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+TEST_P(FingerprintHidlTest, SetActiveGroupUnwritableTest) {
+    // Create an active group to an unwritable location (device root dir)
+    Return<RequestStatus> res = mService->setActiveGroup(3, "/");
+    ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // Reset active group
-  res = mService->setActiveGroup(kGroupId, kTmpDir);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    // Reset active group
+    res = mService->setActiveGroup(kGroupId, kTmpDir);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 }
 
 // Active group should fail to set to a null location.
-TEST_F(FingerprintHidlTest, SetActiveGroupNullTest) {
-  // Create an active group to a null location.
-  Return<RequestStatus> res = mService->setActiveGroup(4, nullptr);
-  ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+TEST_P(FingerprintHidlTest, SetActiveGroupNullTest) {
+    // Create an active group to a null location.
+    Return<RequestStatus> res = mService->setActiveGroup(4, nullptr);
+    ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // Reset active group
-  res = mService->setActiveGroup(kGroupId, kTmpDir);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    // Reset active group
+    res = mService->setActiveGroup(kGroupId, kTmpDir);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 }
 
 // Cancel should always return ERROR_CANCELED from any starting state including
 // the IDLE state.
-TEST_F(FingerprintHidlTest, CancelTest) {
-  sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0UL, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, CancelTest) {
+    sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0UL, static_cast<uint64_t>(rc));
 
-  Return<RequestStatus> res = mService->cancel();
-  // check that we were able to make an IPC request successfully
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    Return<RequestStatus> res = mService->cancel();
+    // check that we were able to make an IPC request successfully
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // make sure callback was invoked within kTimeoutInSeconds
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
-  // check error should be ERROR_CANCELED
-  ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
+    // make sure callback was invoked within kTimeoutInSeconds
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    // check error should be ERROR_CANCELED
+    ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
 }
 
 // A call to cancel should succeed during enroll.
-TEST_F(FingerprintHidlTest, CancelEnrollTest) {
-  Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+TEST_P(FingerprintHidlTest, CancelEnrollTest) {
+    Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0U, static_cast<uint64_t>(rc));
+    sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0U, static_cast<uint64_t>(rc));
 
-  uint8_t token[69];
-  res = mService->enroll(token, kGroupId, kTimeout);
-  // check that we were able to make an IPC request successfully
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    uint8_t token[69];
+    res = mService->enroll(token, kGroupId, kTimeout);
+    // check that we were able to make an IPC request successfully
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  res = mService->cancel();
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    res = mService->cancel();
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // make sure callback was invoked within kTimeoutInSeconds
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    // make sure callback was invoked within kTimeoutInSeconds
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
 
-  // check error should be ERROR_CANCELED
-  ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
+    // check error should be ERROR_CANCELED
+    ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
 }
 
 // A call to cancel should succeed during authentication.
-TEST_F(FingerprintHidlTest, CancelAuthTest) {
-  sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0U, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, CancelAuthTest) {
+    sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0U, static_cast<uint64_t>(rc));
 
-  Return<RequestStatus> res = mService->authenticate(0, kGroupId);
-  // check that we were able to make an IPC request successfully
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    Return<RequestStatus> res = mService->authenticate(0, kGroupId);
+    // check that we were able to make an IPC request successfully
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  res = mService->cancel();
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    res = mService->cancel();
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // make sure callback was invoked within kTimeoutInSeconds
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    // make sure callback was invoked within kTimeoutInSeconds
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
 
-  // check error should be ERROR_CANCELED
-  ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
+    // check error should be ERROR_CANCELED
+    ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
 }
 
 // A call to cancel should succeed during authentication.
-TEST_F(FingerprintHidlTest, CancelRemoveTest) {
-  sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0U, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, CancelRemoveTest) {
+    sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0U, static_cast<uint64_t>(rc));
 
-  // Remove a fingerprint
-  Return<RequestStatus> res = mService->remove(kGroupId, 1);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    // Remove a fingerprint
+    Return<RequestStatus> res = mService->remove(kGroupId, 1);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  res = mService->cancel();
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    res = mService->cancel();
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // make sure callback was invoked within kTimeoutInSeconds
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    // make sure callback was invoked within kTimeoutInSeconds
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
 
-  // check error should be ERROR_CANCELED
-  ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
+    // check error should be ERROR_CANCELED
+    ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
 }
 
 // A call to cancel should succeed during authentication.
-TEST_F(FingerprintHidlTest, CancelRemoveAllTest) {
-  sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
-  Return<uint64_t> rc = mService->setNotify(cb);
-  ASSERT_NE(0U, static_cast<uint64_t>(rc));
+TEST_P(FingerprintHidlTest, CancelRemoveAllTest) {
+    sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
+    Return<uint64_t> rc = mService->setNotify(cb);
+    ASSERT_NE(0U, static_cast<uint64_t>(rc));
 
-  // Remove a fingerprint
-  Return<RequestStatus> res = mService->remove(kGroupId, 0);
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    // Remove a fingerprint
+    Return<RequestStatus> res = mService->remove(kGroupId, 0);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  res = mService->cancel();
-  ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    res = mService->cancel();
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
 
-  // make sure callback was invoked within kTimeoutInSeconds
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    // make sure callback was invoked within kTimeoutInSeconds
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
 
-  // check error should be ERROR_CANCELED
-  ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
+    // check error should be ERROR_CANCELED
+    ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
 }
 }  // anonymous namespace
 
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(FingerprintHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  FingerprintHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
-
+INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IBiometricsFingerprint::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/bluetooth/1.0/Android.bp b/bluetooth/1.0/Android.bp
index 67f1a4f..7036d6e 100644
--- a/bluetooth/1.0/Android.bp
+++ b/bluetooth/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/bluetooth/1.0/default/Android.bp b/bluetooth/1.0/default/Android.bp
index f4b1e7b..f66c25e 100644
--- a/bluetooth/1.0/default/Android.bp
+++ b/bluetooth/1.0/default/Android.bp
@@ -29,7 +29,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
@@ -130,7 +129,6 @@
         "libutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.bluetooth@1.0",
     ],
 }
diff --git a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
index b615227..9fa128d 100644
--- a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
+++ b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service
+    interface android.hardware.bluetooth@1.0::IBluetoothHci default
     class hal
     capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
     user bluetooth
diff --git a/bluetooth/1.0/default/bluetooth_hci.cc b/bluetooth/1.0/default/bluetooth_hci.cc
index e14e3d7..a2211f4 100644
--- a/bluetooth/1.0/default/bluetooth_hci.cc
+++ b/bluetooth/1.0/default/bluetooth_hci.cc
@@ -89,6 +89,9 @@
         if (!hidl_status.isOk()) {
           ALOGE("VendorInterface -> Unable to call scoDataReceived()");
         }
+      },
+      [cb](const hidl_vec<uint8_t>&) {
+        ALOGE("VendorInterface -> No callback for ISO packets in HAL V1_0");
       });
   if (!rc) {
     auto hidl_status = cb->initializationComplete(Status::INITIALIZATION_ERROR);
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
index 98e3273..8c24f76 100644
--- a/bluetooth/1.0/default/h4_protocol.cc
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -58,6 +58,9 @@
     case HCI_PACKET_TYPE_SCO_DATA:
       sco_cb_(hci_packetizer_.GetPacket());
       break;
+    case HCI_PACKET_TYPE_ISO_DATA:
+      iso_cb_(hci_packetizer_.GetPacket());
+      break;
     default:
       LOG_ALWAYS_FATAL("%s: Unimplemented packet type %d", __func__,
                        static_cast<int>(hci_packet_type_));
diff --git a/bluetooth/1.0/default/h4_protocol.h b/bluetooth/1.0/default/h4_protocol.h
index 0d0a1ca..0c82fd6 100644
--- a/bluetooth/1.0/default/h4_protocol.h
+++ b/bluetooth/1.0/default/h4_protocol.h
@@ -31,11 +31,12 @@
 class H4Protocol : public HciProtocol {
  public:
   H4Protocol(int fd, PacketReadCallback event_cb, PacketReadCallback acl_cb,
-             PacketReadCallback sco_cb)
+             PacketReadCallback sco_cb, PacketReadCallback iso_cb)
       : uart_fd_(fd),
         event_cb_(event_cb),
         acl_cb_(acl_cb),
         sco_cb_(sco_cb),
+        iso_cb_(iso_cb),
         hci_packetizer_([this]() { OnPacketReady(); }) {}
 
   size_t Send(uint8_t type, const uint8_t* data, size_t length);
@@ -50,6 +51,7 @@
   PacketReadCallback event_cb_;
   PacketReadCallback acl_cb_;
   PacketReadCallback sco_cb_;
+  PacketReadCallback iso_cb_;
 
   HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
   hci::HciPacketizer hci_packetizer_;
diff --git a/bluetooth/1.0/default/hci_internals.h b/bluetooth/1.0/default/hci_internals.h
index 1e1f300..24e944f 100644
--- a/bluetooth/1.0/default/hci_internals.h
+++ b/bluetooth/1.0/default/hci_internals.h
@@ -24,7 +24,8 @@
   HCI_PACKET_TYPE_COMMAND = 1,
   HCI_PACKET_TYPE_ACL_DATA = 2,
   HCI_PACKET_TYPE_SCO_DATA = 3,
-  HCI_PACKET_TYPE_EVENT = 4
+  HCI_PACKET_TYPE_EVENT = 4,
+  HCI_PACKET_TYPE_ISO_DATA = 5,
 };
 
 // 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
diff --git a/bluetooth/1.0/default/test/h4_protocol_unittest.cc b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
index ba56c0d..283243d 100644
--- a/bluetooth/1.0/default/test/h4_protocol_unittest.cc
+++ b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
@@ -42,11 +42,15 @@
 static char sample_data1[100] = "A point is that which has no part.";
 static char sample_data2[100] = "A line is breadthless length.";
 static char sample_data3[100] = "The ends of a line are points.";
+static char sample_data4[100] =
+    "A plane surface is a surface which lies evenly with the straight ...";
 static char acl_data[100] =
     "A straight line is a line which lies evenly with the points on itself.";
 static char sco_data[100] =
     "A surface is that which has length and breadth only.";
 static char event_data[100] = "The edges of a surface are lines.";
+static char iso_data[100] =
+    "A plane angle is the inclination to one another of two lines in a ...";
 
 MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
   size_t length = strlen(payload) + preamble_length;
@@ -75,9 +79,9 @@
 
     int sockfd[2];
     socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
-    H4Protocol* h4_hci =
-        new H4Protocol(sockfd[0], event_cb_.AsStdFunction(),
-                       acl_cb_.AsStdFunction(), sco_cb_.AsStdFunction());
+    H4Protocol* h4_hci = new H4Protocol(
+        sockfd[0], event_cb_.AsStdFunction(), acl_cb_.AsStdFunction(),
+        sco_cb_.AsStdFunction(), iso_cb_.AsStdFunction());
     fd_watcher_.WatchFdForNonBlockingReads(
         sockfd[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
     protocol_ = h4_hci;
@@ -184,9 +188,35 @@
     }
   }
 
+  void WriteAndExpectInboundIsoData(char* payload) {
+    // h4 type[1] + handle[2] + size[1]
+    char preamble[4] = {HCI_PACKET_TYPE_ISO_DATA, 20, 17, 0};
+    preamble[3] = strlen(payload) & 0xFF;
+
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(iso_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
+                                             payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    // Fail if it takes longer than 100 ms.
+    auto timeout_time =
+        std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait_until(lock, timeout_time);
+    }
+  }
+
   testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
   testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
   testing::MockFunction<void(const hidl_vec<uint8_t>&)> sco_cb_;
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> iso_cb_;
   async::AsyncFdWatcher fd_watcher_;
   H4Protocol* protocol_;
   int fake_uart_;
@@ -197,6 +227,7 @@
   SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1);
   SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2);
   SendAndReadUartOutbound(HCI_PACKET_TYPE_SCO_DATA, sample_data3);
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_ISO_DATA, sample_data4);
 }
 
 // Ensure we properly parse data coming from the UART
@@ -204,6 +235,7 @@
   WriteAndExpectInboundAclData(acl_data);
   WriteAndExpectInboundScoData(sco_data);
   WriteAndExpectInboundEvent(event_data);
+  WriteAndExpectInboundIsoData(iso_data);
 }
 
 }  // namespace implementation
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index d56e344..d809313 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -162,14 +162,14 @@
 bool VendorInterface::Initialize(
     InitializeCompleteCallback initialize_complete_cb,
     PacketReadCallback event_cb, PacketReadCallback acl_cb,
-    PacketReadCallback sco_cb) {
+    PacketReadCallback sco_cb, PacketReadCallback iso_cb) {
   if (g_vendor_interface) {
     ALOGE("%s: No previous Shutdown()?", __func__);
     return false;
   }
   g_vendor_interface = new VendorInterface();
   return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
-                                  sco_cb);
+                                  sco_cb, iso_cb);
 }
 
 void VendorInterface::Shutdown() {
@@ -185,7 +185,8 @@
 bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
                            PacketReadCallback event_cb,
                            PacketReadCallback acl_cb,
-                           PacketReadCallback sco_cb) {
+                           PacketReadCallback sco_cb,
+                           PacketReadCallback iso_cb) {
   initialize_complete_cb_ = initialize_complete_cb;
 
   // Initialize vendor interface
@@ -248,7 +249,7 @@
 
   if (fd_count == 1) {
     hci::H4Protocol* h4_hci =
-        new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb);
+        new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb);
     fd_watcher_.WatchFdForNonBlockingReads(
         fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
     hci_ = h4_hci;
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index 1d69040..040f31a 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -38,7 +38,7 @@
  public:
   static bool Initialize(InitializeCompleteCallback initialize_complete_cb,
                          PacketReadCallback event_cb, PacketReadCallback acl_cb,
-                         PacketReadCallback sco_cb);
+                         PacketReadCallback sco_cb, PacketReadCallback iso_cb);
   static void Shutdown();
   static VendorInterface* get();
 
@@ -51,7 +51,7 @@
 
   bool Open(InitializeCompleteCallback initialize_complete_cb,
             PacketReadCallback event_cb, PacketReadCallback acl_cb,
-            PacketReadCallback sco_cb);
+            PacketReadCallback sco_cb, PacketReadCallback iso_cb);
   void Close();
 
   void OnTimeout();
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
index beb9a3e..ef02eff 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
@@ -24,8 +24,9 @@
 #include <utils/Log.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <chrono>
 #include <queue>
@@ -137,30 +138,12 @@
   std::chrono::steady_clock::time_point start_time_;
 };
 
-// Test environment for Bluetooth HIDL HAL.
-class BluetoothHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static BluetoothHidlEnvironment* Instance() {
-    static BluetoothHidlEnvironment* instance = new BluetoothHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override {
-    registerTestService<IBluetoothHci>();
-  }
-
- private:
-  BluetoothHidlEnvironment() {}
-};
-
 // The main test class for Bluetooth HIDL HAL.
-class BluetoothHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class BluetoothHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
     // currently test passthrough mode only
-    bluetooth =
-        ::testing::VtsHalHidlTargetTestBase::getService<IBluetoothHci>();
+    bluetooth = IBluetoothHci::getService(GetParam());
     ASSERT_NE(bluetooth, nullptr);
     ALOGI("%s: getService() for bluetooth is %s", __func__,
           bluetooth->isRemote() ? "remote" : "local");
@@ -617,10 +600,10 @@
 }
 
 // Empty test: Initialize()/Close() are called in SetUp()/TearDown().
-TEST_F(BluetoothHidlTest, InitializeAndClose) {}
+TEST_P(BluetoothHidlTest, InitializeAndClose) {}
 
 // Send an HCI Reset with sendHciCommand and wait for a command complete event.
-TEST_F(BluetoothHidlTest, HciReset) {
+TEST_P(BluetoothHidlTest, HciReset) {
   hidl_vec<uint8_t> cmd = COMMAND_HCI_RESET;
   bluetooth->sendHciCommand(cmd);
 
@@ -628,7 +611,7 @@
 }
 
 // Read and check the HCI version of the controller.
-TEST_F(BluetoothHidlTest, HciVersionTest) {
+TEST_P(BluetoothHidlTest, HciVersionTest) {
   hidl_vec<uint8_t> cmd = COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION;
   bluetooth->sendHciCommand(cmd);
 
@@ -649,7 +632,7 @@
 }
 
 // Send an unknown HCI command and wait for the error message.
-TEST_F(BluetoothHidlTest, HciUnknownCommand) {
+TEST_P(BluetoothHidlTest, HciUnknownCommand) {
   hidl_vec<uint8_t> cmd = COMMAND_HCI_SHOULD_BE_UNKNOWN;
   bluetooth->sendHciCommand(cmd);
 
@@ -676,14 +659,14 @@
 }
 
 // Enter loopback mode, but don't send any packets.
-TEST_F(BluetoothHidlTest, WriteLoopbackMode) {
+TEST_P(BluetoothHidlTest, WriteLoopbackMode) {
   std::vector<uint16_t> sco_connection_handles;
   std::vector<uint16_t> acl_connection_handles;
   enterLoopbackMode(sco_connection_handles, acl_connection_handles);
 }
 
 // Enter loopback mode and send single packets.
-TEST_F(BluetoothHidlTest, LoopbackModeSinglePackets) {
+TEST_P(BluetoothHidlTest, LoopbackModeSinglePackets) {
   setBufferSizes();
 
   std::vector<uint16_t> sco_connection_handles;
@@ -720,7 +703,7 @@
 }
 
 // Enter loopback mode and send packets for bandwidth measurements.
-TEST_F(BluetoothHidlTest, LoopbackModeBandwidth) {
+TEST_P(BluetoothHidlTest, LoopbackModeBandwidth) {
   setBufferSizes();
 
   std::vector<uint16_t> sco_connection_handles;
@@ -758,11 +741,8 @@
   }
 }
 
-int main(int argc, char** argv) {
-  ::testing::AddGlobalTestEnvironment(BluetoothHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  BluetoothHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, BluetoothHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IBluetoothHci::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/bluetooth/1.1/Android.bp b/bluetooth/1.1/Android.bp
new file mode 100644
index 0000000..4204aed
--- /dev/null
+++ b/bluetooth/1.1/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.bluetooth@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IBluetoothHci.hal",
+        "IBluetoothHciCallbacks.hal",
+    ],
+    interfaces: [
+        "android.hardware.bluetooth@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/bluetooth/1.1/IBluetoothHci.hal b/bluetooth/1.1/IBluetoothHci.hal
new file mode 100644
index 0000000..0f69c6e
--- /dev/null
+++ b/bluetooth/1.1/IBluetoothHci.hal
@@ -0,0 +1,44 @@
+/*
+ * 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.bluetooth@1.1;
+
+import @1.0::HciPacket;
+import @1.0::IBluetoothHci;
+import IBluetoothHciCallbacks;
+
+/**
+ * The Host Controller Interface (HCI) is the layer defined by the Bluetooth
+ * specification between the software that runs on the host and the Bluetooth
+ * controller chip. This boundary is the natural choice for a Hardware
+ * Abstraction Layer (HAL). Dealing only in HCI packets and events simplifies
+ * the stack and abstracts away power management, initialization, and other
+ * implementation-specific details related to the hardware.
+ */
+interface IBluetoothHci extends @1.0::IBluetoothHci {
+    /**
+     * Same as @1.0, but uses 1.1 Callbacks version
+     */
+    initialize_1_1(@1.1::IBluetoothHciCallbacks callback);
+
+    /**
+     * Send an ISO data packet (as specified in the Bluetooth Specification
+     * V6.0) to the Bluetooth controller.
+     * Packets must be processed in order.
+     * @param data HCI data packet to be sent
+     */
+    sendIsoData(HciPacket data);
+};
diff --git a/bluetooth/1.1/IBluetoothHciCallbacks.hal b/bluetooth/1.1/IBluetoothHciCallbacks.hal
new file mode 100644
index 0000000..62cbe45
--- /dev/null
+++ b/bluetooth/1.1/IBluetoothHciCallbacks.hal
@@ -0,0 +1,31 @@
+/*
+ * 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.bluetooth@1.1;
+
+import @1.0::HciPacket;
+import @1.0::IBluetoothHciCallbacks;
+
+/**
+ * The interface from the Bluetooth Controller to the stack.
+ */
+interface IBluetoothHciCallbacks extends @1.0::IBluetoothHciCallbacks {
+    /**
+     * Send a ISO data packet form the controller to the host.
+     * @param data the ISO HCI packet to be passed to the host stack
+     */
+    isoDataReceived(HciPacket data);
+};
diff --git a/bluetooth/1.1/default/Android.bp b/bluetooth/1.1/default/Android.bp
new file mode 100644
index 0000000..4f7fecb
--- /dev/null
+++ b/bluetooth/1.1/default/Android.bp
@@ -0,0 +1,42 @@
+//
+// 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_binary {
+    name: "android.hardware.bluetooth@1.1-service",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.bluetooth@1.1-service.rc"],
+    srcs: [
+        "service.cpp",
+        "bluetooth_hci.cc",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libdl",
+        "libbase",
+        "libutils",
+        "libhardware",
+        "libhidlbase",
+        "android.hardware.bluetooth@1.0-impl",
+        "android.hardware.bluetooth@1.1",
+    ],
+
+    static_libs: [
+        "android.hardware.bluetooth-hci",
+    ],
+}
diff --git a/bluetooth/1.1/default/OWNERS b/bluetooth/1.1/default/OWNERS
new file mode 100644
index 0000000..0c01df6
--- /dev/null
+++ b/bluetooth/1.1/default/OWNERS
@@ -0,0 +1,3 @@
+zachoverflow@google.com
+mylesgw@google.com
+jpawlowski@google.com
diff --git a/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc b/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc
new file mode 100644
index 0000000..49f0be3
--- /dev/null
+++ b/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc
@@ -0,0 +1,9 @@
+service vendor.bluetooth-1-1 /vendor/bin/hw/android.hardware.bluetooth@1.1-service
+    interface android.hardware.bluetooth@1.1::IBluetoothHci default
+    interface android.hardware.bluetooth@1.0::IBluetoothHci default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    writepid /dev/stune/foreground/tasks
+
diff --git a/bluetooth/1.1/default/bluetooth_hci.cc b/bluetooth/1.1/default/bluetooth_hci.cc
new file mode 100644
index 0000000..7ccce80
--- /dev/null
+++ b/bluetooth/1.1/default/bluetooth_hci.cc
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.bluetooth@1.1-impl"
+#include "bluetooth_hci.h"
+
+#include <log/log.h>
+
+#include "vendor_interface.h"
+
+using android::hardware::bluetooth::V1_0::implementation::VendorInterface;
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_1 {
+namespace implementation {
+
+static const uint8_t HCI_DATA_TYPE_COMMAND = 1;
+static const uint8_t HCI_DATA_TYPE_ACL = 2;
+static const uint8_t HCI_DATA_TYPE_SCO = 3;
+static const uint8_t HCI_DATA_TYPE_ISO = 5;
+
+class BluetoothDeathRecipient : public hidl_death_recipient {
+ public:
+  BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
+
+  virtual void serviceDied(
+      uint64_t /*cookie*/,
+      const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+    ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
+    has_died_ = true;
+    mHci->close();
+  }
+  sp<IBluetoothHci> mHci;
+  bool getHasDied() const { return has_died_; }
+  void setHasDied(bool has_died) { has_died_ = has_died; }
+
+ private:
+  bool has_died_;
+};
+
+BluetoothHci::BluetoothHci()
+    : death_recipient_(new BluetoothDeathRecipient(this)) {}
+
+Return<void> BluetoothHci::initialize_1_1(
+    const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb) {
+  ALOGI("BluetoothHci::initialize_1_1()");
+  if (cb == nullptr) {
+    ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
+    return Void();
+  }
+
+  death_recipient_->setHasDied(false);
+  cb->linkToDeath(death_recipient_, 0);
+
+  bool rc = VendorInterface::Initialize(
+      [cb](bool status) {
+        auto hidl_status = cb->initializationComplete(
+            status ? V1_0::Status::SUCCESS
+                   : V1_0::Status::INITIALIZATION_ERROR);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call initializationComplete()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->hciEventReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call hciEventReceived()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->aclDataReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call aclDataReceived()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->scoDataReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call scoDataReceived()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->isoDataReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call isoDataReceived()");
+        }
+      });
+  if (!rc) {
+    auto hidl_status =
+        cb->initializationComplete(V1_0::Status::INITIALIZATION_ERROR);
+    if (!hidl_status.isOk()) {
+      ALOGE("VendorInterface -> Unable to call initializationComplete(ERR)");
+    }
+  }
+
+  unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
+    if (death_recipient->getHasDied())
+      ALOGI("Skipping unlink call, service died.");
+    else
+      cb->unlinkToDeath(death_recipient);
+  };
+
+  return Void();
+}
+
+class OldCbWrapper : public V1_1::IBluetoothHciCallbacks {
+ public:
+  const ::android::sp<V1_0::IBluetoothHciCallbacks> old_cb_;
+  OldCbWrapper(const ::android::sp<V1_0::IBluetoothHciCallbacks>& old_cb)
+      : old_cb_(old_cb) {}
+
+  virtual ~OldCbWrapper() = default;
+
+  Return<void> initializationComplete(V1_0::Status status) override {
+    return old_cb_->initializationComplete(status);
+  };
+
+  Return<void> hciEventReceived(
+      const ::android::hardware::hidl_vec<uint8_t>& event) override {
+    return old_cb_->hciEventReceived(event);
+  };
+
+  Return<void> aclDataReceived(
+      const ::android::hardware::hidl_vec<uint8_t>& data) override {
+    return old_cb_->aclDataReceived(data);
+  };
+
+  Return<void> scoDataReceived(
+      const ::android::hardware::hidl_vec<uint8_t>& data) override {
+    return old_cb_->scoDataReceived(data);
+  };
+
+  Return<void> isoDataReceived(
+      const ::android::hardware::hidl_vec<uint8_t>&) override {
+    ALOGE("Please use HAL V1_1 for ISO.");
+    return Void();
+  };
+};
+
+Return<void> BluetoothHci::initialize(
+    const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb) {
+  ALOGE("Using initialize from HAL V1_0 instead of initialize_1_1.");
+  return initialize_1_1(new OldCbWrapper(cb));
+}
+
+Return<void> BluetoothHci::close() {
+  ALOGI("BluetoothHci::close()");
+  unlink_cb_(death_recipient_);
+  VendorInterface::Shutdown();
+  return Void();
+}
+
+Return<void> BluetoothHci::sendHciCommand(const hidl_vec<uint8_t>& command) {
+  sendDataToController(HCI_DATA_TYPE_COMMAND, command);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& data) {
+  sendDataToController(HCI_DATA_TYPE_ACL, data);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& data) {
+  sendDataToController(HCI_DATA_TYPE_SCO, data);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendIsoData(const hidl_vec<uint8_t>& data) {
+  sendDataToController(HCI_DATA_TYPE_ISO, data);
+  return Void();
+}
+
+void BluetoothHci::sendDataToController(const uint8_t type,
+                                        const hidl_vec<uint8_t>& data) {
+  VendorInterface::get()->Send(type, data.data(), data.size());
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.1/default/bluetooth_hci.h b/bluetooth/1.1/default/bluetooth_hci.h
new file mode 100644
index 0000000..5f59cb0
--- /dev/null
+++ b/bluetooth/1.1/default/bluetooth_hci.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
+#define HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
+
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHciCallbacks.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include <functional>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+class BluetoothDeathRecipient;
+
+class BluetoothHci : public V1_1::IBluetoothHci {
+ public:
+  BluetoothHci();
+  Return<void> initialize(
+      const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb) override;
+  Return<void> initialize_1_1(
+      const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb) override;
+  Return<void> sendHciCommand(const hidl_vec<uint8_t>& packet) override;
+  Return<void> sendAclData(const hidl_vec<uint8_t>& data) override;
+  Return<void> sendScoData(const hidl_vec<uint8_t>& data) override;
+  Return<void> sendIsoData(const hidl_vec<uint8_t>& data) override;
+  Return<void> close() override;
+
+ private:
+  void sendDataToController(const uint8_t type, const hidl_vec<uint8_t>& data);
+  ::android::sp<BluetoothDeathRecipient> death_recipient_;
+  std::function<void(sp<BluetoothDeathRecipient>&)> unlink_cb_;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
diff --git a/bluetooth/1.1/default/service.cpp b/bluetooth/1.1/default/service.cpp
new file mode 100644
index 0000000..affa855
--- /dev/null
+++ b/bluetooth/1.1/default/service.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright 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 "android.hardware.bluetooth@1.1-service"
+
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "bluetooth_hci.h"
+
+// Generated HIDL files
+using android::hardware::bluetooth::V1_1::IBluetoothHci;
+using android::hardware::bluetooth::V1_1::implementation::BluetoothHci;
+
+using android::sp;
+using android::status_t;
+
+int main() {
+  ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/);
+
+  sp bluetoothHci = new BluetoothHci();
+  const status_t status = bluetoothHci->registerAsService();
+  if (status != ::android::OK) {
+    ALOGE("Cannot register Bluetooth HAL service");
+    return 1;  // or handle error
+  }
+
+  ::android::hardware::joinRpcThreadpool();
+  return 1;  // joinRpcThreadpool should never return
+}
diff --git a/bluetooth/1.1/vts/OWNERS b/bluetooth/1.1/vts/OWNERS
new file mode 100644
index 0000000..ff6fd93
--- /dev/null
+++ b/bluetooth/1.1/vts/OWNERS
@@ -0,0 +1,6 @@
+zachoverflow@google.com
+siyuanh@google.com
+mylesgw@google.com
+jpawlowski@google.com
+hsz@google.com
+
diff --git a/bluetooth/1.1/vts/functional/Android.bp b/bluetooth/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..8d6d749
--- /dev/null
+++ b/bluetooth/1.1/vts/functional/Android.bp
@@ -0,0 +1,27 @@
+//
+// 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: "VtsHalBluetoothV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBluetoothV1_1TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.bluetooth@1.1",
+        "android.hardware.bluetooth@1.0",
+        "libbluetooth-types",
+    ],
+    test_suites: ["general-tests", "vts-core"],
+}
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp
new file mode 100644
index 0000000..659b2c8
--- /dev/null
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp
@@ -0,0 +1,760 @@
+/*
+ * 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 "bluetooth_hidl_hal_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/bluetooth/1.0/types.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHciCallbacks.h>
+#include <hardware/bluetooth.h>
+#include <utils/Log.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <chrono>
+#include <queue>
+#include <thread>
+
+using ::android::sp;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::V1_0::Status;
+using ::android::hardware::bluetooth::V1_1::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_1::IBluetoothHciCallbacks;
+
+#define HCI_MINIMUM_HCI_VERSION 5  // Bluetooth Core Specification 3.0 + HS
+#define HCI_MINIMUM_LMP_VERSION 5  // Bluetooth Core Specification 3.0 + HS
+#define NUM_HCI_COMMANDS_BANDWIDTH 1000
+#define NUM_SCO_PACKETS_BANDWIDTH 1000
+#define NUM_ACL_PACKETS_BANDWIDTH 1000
+#define WAIT_FOR_INIT_TIMEOUT std::chrono::milliseconds(2000)
+#define WAIT_FOR_HCI_EVENT_TIMEOUT std::chrono::milliseconds(2000)
+#define WAIT_FOR_SCO_DATA_TIMEOUT std::chrono::milliseconds(1000)
+#define WAIT_FOR_ACL_DATA_TIMEOUT std::chrono::milliseconds(1000)
+#define INTERFACE_CLOSE_DELAY_MS std::chrono::milliseconds(200)
+
+#define COMMAND_HCI_SHOULD_BE_UNKNOWN \
+  { 0xff, 0x3B, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }
+#define COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION \
+  { 0x01, 0x10, 0x00 }
+#define COMMAND_HCI_READ_BUFFER_SIZE \
+  { 0x05, 0x10, 0x00 }
+#define COMMAND_HCI_WRITE_LOOPBACK_MODE_LOCAL \
+  { 0x02, 0x18, 0x01, 0x01 }
+#define COMMAND_HCI_RESET \
+  { 0x03, 0x0c, 0x00 }
+#define COMMAND_HCI_WRITE_LOCAL_NAME \
+  { 0x13, 0x0c, 0xf8 }
+#define HCI_STATUS_SUCCESS 0x00
+#define HCI_STATUS_UNKNOWN_HCI_COMMAND 0x01
+
+#define EVENT_CONNECTION_COMPLETE 0x03
+#define EVENT_COMMAND_COMPLETE 0x0e
+#define EVENT_COMMAND_STATUS 0x0f
+#define EVENT_NUMBER_OF_COMPLETED_PACKETS 0x13
+#define EVENT_LOOPBACK_COMMAND 0x19
+
+#define EVENT_CODE_BYTE 0
+#define EVENT_LENGTH_BYTE 1
+#define EVENT_FIRST_PAYLOAD_BYTE 2
+#define EVENT_COMMAND_STATUS_STATUS_BYTE 2
+#define EVENT_COMMAND_STATUS_ALLOWED_PACKETS_BYTE 3
+#define EVENT_COMMAND_STATUS_OPCODE_LSBYTE 4  // Bytes 4 and 5
+#define EVENT_COMMAND_COMPLETE_ALLOWED_PACKETS_BYTE 2
+#define EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE 3  // Bytes 3 and 4
+#define EVENT_COMMAND_COMPLETE_STATUS_BYTE 5
+#define EVENT_COMMAND_COMPLETE_FIRST_PARAM_BYTE 6
+#define EVENT_LOCAL_HCI_VERSION_BYTE EVENT_COMMAND_COMPLETE_FIRST_PARAM_BYTE
+#define EVENT_LOCAL_LMP_VERSION_BYTE EVENT_LOCAL_HCI_VERSION_BYTE + 3
+
+#define EVENT_CONNECTION_COMPLETE_PARAM_LENGTH 11
+#define EVENT_CONNECTION_COMPLETE_TYPE 11
+#define EVENT_CONNECTION_COMPLETE_TYPE_SCO 0
+#define EVENT_CONNECTION_COMPLETE_TYPE_ACL 1
+#define EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE 3
+#define EVENT_COMMAND_STATUS_LENGTH 4
+
+#define EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES 2
+
+#define ACL_BROADCAST_FLAG_OFFSET 6
+#define ACL_BROADCAST_FLAG_POINT_TO_POINT 0x0
+#define ACL_BROADCAST_POINT_TO_POINT \
+  (ACL_BROADCAST_FLAG_POINT_TO_POINT << ACL_BROADCAST_FLAG_OFFSET)
+
+#define ACL_PACKET_BOUNDARY_FLAG_OFFSET 4
+#define ACL_PACKET_BOUNDARY_FLAG_FIRST_AUTO_FLUSHABLE 0x2
+#define ACL_PACKET_BOUNDARY_FIRST_AUTO_FLUSHABLE \
+  (ACL_PACKET_BOUNDARY_FLAG_FIRST_AUTO_FLUSHABLE \
+   << ACL_PACKET_BOUNDARY_FLAG_OFFSET)
+
+// To be removed in VTS release builds
+#define ACL_HANDLE_QCA_DEBUG_MESSAGE 0xedc
+
+constexpr char kCallbackNameAclEventReceived[] = "aclDataReceived";
+constexpr char kCallbackNameHciEventReceived[] = "hciEventReceived";
+constexpr char kCallbackNameInitializationComplete[] = "initializationComplete";
+constexpr char kCallbackNameScoEventReceived[] = "scoDataReceived";
+constexpr char kCallbackNameIsoEventReceived[] = "isoDataReceived";
+
+class ThroughputLogger {
+ public:
+  ThroughputLogger(std::string task)
+      : task_(task), start_time_(std::chrono::steady_clock::now()) {}
+
+  ~ThroughputLogger() {
+    if (total_bytes_ == 0) return;
+    std::chrono::duration<double> duration =
+        std::chrono::steady_clock::now() - start_time_;
+    double s = duration.count();
+    if (s == 0) return;
+    double rate_kb = (static_cast<double>(total_bytes_) / s) / 1024;
+    ALOGD("%s %.1f KB/s (%zu bytes in %.3fs)", task_.c_str(), rate_kb,
+          total_bytes_, s);
+  }
+
+  void setTotalBytes(size_t total_bytes) { total_bytes_ = total_bytes; }
+
+ private:
+  size_t total_bytes_;
+  std::string task_;
+  std::chrono::steady_clock::time_point start_time_;
+};
+
+// The main test class for Bluetooth HIDL HAL.
+class BluetoothHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+  virtual void SetUp() override {
+    // currently test passthrough mode only
+    bluetooth = IBluetoothHci::getService(GetParam());
+    ASSERT_NE(bluetooth, nullptr);
+    ALOGI("%s: getService() for bluetooth is %s", __func__,
+          bluetooth->isRemote() ? "remote" : "local");
+
+    bluetooth_hci_death_recipient = new BluetoothHciDeathRecipient();
+    ASSERT_NE(bluetooth_hci_death_recipient, nullptr);
+    ASSERT_TRUE(
+        bluetooth->linkToDeath(bluetooth_hci_death_recipient, 0).isOk());
+
+    bluetooth_cb = new BluetoothHciCallbacks(*this);
+    ASSERT_NE(bluetooth_cb, nullptr);
+
+    max_acl_data_packet_length = 0;
+    max_sco_data_packet_length = 0;
+    max_acl_data_packets = 0;
+    max_sco_data_packets = 0;
+
+    initialized = false;
+    event_cb_count = 0;
+    acl_cb_count = 0;
+    sco_cb_count = 0;
+
+    ASSERT_FALSE(initialized);
+    // Should not be checked in production code
+    ASSERT_TRUE(bluetooth->initialize(bluetooth_cb).isOk());
+
+    bluetooth_cb->SetWaitTimeout(kCallbackNameInitializationComplete,
+                                 WAIT_FOR_INIT_TIMEOUT);
+    bluetooth_cb->SetWaitTimeout(kCallbackNameHciEventReceived,
+                                 WAIT_FOR_HCI_EVENT_TIMEOUT);
+    bluetooth_cb->SetWaitTimeout(kCallbackNameAclEventReceived,
+                                 WAIT_FOR_ACL_DATA_TIMEOUT);
+    bluetooth_cb->SetWaitTimeout(kCallbackNameScoEventReceived,
+                                 WAIT_FOR_SCO_DATA_TIMEOUT);
+
+    EXPECT_TRUE(
+        bluetooth_cb->WaitForCallback(kCallbackNameInitializationComplete)
+            .no_timeout);
+
+    ASSERT_TRUE(initialized);
+  }
+
+  virtual void TearDown() override {
+    ALOGI("TearDown");
+    // Should not be checked in production code
+    ASSERT_TRUE(bluetooth->close().isOk());
+    std::this_thread::sleep_for(INTERFACE_CLOSE_DELAY_MS);
+    handle_no_ops();
+    EXPECT_EQ(static_cast<size_t>(0), event_queue.size());
+    EXPECT_EQ(static_cast<size_t>(0), sco_queue.size());
+    EXPECT_EQ(static_cast<size_t>(0), acl_queue.size());
+    EXPECT_EQ(static_cast<size_t>(0), iso_queue.size());
+  }
+
+  void setBufferSizes();
+
+  // Functions called from within tests in loopback mode
+  void sendAndCheckHCI(int num_packets);
+  void sendAndCheckSCO(int num_packets, size_t size, uint16_t handle);
+  void sendAndCheckACL(int num_packets, size_t size, uint16_t handle);
+
+  // Helper functions to try to get a handle on verbosity
+  void enterLoopbackMode(std::vector<uint16_t>* sco_handles,
+                         std::vector<uint16_t>* acl_handles);
+  void handle_no_ops();
+  void wait_for_event(bool timeout_is_error);
+  void wait_for_command_complete_event(hidl_vec<uint8_t> cmd);
+  int wait_for_completed_packets_event(uint16_t handle);
+
+  class BluetoothHciDeathRecipient : public hidl_death_recipient {
+   public:
+    void serviceDied(
+        uint64_t /*cookie*/,
+        const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/)
+        override {
+      FAIL();
+    }
+  };
+
+  // A simple test implementation of BluetoothHciCallbacks.
+  class BluetoothHciCallbacks
+      : public ::testing::VtsHalHidlTargetCallbackBase<BluetoothHidlTest>,
+        public IBluetoothHciCallbacks {
+    BluetoothHidlTest& parent_;
+
+   public:
+    BluetoothHciCallbacks(BluetoothHidlTest& parent) : parent_(parent){};
+
+    virtual ~BluetoothHciCallbacks() = default;
+
+    Return<void> initializationComplete(Status status) override {
+      parent_.initialized = (status == Status::SUCCESS);
+      NotifyFromCallback(kCallbackNameInitializationComplete);
+      ALOGV("%s (status = %d)", __func__, static_cast<int>(status));
+      return Void();
+    };
+
+    Return<void> hciEventReceived(
+        const ::android::hardware::hidl_vec<uint8_t>& event) override {
+      parent_.event_cb_count++;
+      parent_.event_queue.push(event);
+      NotifyFromCallback(kCallbackNameHciEventReceived);
+      ALOGV("Event received (length = %d)", static_cast<int>(event.size()));
+      return Void();
+    };
+
+    Return<void> aclDataReceived(
+        const ::android::hardware::hidl_vec<uint8_t>& data) override {
+      parent_.acl_cb_count++;
+      parent_.acl_queue.push(data);
+      NotifyFromCallback(kCallbackNameAclEventReceived);
+      return Void();
+    };
+
+    Return<void> scoDataReceived(
+        const ::android::hardware::hidl_vec<uint8_t>& data) override {
+      parent_.sco_cb_count++;
+      parent_.sco_queue.push(data);
+      NotifyFromCallback(kCallbackNameScoEventReceived);
+      return Void();
+    };
+
+    Return<void> isoDataReceived(
+        const ::android::hardware::hidl_vec<uint8_t>& data) override {
+      parent_.iso_cb_count++;
+      parent_.iso_queue.push(data);
+      NotifyFromCallback(kCallbackNameIsoEventReceived);
+      return Void();
+    };
+  };
+
+  sp<IBluetoothHci> bluetooth;
+  sp<BluetoothHciCallbacks> bluetooth_cb;
+  sp<BluetoothHciDeathRecipient> bluetooth_hci_death_recipient;
+  std::queue<hidl_vec<uint8_t>> event_queue;
+  std::queue<hidl_vec<uint8_t>> acl_queue;
+  std::queue<hidl_vec<uint8_t>> sco_queue;
+  std::queue<hidl_vec<uint8_t>> iso_queue;
+
+  bool initialized;
+
+  int event_cb_count;
+  int sco_cb_count;
+  int acl_cb_count;
+  int iso_cb_count;
+
+  int max_acl_data_packet_length;
+  int max_sco_data_packet_length;
+  int max_acl_data_packets;
+  int max_sco_data_packets;
+};
+
+// Discard NO-OPs from the event queue.
+void BluetoothHidlTest::handle_no_ops() {
+  while (event_queue.size() > 0) {
+    hidl_vec<uint8_t> event = event_queue.front();
+    EXPECT_GE(event.size(),
+              static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+    bool event_is_no_op =
+        (event[EVENT_CODE_BYTE] == EVENT_COMMAND_COMPLETE) &&
+        (event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE] == 0x00) &&
+        (event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1] == 0x00);
+    event_is_no_op |= (event[EVENT_CODE_BYTE] == EVENT_COMMAND_STATUS) &&
+                      (event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE] == 0x00) &&
+                      (event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1] == 0x00);
+    if (event_is_no_op) {
+      event_queue.pop();
+    } else {
+      break;
+    }
+  }
+  // To be removed in VTS release builds
+  while (acl_queue.size() > 0) {
+    hidl_vec<uint8_t> acl_packet = acl_queue.front();
+    uint16_t connection_handle = acl_packet[1] & 0xF;
+    connection_handle <<= 8;
+    connection_handle |= acl_packet[0];
+    bool packet_is_no_op = connection_handle == ACL_HANDLE_QCA_DEBUG_MESSAGE;
+    if (packet_is_no_op) {
+      acl_queue.pop();
+    } else {
+      break;
+    }
+  }
+}
+
+// Receive an event, discarding NO-OPs.
+void BluetoothHidlTest::wait_for_event(bool timeout_is_error = true) {
+  hidl_vec<uint8_t> event;
+  do {
+    bool no_timeout =
+        bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived).no_timeout;
+    EXPECT_TRUE(no_timeout || !timeout_is_error);
+    if (no_timeout && timeout_is_error) {
+      EXPECT_LT(static_cast<size_t>(0), event_queue.size());
+    }
+    if (event_queue.size() == 0) {
+      // WaitForCallback timed out.
+      return;
+    }
+    handle_no_ops();
+  } while (event_queue.size() == 0);
+}
+
+// Wait until a COMMAND_COMPLETE is received.
+void BluetoothHidlTest::wait_for_command_complete_event(hidl_vec<uint8_t> cmd) {
+  wait_for_event();
+  hidl_vec<uint8_t> event = event_queue.front();
+  event_queue.pop();
+
+  EXPECT_GT(event.size(),
+            static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+  EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+}
+
+// Send the command to read the controller's buffer sizes.
+void BluetoothHidlTest::setBufferSizes() {
+  hidl_vec<uint8_t> cmd = COMMAND_HCI_READ_BUFFER_SIZE;
+  bluetooth->sendHciCommand(cmd);
+
+  wait_for_event();
+  if (event_queue.size() == 0) return;
+
+  hidl_vec<uint8_t> event = event_queue.front();
+  event_queue.pop();
+
+  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+  EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+
+  max_acl_data_packet_length =
+      event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 1] +
+      (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 2] << 8);
+  max_sco_data_packet_length = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 3];
+  max_acl_data_packets = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 4] +
+                         (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 5] << 8);
+  max_sco_data_packets = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 6] +
+                         (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 7] << 8);
+
+  ALOGD("%s: ACL max %d num %d SCO max %d num %d", __func__,
+        static_cast<int>(max_acl_data_packet_length),
+        static_cast<int>(max_acl_data_packets),
+        static_cast<int>(max_sco_data_packet_length),
+        static_cast<int>(max_sco_data_packets));
+}
+
+// Send an HCI command (in Loopback mode) and check the response.
+void BluetoothHidlTest::sendAndCheckHCI(int num_packets) {
+  ThroughputLogger logger = {__func__};
+  int command_size = 0;
+  for (int n = 0; n < num_packets; n++) {
+    // Send an HCI packet
+    std::vector<uint8_t> write_name = COMMAND_HCI_WRITE_LOCAL_NAME;
+    // With a name
+    char new_name[] = "John Jacob Jingleheimer Schmidt ___________________0";
+    size_t new_name_length = strlen(new_name);
+    for (size_t i = 0; i < new_name_length; i++)
+      write_name.push_back(static_cast<uint8_t>(new_name[i]));
+    // And the packet number
+    size_t i = new_name_length - 1;
+    for (int digits = n; digits > 0; digits = digits / 10, i--)
+      write_name[i] = static_cast<uint8_t>('0' + digits % 10);
+    // And padding
+    for (size_t i = 0; i < 248 - new_name_length; i++)
+      write_name.push_back(static_cast<uint8_t>(0));
+
+    hidl_vec<uint8_t> cmd = write_name;
+    bluetooth->sendHciCommand(cmd);
+
+    // Check the loopback of the HCI packet
+    wait_for_event();
+    if (event_queue.size() == 0) return;
+
+    hidl_vec<uint8_t> event = event_queue.front();
+    event_queue.pop();
+    size_t compare_length =
+        (cmd.size() > static_cast<size_t>(0xff) ? static_cast<size_t>(0xff)
+                                                : cmd.size());
+    EXPECT_GT(event.size(), compare_length + EVENT_FIRST_PAYLOAD_BYTE - 1);
+
+    EXPECT_EQ(EVENT_LOOPBACK_COMMAND, event[EVENT_CODE_BYTE]);
+    EXPECT_EQ(compare_length, event[EVENT_LENGTH_BYTE]);
+
+    // Don't compare past the end of the event.
+    if (compare_length + EVENT_FIRST_PAYLOAD_BYTE > event.size()) {
+      compare_length = event.size() - EVENT_FIRST_PAYLOAD_BYTE;
+      ALOGE("Only comparing %d bytes", static_cast<int>(compare_length));
+    }
+
+    if (n == num_packets - 1) {
+      command_size = cmd.size();
+    }
+
+    for (size_t i = 0; i < compare_length; i++)
+      EXPECT_EQ(cmd[i], event[EVENT_FIRST_PAYLOAD_BYTE + i]);
+  }
+  logger.setTotalBytes(command_size * num_packets * 2);
+}
+
+// Send a SCO data packet (in Loopback mode) and check the response.
+void BluetoothHidlTest::sendAndCheckSCO(int num_packets, size_t size,
+                                        uint16_t handle) {
+  ThroughputLogger logger = {__func__};
+  for (int n = 0; n < num_packets; n++) {
+    // Send a SCO packet
+    hidl_vec<uint8_t> sco_packet;
+    std::vector<uint8_t> sco_vector;
+    sco_vector.push_back(static_cast<uint8_t>(handle & 0xff));
+    sco_vector.push_back(static_cast<uint8_t>((handle & 0x0f00) >> 8));
+    sco_vector.push_back(static_cast<uint8_t>(size & 0xff));
+    sco_vector.push_back(static_cast<uint8_t>((size & 0xff00) >> 8));
+    for (size_t i = 0; i < size; i++) {
+      sco_vector.push_back(static_cast<uint8_t>(i + n));
+    }
+    sco_packet = sco_vector;
+    bluetooth->sendScoData(sco_vector);
+
+    // Check the loopback of the SCO packet
+    EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameScoEventReceived)
+                    .no_timeout);
+    hidl_vec<uint8_t> sco_loopback = sco_queue.front();
+    sco_queue.pop();
+
+    EXPECT_EQ(sco_packet.size(), sco_loopback.size());
+    size_t successful_bytes = 0;
+
+    for (size_t i = 0; i < sco_packet.size(); i++) {
+      if (sco_packet[i] == sco_loopback[i]) {
+        successful_bytes = i;
+      } else {
+        ALOGE("Miscompare at %d (expected %x, got %x)", static_cast<int>(i),
+              sco_packet[i], sco_loopback[i]);
+        ALOGE("At %d (expected %x, got %x)", static_cast<int>(i + 1),
+              sco_packet[i + 1], sco_loopback[i + 1]);
+        break;
+      }
+    }
+    EXPECT_EQ(sco_packet.size(), successful_bytes + 1);
+  }
+  logger.setTotalBytes(num_packets * size * 2);
+}
+
+// Send an ACL data packet (in Loopback mode) and check the response.
+void BluetoothHidlTest::sendAndCheckACL(int num_packets, size_t size,
+                                        uint16_t handle) {
+  ThroughputLogger logger = {__func__};
+  for (int n = 0; n < num_packets; n++) {
+    // Send an ACL packet
+    hidl_vec<uint8_t> acl_packet;
+    std::vector<uint8_t> acl_vector;
+    acl_vector.push_back(static_cast<uint8_t>(handle & 0xff));
+    acl_vector.push_back(static_cast<uint8_t>((handle & 0x0f00) >> 8) |
+                         ACL_BROADCAST_POINT_TO_POINT |
+                         ACL_PACKET_BOUNDARY_FIRST_AUTO_FLUSHABLE);
+    acl_vector.push_back(static_cast<uint8_t>(size & 0xff));
+    acl_vector.push_back(static_cast<uint8_t>((size & 0xff00) >> 8));
+    for (size_t i = 0; i < size; i++) {
+      acl_vector.push_back(static_cast<uint8_t>(i + n));
+    }
+    acl_packet = acl_vector;
+    bluetooth->sendAclData(acl_vector);
+
+    // Check the loopback of the ACL packet
+    EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameAclEventReceived)
+                    .no_timeout);
+    hidl_vec<uint8_t> acl_loopback = acl_queue.front();
+    acl_queue.pop();
+
+    EXPECT_EQ(acl_packet.size(), acl_loopback.size());
+    size_t successful_bytes = 0;
+
+    for (size_t i = 0; i < acl_packet.size(); i++) {
+      if (acl_packet[i] == acl_loopback[i]) {
+        successful_bytes = i;
+      } else {
+        ALOGE("Miscompare at %d (expected %x, got %x)", static_cast<int>(i),
+              acl_packet[i], acl_loopback[i]);
+        ALOGE("At %d (expected %x, got %x)", static_cast<int>(i + 1),
+              acl_packet[i + 1], acl_loopback[i + 1]);
+        break;
+      }
+    }
+    EXPECT_EQ(acl_packet.size(), successful_bytes + 1);
+  }
+  logger.setTotalBytes(num_packets * size * 2);
+}
+
+// Return the number of completed packets reported by the controller.
+int BluetoothHidlTest::wait_for_completed_packets_event(uint16_t handle) {
+  int packets_processed = 0;
+  wait_for_event(false);
+  if (event_queue.size() == 0) {
+    ALOGW("%s: WaitForCallback timed out.", __func__);
+    return packets_processed;
+  }
+  while (event_queue.size() > 0) {
+    hidl_vec<uint8_t> event = event_queue.front();
+    event_queue.pop();
+
+    EXPECT_EQ(EVENT_NUMBER_OF_COMPLETED_PACKETS, event[EVENT_CODE_BYTE]);
+    EXPECT_EQ(1, event[EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES]);
+
+    uint16_t event_handle = event[3] + (event[4] << 8);
+    EXPECT_EQ(handle, event_handle);
+
+    packets_processed += event[5] + (event[6] << 8);
+  }
+  return packets_processed;
+}
+
+// Send local loopback command and initialize SCO and ACL handles.
+void BluetoothHidlTest::enterLoopbackMode(std::vector<uint16_t>* sco_handles,
+                                          std::vector<uint16_t>* acl_handles) {
+  hidl_vec<uint8_t> cmd = COMMAND_HCI_WRITE_LOOPBACK_MODE_LOCAL;
+  bluetooth->sendHciCommand(cmd);
+
+  // Receive connection complete events with data channels
+  int connection_event_count = 0;
+  bool command_complete_received = false;
+  while (true) {
+    wait_for_event(false);
+    if (event_queue.size() == 0) {
+      // Fail if there was no event received or no connections completed.
+      EXPECT_TRUE(command_complete_received);
+      EXPECT_LT(0, connection_event_count);
+      return;
+    }
+    hidl_vec<uint8_t> event = event_queue.front();
+    event_queue.pop();
+    EXPECT_GT(event.size(),
+              static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+    if (event[EVENT_CODE_BYTE] == EVENT_CONNECTION_COMPLETE) {
+      EXPECT_GT(event.size(),
+                static_cast<size_t>(EVENT_CONNECTION_COMPLETE_TYPE));
+      EXPECT_EQ(event[EVENT_LENGTH_BYTE],
+                EVENT_CONNECTION_COMPLETE_PARAM_LENGTH);
+      uint8_t connection_type = event[EVENT_CONNECTION_COMPLETE_TYPE];
+
+      EXPECT_TRUE(connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO ||
+                  connection_type == EVENT_CONNECTION_COMPLETE_TYPE_ACL);
+
+      // Save handles
+      uint16_t handle = event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE] |
+                        event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE + 1] << 8;
+      if (connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO)
+        sco_handles->push_back(handle);
+      else
+        acl_handles->push_back(handle);
+
+      ALOGD("Connect complete type = %d handle = %d",
+            event[EVENT_CONNECTION_COMPLETE_TYPE], handle);
+      connection_event_count++;
+    } else {
+      EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+      EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+      EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+      EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+      command_complete_received = true;
+    }
+  }
+}
+
+// Empty test: Initialize()/Close() are called in SetUp()/TearDown().
+TEST_P(BluetoothHidlTest, InitializeAndClose) {}
+
+// Send an HCI Reset with sendHciCommand and wait for a command complete event.
+TEST_P(BluetoothHidlTest, HciReset) {
+  hidl_vec<uint8_t> cmd = COMMAND_HCI_RESET;
+  bluetooth->sendHciCommand(cmd);
+
+  wait_for_command_complete_event(cmd);
+}
+
+// Read and check the HCI version of the controller.
+TEST_P(BluetoothHidlTest, HciVersionTest) {
+  hidl_vec<uint8_t> cmd = COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION;
+  bluetooth->sendHciCommand(cmd);
+
+  wait_for_event();
+  if (event_queue.size() == 0) return;
+
+  hidl_vec<uint8_t> event = event_queue.front();
+  event_queue.pop();
+  EXPECT_GT(event.size(), static_cast<size_t>(EVENT_LOCAL_LMP_VERSION_BYTE));
+
+  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+  EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+
+  EXPECT_LE(HCI_MINIMUM_HCI_VERSION, event[EVENT_LOCAL_HCI_VERSION_BYTE]);
+  EXPECT_LE(HCI_MINIMUM_LMP_VERSION, event[EVENT_LOCAL_LMP_VERSION_BYTE]);
+}
+
+// Send an unknown HCI command and wait for the error message.
+TEST_P(BluetoothHidlTest, HciUnknownCommand) {
+  hidl_vec<uint8_t> cmd = COMMAND_HCI_SHOULD_BE_UNKNOWN;
+  bluetooth->sendHciCommand(cmd);
+
+  wait_for_event();
+  if (event_queue.size() == 0) return;
+
+  hidl_vec<uint8_t> event = event_queue.front();
+  event_queue.pop();
+
+  EXPECT_GT(event.size(),
+            static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+  if (event[EVENT_CODE_BYTE] == EVENT_COMMAND_COMPLETE) {
+    EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+    EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+    EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
+              event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+  } else {
+    EXPECT_EQ(EVENT_COMMAND_STATUS, event[EVENT_CODE_BYTE]);
+    EXPECT_EQ(cmd[0], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE]);
+    EXPECT_EQ(cmd[1], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1]);
+    EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
+              event[EVENT_COMMAND_STATUS_STATUS_BYTE]);
+  }
+}
+
+// Enter loopback mode, but don't send any packets.
+TEST_P(BluetoothHidlTest, WriteLoopbackMode) {
+  std::vector<uint16_t> sco_connection_handles;
+  std::vector<uint16_t> acl_connection_handles;
+  enterLoopbackMode(&sco_connection_handles, &acl_connection_handles);
+}
+
+// Enter loopback mode and send single packets.
+TEST_P(BluetoothHidlTest, LoopbackModeSinglePackets) {
+  setBufferSizes();
+
+  std::vector<uint16_t> sco_connection_handles;
+  std::vector<uint16_t> acl_connection_handles;
+  enterLoopbackMode(&sco_connection_handles, &acl_connection_handles);
+
+  sendAndCheckHCI(1);
+
+  // This should work, but breaks on some current platforms.  Figure out how to
+  // grandfather older devices but test new ones.
+  if (0 && sco_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_sco_data_packet_length);
+    sendAndCheckSCO(1, max_sco_data_packet_length, sco_connection_handles[0]);
+    int sco_packets_sent = 1;
+    int completed_packets =
+        wait_for_completed_packets_event(sco_connection_handles[0]);
+    if (sco_packets_sent != completed_packets) {
+      ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+            sco_packets_sent, completed_packets);
+    }
+  }
+
+  if (acl_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_acl_data_packet_length);
+    sendAndCheckACL(1, max_acl_data_packet_length, acl_connection_handles[0]);
+    int acl_packets_sent = 1;
+    int completed_packets =
+        wait_for_completed_packets_event(acl_connection_handles[0]);
+    if (acl_packets_sent != completed_packets) {
+      ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+            acl_packets_sent, completed_packets);
+    }
+  }
+}
+
+// Enter loopback mode and send packets for bandwidth measurements.
+TEST_P(BluetoothHidlTest, LoopbackModeBandwidth) {
+  setBufferSizes();
+
+  std::vector<uint16_t> sco_connection_handles;
+  std::vector<uint16_t> acl_connection_handles;
+  enterLoopbackMode(&sco_connection_handles, &acl_connection_handles);
+
+  sendAndCheckHCI(NUM_HCI_COMMANDS_BANDWIDTH);
+
+  // This should work, but breaks on some current platforms.  Figure out how to
+  // grandfather older devices but test new ones.
+  if (0 && sco_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_sco_data_packet_length);
+    sendAndCheckSCO(NUM_SCO_PACKETS_BANDWIDTH, max_sco_data_packet_length,
+                    sco_connection_handles[0]);
+    int sco_packets_sent = NUM_SCO_PACKETS_BANDWIDTH;
+    int completed_packets =
+        wait_for_completed_packets_event(sco_connection_handles[0]);
+    if (sco_packets_sent != completed_packets) {
+      ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+            sco_packets_sent, completed_packets);
+    }
+  }
+
+  if (acl_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_acl_data_packet_length);
+    sendAndCheckACL(NUM_ACL_PACKETS_BANDWIDTH, max_acl_data_packet_length,
+                    acl_connection_handles[0]);
+    int acl_packets_sent = NUM_ACL_PACKETS_BANDWIDTH;
+    int completed_packets =
+        wait_for_completed_packets_event(acl_connection_handles[0]);
+    if (acl_packets_sent != completed_packets) {
+      ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+            acl_packets_sent, completed_packets);
+    }
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, BluetoothHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IBluetoothHci::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/bluetooth/a2dp/1.0/Android.bp b/bluetooth/a2dp/1.0/Android.bp
index fa46a1c..02f224a 100644
--- a/bluetooth/a2dp/1.0/Android.bp
+++ b/bluetooth/a2dp/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/bluetooth/a2dp/1.0/default/Android.bp b/bluetooth/a2dp/1.0/default/Android.bp
index 8e6f32d..5264899 100644
--- a/bluetooth/a2dp/1.0/default/Android.bp
+++ b/bluetooth/a2dp/1.0/default/Android.bp
@@ -1,5 +1,5 @@
 cc_library_shared {
-    name: "android.hardware.bluetooth.a2dp@1.0-impl",
+    name: "android.hardware.bluetooth.a2dp@1.0-impl.mock",
     relative_install_path: "hw",
     vendor: true,
     srcs: [
@@ -7,7 +7,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.bluetooth.a2dp@1.0",
     ],
diff --git a/bluetooth/audio/2.0/Android.bp b/bluetooth/audio/2.0/Android.bp
index a020f22..6bf0070 100644
--- a/bluetooth/audio/2.0/Android.bp
+++ b/bluetooth/audio/2.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/bluetooth/audio/2.0/default/Android.bp b/bluetooth/audio/2.0/default/Android.bp
index 1dfc05d..0db0028 100644
--- a/bluetooth/audio/2.0/default/Android.bp
+++ b/bluetooth/audio/2.0/default/Android.bp
@@ -19,7 +19,6 @@
         "libcutils",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
@@ -41,7 +40,6 @@
         "libcutils",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
index 85e8742..838d1cc 100644
--- a/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
@@ -156,8 +156,9 @@
 
   static constexpr PcmParameters kInvalidPcmParameters = {
       .sampleRate = SampleRate::RATE_UNKNOWN,
+      .channelMode = ChannelMode::UNKNOWN,
       .bitsPerSample = BitsPerSample::BITS_UNKNOWN,
-      .channelMode = ChannelMode::UNKNOWN};
+  };
   // can't be constexpr because of non-literal type
   static const CodecConfiguration kInvalidCodecConfiguration;
 
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
index 292e28b..6ea61e1 100644
--- a/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
@@ -94,16 +94,18 @@
 static const AptxParameters kDefaultOffloadAptxCapability = {
     .sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 |
                                           SampleRate::RATE_48000),
+    .channelMode = ChannelMode::STEREO,
     .bitsPerSample = BitsPerSample::BITS_16,
-    .channelMode = ChannelMode::STEREO};
+};
 
 // aptX HD: mSampleRate:(44100|48000), mBitsPerSample:(24),
 //          mChannelMode:(STEREO)
 static const AptxParameters kDefaultOffloadAptxHdCapability = {
     .sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 |
                                           SampleRate::RATE_48000),
+    .channelMode = ChannelMode::STEREO,
     .bitsPerSample = BitsPerSample::BITS_24,
-    .channelMode = ChannelMode::STEREO};
+};
 
 const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {
     {.codecType = CodecType::SBC, .capabilities = {}},
diff --git a/bluetooth/audio/2.0/vts/functional/Android.bp b/bluetooth/audio/2.0/vts/functional/Android.bp
index b672fe4..b778b97 100644
--- a/bluetooth/audio/2.0/vts/functional/Android.bp
+++ b/bluetooth/audio/2.0/vts/functional/Android.bp
@@ -9,4 +9,5 @@
     shared_libs: [
         "libfmq",
     ],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp b/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp
index 9572d3f..b3cb6f7 100644
--- a/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp
+++ b/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp
@@ -21,12 +21,13 @@
 #include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvider.h>
 #include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
 #include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/MQDescriptor.h>
+#include <hidl/ServiceManagement.h>
 #include <utils/Log.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 
 using ::android::sp;
 using ::android::hardware::hidl_vec;
@@ -105,34 +106,13 @@
 }
 }  // namespace
 
-// Test environment for Bluetooth Audio HAL.
-class BluetoothAudioHidlEnvironment
-    : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static BluetoothAudioHidlEnvironment* Instance() {
-    static BluetoothAudioHidlEnvironment* instance =
-        new BluetoothAudioHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override {
-    registerTestService<IBluetoothAudioProvidersFactory>();
-  }
-
- private:
-  BluetoothAudioHidlEnvironment() {}
-};
-
 // The base test class for Bluetooth Audio HAL.
 class BluetoothAudioProvidersFactoryHidlTest
-    : public ::testing::VtsHalHidlTargetTestBase {
+    : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-    providers_factory_ = ::testing::VtsHalHidlTargetTestBase::getService<
-        IBluetoothAudioProvidersFactory>(
-        BluetoothAudioHidlEnvironment::Instance()
-            ->getServiceName<IBluetoothAudioProvidersFactory>());
+    providers_factory_ =
+        IBluetoothAudioProvidersFactory::getService(GetParam());
     ASSERT_NE(providers_factory_, nullptr);
   }
 
@@ -300,13 +280,13 @@
 /**
  * Test whether we can get the FactoryService from HIDL
  */
-TEST_F(BluetoothAudioProvidersFactoryHidlTest, GetProvidersFactoryService) {}
+TEST_P(BluetoothAudioProvidersFactoryHidlTest, GetProvidersFactoryService) {}
 
 /**
  * Test whether we can open a provider for each provider returned by
  * getProviderCapabilities() with non-empty capabalities
  */
-TEST_F(BluetoothAudioProvidersFactoryHidlTest,
+TEST_P(BluetoothAudioProvidersFactoryHidlTest,
        OpenProviderAndCheckCapabilitiesBySession) {
   for (auto session_type : session_types_) {
     GetProviderCapabilitiesHelper(session_type);
@@ -341,14 +321,14 @@
 /**
  * Test whether we can open a provider of type
  */
-TEST_F(BluetoothAudioProviderA2dpSoftwareHidlTest, OpenA2dpSoftwareProvider) {}
+TEST_P(BluetoothAudioProviderA2dpSoftwareHidlTest, OpenA2dpSoftwareProvider) {}
 
 /**
  * Test whether each provider of type
  * SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with
  * different PCM config
  */
-TEST_F(BluetoothAudioProviderA2dpSoftwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpSoftwareHidlTest,
        StartAndEndA2dpSoftwareSessionWithPossiblePcmConfig) {
   bool is_codec_config_valid;
   std::unique_ptr<DataMQ> tempDataMQ;
@@ -616,14 +596,14 @@
 /**
  * Test whether we can open a provider of type
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest, OpenA2dpHardwareProvider) {}
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest, OpenA2dpHardwareProvider) {}
 
 /**
  * Test whether each provider of type
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
  * SBC hardware encoding config
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
        StartAndEndA2dpSbcHardwareSession) {
   if (!IsOffloadSupported()) {
     return;
@@ -658,7 +638,7 @@
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
  * AAC hardware encoding config
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
        StartAndEndA2dpAacHardwareSession) {
   if (!IsOffloadSupported()) {
     return;
@@ -693,7 +673,7 @@
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
  * LDAC hardware encoding config
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
        StartAndEndA2dpLdacHardwareSession) {
   if (!IsOffloadSupported()) {
     return;
@@ -728,7 +708,7 @@
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
  * AptX hardware encoding config
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
        StartAndEndA2dpAptxHardwareSession) {
   if (!IsOffloadSupported()) {
     return;
@@ -767,7 +747,7 @@
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
  * an invalid codec config
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
        StartAndEndA2dpHardwareSessionInvalidCodecConfig) {
   if (!IsOffloadSupported()) {
     return;
@@ -857,7 +837,7 @@
  * SessionType::HEARING_AID_HARDWARE_ENCODING_DATAPATH can be started and
  * stopped with SBC hardware encoding config
  */
-TEST_F(BluetoothAudioProviderHearingAidSoftwareHidlTest,
+TEST_P(BluetoothAudioProviderHearingAidSoftwareHidlTest,
        OpenHearingAidSoftwareProvider) {}
 
 /**
@@ -865,7 +845,7 @@
  * SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH can be started and
  * stopped with different PCM config
  */
-TEST_F(BluetoothAudioProviderHearingAidSoftwareHidlTest,
+TEST_P(BluetoothAudioProviderHearingAidSoftwareHidlTest,
        StartAndEndHearingAidSessionWithPossiblePcmConfig) {
   bool is_codec_config_valid;
   std::unique_ptr<DataMQ> tempDataMQ;
@@ -904,12 +884,25 @@
   }      // SampleRate
 }
 
-int main(int argc, char** argv) {
-  ::testing::AddGlobalTestEnvironment(
-      BluetoothAudioHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  BluetoothAudioHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
+static const std::vector<std::string> kAudioInstances =
+    android::hardware::getAllHalInstanceNames(
+        IBluetoothAudioProvidersFactory::descriptor);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProvidersFactoryHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderA2dpSoftwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderA2dpHardwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderHearingAidSoftwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/boot/1.0/Android.bp b/boot/1.0/Android.bp
index b580cac..5568436 100644
--- a/boot/1.0/Android.bp
+++ b/boot/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/boot/1.0/default/Android.bp b/boot/1.0/default/Android.bp
index 397c56d..fdf7a1e 100644
--- a/boot/1.0/default/Android.bp
+++ b/boot/1.0/default/Android.bp
@@ -9,7 +9,6 @@
     shared_libs: [
         "liblog",
         "libhidlbase",
-        "libhidltransport",
         "libhardware",
         "libutils",
         "android.hardware.boot@1.0",
@@ -29,7 +28,6 @@
         "liblog",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.boot@1.0",
     ],
diff --git a/boot/1.0/default/Android.mk b/boot/1.0/default/Android.mk
deleted file mode 100644
index 7ccc4c8..0000000
--- a/boot/1.0/default/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# TODO(connoro): Remove this file once we eliminate existing usage of
-# PRODUCT_STATIC_BOOT_CONTROL_HAL
-
-LOCAL_PATH := $(call my-dir)
-
-ifneq ($(strip $(PRODUCT_STATIC_BOOT_CONTROL_HAL)),)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.hardware.boot@1.0-impl-wrapper.recovery
-LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_MULTILIB := first
-ifeq ($(TARGET_IS_64_BIT),true)
-LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/lib64/hw
-else
-LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/lib/hw
-endif
-LOCAL_SRC_FILES := BootControl.cpp
-LOCAL_CFLAGS := -DBOOT_CONTROL_RECOVERY
-LOCAL_SHARED_LIBRARIES := \
-    libbase.recovery \
-    liblog.recovery \
-    libhidlbase.recovery \
-    libhidltransport.recovery \
-    libhardware.recovery \
-    libutils.recovery \
-    android.hardware.boot@1.0.recovery
-LOCAL_STATIC_LIBRARIES := $(PRODUCT_STATIC_BOOT_CONTROL_HAL)
-include $(BUILD_SHARED_LIBRARY)
-
-endif
diff --git a/boot/1.0/default/android.hardware.boot@1.0-service.rc b/boot/1.0/default/android.hardware.boot@1.0-service.rc
index 32f3a45..b8125e1 100644
--- a/boot/1.0/default/android.hardware.boot@1.0-service.rc
+++ b/boot/1.0/default/android.hardware.boot@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.boot-hal-1-0 /vendor/bin/hw/android.hardware.boot@1.0-service
+    interface android.hardware.boot@1.0::IBootControl default
     class early_hal
     user root
     group root
diff --git a/boot/1.0/vts/functional/Android.bp b/boot/1.0/vts/functional/Android.bp
index 5d1a9cb..5244b95 100644
--- a/boot/1.0/vts/functional/Android.bp
+++ b/boot/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalBootV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.boot@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp b/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp
index 2f2052c..fbddf6d 100644
--- a/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp
+++ b/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp
@@ -21,8 +21,9 @@
 
 #include <android/hardware/boot/1.0/IBootControl.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <unordered_set>
 
@@ -37,30 +38,17 @@
 using std::unordered_set;
 using std::vector;
 
-// Test environment for Boot HIDL HAL.
-class BootHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static BootHidlEnvironment* Instance() {
-        static BootHidlEnvironment* instance = new BootHidlEnvironment;
-        return instance;
+// The main test class for the Boot HIDL HAL.
+class BootHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        boot = IBootControl::getService(GetParam());
+        ASSERT_NE(boot, nullptr);
     }
 
-    virtual void registerTestServices() override { registerTestService<IBootControl>(); }
-};
+    virtual void TearDown() override {}
 
-// The main test class for the Boot HIDL HAL.
-class BootHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
-  virtual void SetUp() override {
-      boot = ::testing::VtsHalHidlTargetTestBase::getService<IBootControl>(
-          BootHidlEnvironment::Instance()->getServiceName<IBootControl>());
-      ASSERT_NE(boot, nullptr);
-  }
-
-  virtual void TearDown() override {}
-
-  sp<IBootControl> boot;
+    sp<IBootControl> boot;
 };
 
 auto generate_callback(CommandResult *dest) {
@@ -68,108 +56,105 @@
 }
 
 // Sanity check Boot::getNumberSlots().
-TEST_F(BootHidlTest, GetNumberSlots) {
-  uint32_t slots = boot->getNumberSlots();
-  EXPECT_LE((uint32_t)2, slots);
+TEST_P(BootHidlTest, GetNumberSlots) {
+    uint32_t slots = boot->getNumberSlots();
+    EXPECT_LE((uint32_t)2, slots);
 }
 
 // Sanity check Boot::getCurrentSlot().
-TEST_F(BootHidlTest, GetCurrentSlot) {
-  Slot curSlot = boot->getCurrentSlot();
-  uint32_t slots = boot->getNumberSlots();
-  EXPECT_LT(curSlot, slots);
+TEST_P(BootHidlTest, GetCurrentSlot) {
+    Slot curSlot = boot->getCurrentSlot();
+    uint32_t slots = boot->getNumberSlots();
+    EXPECT_LT(curSlot, slots);
 }
 
 // Sanity check Boot::markBootSuccessful().
-TEST_F(BootHidlTest, MarkBootSuccessful) {
-  CommandResult cr;
-  Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
-  ASSERT_TRUE(result.isOk());
-  if (cr.success) {
-    Slot curSlot = boot->getCurrentSlot();
-    BoolResult ret = boot->isSlotMarkedSuccessful(curSlot);
-    EXPECT_EQ(BoolResult::TRUE, ret);
-  }
+TEST_P(BootHidlTest, MarkBootSuccessful) {
+    CommandResult cr;
+    Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
+    ASSERT_TRUE(result.isOk());
+    if (cr.success) {
+        Slot curSlot = boot->getCurrentSlot();
+        BoolResult ret = boot->isSlotMarkedSuccessful(curSlot);
+        EXPECT_EQ(BoolResult::TRUE, ret);
+    }
 }
 
 // Sanity check Boot::setActiveBootSlot() on good and bad inputs.
-TEST_F(BootHidlTest, SetActiveBootSlot) {
-  for (Slot s = 0; s < 2; s++) {
-    CommandResult cr;
-    Return<void> result = boot->setActiveBootSlot(s, generate_callback(&cr));
-    EXPECT_TRUE(result.isOk());
-  }
-  {
-    // Restore original flags to avoid problems on reboot
-    CommandResult cr;
-    Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
-    EXPECT_TRUE(result.isOk());
-    EXPECT_TRUE(cr.success);
-  }
-  {
-    CommandResult cr;
-    uint32_t slots = boot->getNumberSlots();
-    Return<void> result =
-        boot->setActiveBootSlot(slots, generate_callback(&cr));
-    ASSERT_TRUE(result.isOk());
-    EXPECT_EQ(false, cr.success);
-  }
+TEST_P(BootHidlTest, SetActiveBootSlot) {
+    for (Slot s = 0; s < 2; s++) {
+        CommandResult cr;
+        Return<void> result = boot->setActiveBootSlot(s, generate_callback(&cr));
+        EXPECT_TRUE(result.isOk());
+    }
+    {
+        // Restore original flags to avoid problems on reboot
+        CommandResult cr;
+        Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
+        EXPECT_TRUE(result.isOk());
+        EXPECT_TRUE(cr.success);
+    }
+    {
+        CommandResult cr;
+        uint32_t slots = boot->getNumberSlots();
+        Return<void> result = boot->setActiveBootSlot(slots, generate_callback(&cr));
+        ASSERT_TRUE(result.isOk());
+        EXPECT_EQ(false, cr.success);
+    }
 }
 
 // Sanity check Boot::setSlotAsUnbootable() on good and bad inputs.
-TEST_F(BootHidlTest, SetSlotAsUnbootable) {
-  {
-    CommandResult cr;
-    Slot curSlot = boot->getCurrentSlot();
-    Slot otherSlot = curSlot ? 0 : 1;
-    Return<void> result =
-        boot->setSlotAsUnbootable(otherSlot, generate_callback(&cr));
-    EXPECT_TRUE(result.isOk());
-    if (cr.success) {
-      EXPECT_EQ(BoolResult::FALSE, boot->isSlotBootable(otherSlot));
+TEST_P(BootHidlTest, SetSlotAsUnbootable) {
+    {
+        CommandResult cr;
+        Slot curSlot = boot->getCurrentSlot();
+        Slot otherSlot = curSlot ? 0 : 1;
+        Return<void> result = boot->setSlotAsUnbootable(otherSlot, generate_callback(&cr));
+        EXPECT_TRUE(result.isOk());
+        if (cr.success) {
+            EXPECT_EQ(BoolResult::FALSE, boot->isSlotBootable(otherSlot));
 
-      // Restore original flags to avoid problems on reboot
-      result = boot->setActiveBootSlot(otherSlot, generate_callback(&cr));
-      EXPECT_TRUE(result.isOk());
-      EXPECT_TRUE(cr.success);
-      result = boot->setActiveBootSlot(curSlot, generate_callback(&cr));
-      EXPECT_TRUE(result.isOk());
-      EXPECT_TRUE(cr.success);
-      result = boot->markBootSuccessful(generate_callback(&cr));
-      EXPECT_TRUE(result.isOk());
-      EXPECT_TRUE(cr.success);
+            // Restore original flags to avoid problems on reboot
+            result = boot->setActiveBootSlot(otherSlot, generate_callback(&cr));
+            EXPECT_TRUE(result.isOk());
+            EXPECT_TRUE(cr.success);
+            result = boot->setActiveBootSlot(curSlot, generate_callback(&cr));
+            EXPECT_TRUE(result.isOk());
+            EXPECT_TRUE(cr.success);
+            result = boot->markBootSuccessful(generate_callback(&cr));
+            EXPECT_TRUE(result.isOk());
+            EXPECT_TRUE(cr.success);
+        }
     }
-  }
-  {
-    CommandResult cr;
-    uint32_t slots = boot->getNumberSlots();
-    Return<void> result =
-        boot->setSlotAsUnbootable(slots, generate_callback(&cr));
-    EXPECT_TRUE(result.isOk());
-    EXPECT_EQ(false, cr.success);
-  }
+    {
+        CommandResult cr;
+        uint32_t slots = boot->getNumberSlots();
+        Return<void> result = boot->setSlotAsUnbootable(slots, generate_callback(&cr));
+        EXPECT_TRUE(result.isOk());
+        EXPECT_EQ(false, cr.success);
+    }
 }
 
 // Sanity check Boot::isSlotBootable() on good and bad inputs.
-TEST_F(BootHidlTest, IsSlotBootable) {
-  for (Slot s = 0; s < 2; s++) {
-    EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotBootable(s));
-  }
-  uint32_t slots = boot->getNumberSlots();
-  EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotBootable(slots));
+TEST_P(BootHidlTest, IsSlotBootable) {
+    for (Slot s = 0; s < 2; s++) {
+        EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotBootable(s));
+    }
+    uint32_t slots = boot->getNumberSlots();
+    EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotBootable(slots));
 }
 
 // Sanity check Boot::isSlotMarkedSuccessful() on good and bad inputs.
-TEST_F(BootHidlTest, IsSlotMarkedSuccessful) {
-  for (Slot s = 0; s < 2; s++) {
-    EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(s));
-  }
-  uint32_t slots = boot->getNumberSlots();
-  EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(slots));
+TEST_P(BootHidlTest, IsSlotMarkedSuccessful) {
+    for (Slot s = 0; s < 2; s++) {
+        EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(s));
+    }
+    uint32_t slots = boot->getNumberSlots();
+    EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(slots));
 }
 
 // Sanity check Boot::getSuffix() on good and bad inputs.
-TEST_F(BootHidlTest, GetSuffix) {
+TEST_P(BootHidlTest, GetSuffix) {
     string suffixStr;
     unordered_set<string> suffixes;
     auto cb = [&](hidl_string suffix) { suffixStr = suffix.c_str(); };
@@ -191,11 +176,7 @@
     }
 }
 
-int main(int argc, char **argv) {
-    ::testing::AddGlobalTestEnvironment(BootHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    BootHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, BootHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBootControl::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/boot/1.1/Android.bp b/boot/1.1/Android.bp
new file mode 100644
index 0000000..6a8d57a
--- /dev/null
+++ b/boot/1.1/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.boot@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IBootControl.hal",
+    ],
+    interfaces: [
+        "android.hardware.boot@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/boot/1.1/IBootControl.hal b/boot/1.1/IBootControl.hal
new file mode 100644
index 0000000..939dfb3
--- /dev/null
+++ b/boot/1.1/IBootControl.hal
@@ -0,0 +1,66 @@
+/*
+ * Copyright 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.boot@1.1;
+
+import @1.0::IBootControl;
+
+interface IBootControl extends @1.0::IBootControl {
+    /**
+     * Sets whether a snapshot-merge of any dynamic partition is in progress.
+     *
+     * After the merge status is set to a given value, subsequent calls to
+     * getSnapshotMergeStatus must return the set value.
+     *
+     * The merge status must be persistent across reboots. That is, getSnapshotMergeStatus
+     * must return the same value after a reboot if the merge status is not altered in any way
+     * (e.g. set by setSnapshotMergeStatus or set to CANCELLED by bootloader).
+     *
+     * Read/write access to the merge status must be atomic. When the HAL is processing a
+     * setSnapshotMergeStatus call, all subsequent calls to getSnapshotMergeStatus must block until
+     * setSnapshotMergeStatus has returned.
+     *
+     * A MERGING state indicates that dynamic partitions are partially comprised by blocks in the
+     * userdata partition.
+     *
+     * When the merge status is set to MERGING, the following operations must be prohibited from the
+     * bootloader:
+     *  - Flashing or erasing "userdata" or "metadata".
+     *
+     * The following operations may be prohibited when the status is set to MERGING. If not
+     * prohibited, it is recommended that the user receive a warning.
+     *  - Changing the active slot (e.g. via "fastboot set_active")
+     *
+     * @param status Merge status.
+     *
+     * @return success True on success, false otherwise.
+     */
+    setSnapshotMergeStatus(MergeStatus status) generates (bool success);
+
+    /**
+     * Returns whether a snapshot-merge of any dynamic partition is in progress.
+     *
+     * This function must return the merge status set by the last setSnapshotMergeStatus call and
+     * recorded by the bootloader with one exception. If the partitions are being flashed from the
+     * bootloader such that the pending merge must be canceled (for example, if the super partition
+     * is being flashed), this function must return CANCELLED.
+     *
+     * @return success True if the merge status is read successfully, false otherwise.
+     * @return status Merge status.
+     */
+    getSnapshotMergeStatus() generates (MergeStatus status);
+};
+
diff --git a/boot/1.1/default/Android.bp b/boot/1.1/default/Android.bp
new file mode 100644
index 0000000..abf1bf9
--- /dev/null
+++ b/boot/1.1/default/Android.bp
@@ -0,0 +1,48 @@
+cc_library_shared {
+    name: "android.hardware.boot@1.1-impl",
+    stem: "android.hardware.boot@1.0-impl-1.1",
+    defaults: [
+        "hidl_defaults",
+        "libboot_control_defaults",
+    ],
+    relative_install_path: "hw",
+    vendor: true,
+    recovery_available: true,
+    srcs: ["BootControl.cpp"],
+
+    shared_libs: [
+        "liblog",
+        "libhidlbase",
+        "libhardware",
+        "libutils",
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
+    ],
+    static_libs: [
+        "libboot_control",
+        "libfstab",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.boot@1.1-service",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.boot@1.1-service.rc"],
+    srcs: ["service.cpp"],
+
+    vintf_fragments: [
+        "android.hardware.boot@1.1.xml",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libhardware",
+        "libhidlbase",
+        "libutils",
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
+    ],
+
+}
diff --git a/boot/1.1/default/BootControl.cpp b/boot/1.1/default/BootControl.cpp
new file mode 100644
index 0000000..c9c62a4
--- /dev/null
+++ b/boot/1.1/default/BootControl.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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 "android.hardware.boot@1.1-impl"
+
+#include <memory>
+
+#include <log/log.h>
+
+#include "BootControl.h"
+
+namespace android {
+namespace hardware {
+namespace boot {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::boot::V1_0::CommandResult;
+
+bool BootControl::Init() {
+    return impl_.Init();
+}
+
+// Methods from ::android::hardware::boot::V1_0::IBootControl follow.
+Return<uint32_t> BootControl::getNumberSlots() {
+    return impl_.GetNumberSlots();
+}
+
+Return<uint32_t> BootControl::getCurrentSlot() {
+    return impl_.GetCurrentSlot();
+}
+
+Return<void> BootControl::markBootSuccessful(markBootSuccessful_cb _hidl_cb) {
+    struct CommandResult cr;
+    if (impl_.MarkBootSuccessful()) {
+        cr.success = true;
+        cr.errMsg = "Success";
+    } else {
+        cr.success = false;
+        cr.errMsg = "Operation failed";
+    }
+    _hidl_cb(cr);
+    return Void();
+}
+
+Return<void> BootControl::setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) {
+    struct CommandResult cr;
+    if (impl_.SetActiveBootSlot(slot)) {
+        cr.success = true;
+        cr.errMsg = "Success";
+    } else {
+        cr.success = false;
+        cr.errMsg = "Operation failed";
+    }
+    _hidl_cb(cr);
+    return Void();
+}
+
+Return<void> BootControl::setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) {
+    struct CommandResult cr;
+    if (impl_.SetSlotAsUnbootable(slot)) {
+        cr.success = true;
+        cr.errMsg = "Success";
+    } else {
+        cr.success = false;
+        cr.errMsg = "Operation failed";
+    }
+    _hidl_cb(cr);
+    return Void();
+}
+
+Return<BoolResult> BootControl::isSlotBootable(uint32_t slot) {
+    if (!impl_.IsValidSlot(slot)) {
+        return BoolResult::INVALID_SLOT;
+    }
+    return impl_.IsSlotBootable(slot) ? BoolResult::TRUE : BoolResult::FALSE;
+}
+
+Return<BoolResult> BootControl::isSlotMarkedSuccessful(uint32_t slot) {
+    if (!impl_.IsValidSlot(slot)) {
+        return BoolResult::INVALID_SLOT;
+    }
+    return impl_.IsSlotMarkedSuccessful(slot) ? BoolResult::TRUE : BoolResult::FALSE;
+}
+
+Return<void> BootControl::getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) {
+    hidl_string ans;
+    const char* suffix = impl_.GetSuffix(slot);
+    if (suffix) {
+        ans = suffix;
+    }
+    _hidl_cb(ans);
+    return Void();
+}
+
+Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus status) {
+    return impl_.SetSnapshotMergeStatus(status);
+}
+
+Return<MergeStatus> BootControl::getSnapshotMergeStatus() {
+    return impl_.GetSnapshotMergeStatus();
+}
+
+IBootControl* HIDL_FETCH_IBootControl(const char* /* hal */) {
+    auto module = std::make_unique<BootControl>();
+    if (!module->Init()) {
+        ALOGE("Could not initialize BootControl module");
+        return nullptr;
+    }
+    return module.release();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace boot
+}  // namespace hardware
+}  // namespace android
diff --git a/boot/1.1/default/BootControl.h b/boot/1.1/default/BootControl.h
new file mode 100644
index 0000000..75511b6
--- /dev/null
+++ b/boot/1.1/default/BootControl.h
@@ -0,0 +1,64 @@
+/*
+ * 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 <android/hardware/boot/1.1/IBootControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <libboot_control/libboot_control.h>
+
+namespace android {
+namespace hardware {
+namespace boot {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::boot::V1_0::BoolResult;
+using ::android::hardware::boot::V1_1::IBootControl;
+using ::android::hardware::boot::V1_1::MergeStatus;
+
+class BootControl : public IBootControl {
+  public:
+    bool Init();
+
+    // Methods from ::android::hardware::boot::V1_0::IBootControl follow.
+    Return<uint32_t> getNumberSlots() override;
+    Return<uint32_t> getCurrentSlot() override;
+    Return<void> markBootSuccessful(markBootSuccessful_cb _hidl_cb) override;
+    Return<void> setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) override;
+    Return<void> setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) override;
+    Return<BoolResult> isSlotBootable(uint32_t slot) override;
+    Return<BoolResult> isSlotMarkedSuccessful(uint32_t slot) override;
+    Return<void> getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) override;
+
+    // Methods from ::android::hardware::boot::V1_1::IBootControl follow.
+    Return<bool> setSnapshotMergeStatus(MergeStatus status) override;
+    Return<MergeStatus> getSnapshotMergeStatus() override;
+
+  private:
+    android::bootable::BootControl impl_;
+};
+
+extern "C" IBootControl* HIDL_FETCH_IBootControl(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace boot
+}  // namespace hardware
+}  // namespace android
diff --git a/boot/1.1/default/android.hardware.boot@1.1-service.rc b/boot/1.1/default/android.hardware.boot@1.1-service.rc
new file mode 100644
index 0000000..83fa9d0
--- /dev/null
+++ b/boot/1.1/default/android.hardware.boot@1.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.boot-hal-1-1 /vendor/bin/hw/android.hardware.boot@1.1-service
+    interface android.hardware.boot@1.0::IBootControl default
+    interface android.hardware.boot@1.1::IBootControl default
+    class early_hal
+    user root
+    group root
diff --git a/boot/1.1/default/android.hardware.boot@1.1.xml b/boot/1.1/default/android.hardware.boot@1.1.xml
new file mode 100644
index 0000000..83d5d2e
--- /dev/null
+++ b/boot/1.1/default/android.hardware.boot@1.1.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.boot</name>
+        <transport>hwbinder</transport>
+        <fqname>@1.1::IBootControl/default</fqname>
+    </hal>
+</manifest>
diff --git a/boot/1.1/default/service.cpp b/boot/1.1/default/service.cpp
new file mode 100644
index 0000000..89251b5
--- /dev/null
+++ b/boot/1.1/default/service.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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 "android.hardware.boot@1.1-service"
+
+#include <android/hardware/boot/1.1/IBootControl.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::defaultPassthroughServiceImplementation;
+using IBootControl_V1_0 = android::hardware::boot::V1_0::IBootControl;
+using IBootControl_V1_1 = android::hardware::boot::V1_1::IBootControl;
+
+int main(int /* argc */, char* /* argv */[]) {
+    return defaultPassthroughServiceImplementation<IBootControl_V1_0, IBootControl_V1_1>();
+}
diff --git a/boot/1.1/types.hal b/boot/1.1/types.hal
new file mode 100644
index 0000000..6346078
--- /dev/null
+++ b/boot/1.1/types.hal
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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.boot@1.1;
+
+enum MergeStatus : int32_t {
+    /**
+     * No snapshot or merge is in progress.
+     */
+    NONE = 0,
+
+    /**
+     * The merge status could not be determined.
+     */
+    UNKNOWN,
+
+    /**
+     * Partitions are being snapshotted, but no merge has been started.
+     */
+    SNAPSHOTTED,
+
+    /**
+     * At least one partition has merge is in progress.
+     */
+    MERGING,
+
+    /**
+     * A merge was in progress, but it was canceled by the bootloader.
+     */
+    CANCELLED,
+};
diff --git a/boot/1.1/vts/functional/Android.bp b/boot/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..49ea09a
--- /dev/null
+++ b/boot/1.1/vts/functional/Android.bp
@@ -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.
+//
+
+cc_test {
+    name: "VtsHalBootV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBootV1_1TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
+        "libgmock",
+    ],
+    test_suites: ["device-tests"],
+}
+
diff --git a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
new file mode 100644
index 0000000..7c58ef3
--- /dev/null
+++ b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 "boot_hidl_hal_test"
+
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android/hardware/boot/1.1/IBootControl.h>
+#include <android/hardware/boot/1.1/types.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <unistd.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::boot::V1_1::IBootControl;
+using ::android::hardware::boot::V1_1::MergeStatus;
+using ::testing::Contains;
+
+class BootHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        boot = IBootControl::getService(GetParam());
+        ASSERT_NE(boot, nullptr);
+
+        LOG(INFO) << "Test is remote " << boot->isRemote();
+    }
+
+    sp<IBootControl> boot;
+};
+
+static std::vector<MergeStatus> ValidMergeStatusValues() {
+    std::vector<MergeStatus> values;
+    for (const auto value : hidl_enum_range<MergeStatus>()) {
+        if (value == MergeStatus::UNKNOWN) {
+            continue;
+        }
+        values.push_back(value);
+    }
+    return values;
+}
+
+/**
+ * Ensure merge status can be retrieved.
+ */
+TEST_P(BootHidlTest, GetSnapshotMergeStatus) {
+    auto values = ValidMergeStatusValues();
+    auto status = (MergeStatus)boot->getSnapshotMergeStatus();
+    EXPECT_THAT(values, Contains(status));
+}
+
+/**
+ * Ensure merge status can be set to arbitrary value.
+ */
+TEST_P(BootHidlTest, SetSnapshotMergeStatus) {
+    for (const auto value : ValidMergeStatusValues()) {
+        EXPECT_TRUE(boot->setSnapshotMergeStatus(value).withDefault(false));
+        auto status = boot->getSnapshotMergeStatus();
+        EXPECT_EQ(status, value);
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, BootHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBootControl::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/broadcastradio/1.0/Android.bp b/broadcastradio/1.0/Android.bp
index 76e580e..8239d74 100644
--- a/broadcastradio/1.0/Android.bp
+++ b/broadcastradio/1.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/broadcastradio/1.0/default/Android.bp b/broadcastradio/1.0/default/Android.bp
index f961dfd..2c96e2a 100644
--- a/broadcastradio/1.0/default/Android.bp
+++ b/broadcastradio/1.0/default/Android.bp
@@ -31,7 +31,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "liblog",
         "libhardware",
diff --git a/broadcastradio/1.1/Android.bp b/broadcastradio/1.1/Android.bp
index 2186b9a..1cc9b62 100644
--- a/broadcastradio/1.1/Android.bp
+++ b/broadcastradio/1.1/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/broadcastradio/1.1/default/Android.bp b/broadcastradio/1.1/default/Android.bp
index 52fb45b..3659cb9 100644
--- a/broadcastradio/1.1/default/Android.bp
+++ b/broadcastradio/1.1/default/Android.bp
@@ -41,7 +41,6 @@
         "android.hardware.broadcastradio@1.1",
         "libbase",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
diff --git a/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc b/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc
index 7c57135..6fcbfa6 100644
--- a/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc
+++ b/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc
@@ -1,4 +1,6 @@
 service broadcastradio-hal /vendor/bin/hw/android.hardware.broadcastradio@1.1-service
+    interface android.hardware.broadcastradio@1.0::IBroadcastRadioFactory default
+    interface android.hardware.broadcastradio@1.1::IBroadcastRadioFactory default
     class hal
     user audioserver
     group audio
diff --git a/broadcastradio/1.1/default/service.cpp b/broadcastradio/1.1/default/service.cpp
index f8af0b7..29dc76f 100644
--- a/broadcastradio/1.1/default/service.cpp
+++ b/broadcastradio/1.1/default/service.cpp
@@ -20,6 +20,7 @@
 
 #include "BroadcastRadioFactory.h"
 
+using android::sp;
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::broadcastradio::V1_1::implementation::BroadcastRadioFactory;
@@ -27,8 +28,8 @@
 int main(int /* argc */, char** /* argv */) {
     configureRpcThreadpool(4, true);
 
-    BroadcastRadioFactory broadcastRadioFactory;
-    auto status = broadcastRadioFactory.registerAsService();
+    sp<BroadcastRadioFactory> broadcastRadioFactory(new BroadcastRadioFactory());
+    auto status = broadcastRadioFactory->registerAsService();
     CHECK_EQ(status, android::OK) << "Failed to register Broadcast Radio HAL implementation";
 
     joinRpcThreadpool();
diff --git a/broadcastradio/2.0/Android.bp b/broadcastradio/2.0/Android.bp
index 93afc02..1040ba1 100644
--- a/broadcastradio/2.0/Android.bp
+++ b/broadcastradio/2.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp
index 840c4b8..83eedb1 100644
--- a/broadcastradio/2.0/default/Android.bp
+++ b/broadcastradio/2.0/default/Android.bp
@@ -42,7 +42,6 @@
         "android.hardware.broadcastradio@2.0",
         "libbase",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
     ],
 }
diff --git a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
index 7d68b6c..dd8c9c6 100644
--- a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
+++ b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
@@ -1,4 +1,5 @@
 service broadcastradio-hal2 /vendor/bin/hw/android.hardware.broadcastradio@2.0-service
+    interface android.hardware.broadcastradio@2.0::IBroadcastRadio default
     class hal
     user audioserver
     group audio
diff --git a/broadcastradio/2.0/default/service.cpp b/broadcastradio/2.0/default/service.cpp
index 349aba2..bd746fd 100644
--- a/broadcastradio/2.0/default/service.cpp
+++ b/broadcastradio/2.0/default/service.cpp
@@ -19,6 +19,7 @@
 #include "BroadcastRadio.h"
 #include "VirtualRadio.h"
 
+using android::sp;
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::broadcastradio::V2_0::implementation::BroadcastRadio;
@@ -30,13 +31,13 @@
     android::base::SetMinimumLogSeverity(android::base::VERBOSE);
     configureRpcThreadpool(4, true);
 
-    BroadcastRadio broadcastRadio(gAmFmRadio);
-    auto amFmStatus = broadcastRadio.registerAsService("amfm");
+    sp<BroadcastRadio> broadcastRadio(new BroadcastRadio(gAmFmRadio));
+    auto amFmStatus = broadcastRadio->registerAsService("amfm");
     CHECK_EQ(amFmStatus, android::OK)
         << "Failed to register Broadcast Radio AM/FM HAL implementation";
 
-    BroadcastRadio dabRadio(gDabRadio);
-    auto dabStatus = dabRadio.registerAsService("dab");
+    sp<BroadcastRadio> dabRadio(new BroadcastRadio(gDabRadio));
+    auto dabStatus = dabRadio->registerAsService("dab");
     CHECK_EQ(dabStatus, android::OK) << "Failed to register Broadcast Radio DAB HAL implementation";
 
     joinRpcThreadpool();
diff --git a/camera/common/1.0/Android.bp b/camera/common/1.0/Android.bp
index fe29774..ed64060 100644
--- a/camera/common/1.0/Android.bp
+++ b/camera/common/1.0/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/device/1.0/Android.bp b/camera/device/1.0/Android.bp
index a8df1ec..668884d 100644
--- a/camera/device/1.0/Android.bp
+++ b/camera/device/1.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
index aa3b941..97d0b5f 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -8,8 +8,6 @@
     shared_libs: [
         "libhidlbase",
         "libhidlmemory",
-        "libhidltransport",
-        "libhwbinder",
         "libutils",
         "android.hardware.camera.device@1.0",
         "android.hardware.camera.common@1.0",
diff --git a/camera/device/1.0/default/CameraDevice.cpp b/camera/device/1.0/default/CameraDevice.cpp
index a03bbc8..2dd6094 100644
--- a/camera/device/1.0/default/CameraDevice.cpp
+++ b/camera/device/1.0/default/CameraDevice.cpp
@@ -397,9 +397,11 @@
     CameraDevice* device = mem->handle.mDevice;
     if (device == nullptr) {
         ALOGE("%s: camera HAL return memory for a null device!", __FUNCTION__);
+        return;
     }
     if (device->mDeviceCallback == nullptr) {
         ALOGE("%s: camera HAL return memory while camera is not opened!", __FUNCTION__);
+        return;
     }
     device->mDeviceCallback->unregisterMemory(mem->handle.mId);
     {
diff --git a/camera/device/3.2/Android.bp b/camera/device/3.2/Android.bp
index e7546de..2e5349f 100644
--- a/camera/device/3.2/Android.bp
+++ b/camera/device/3.2/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
index edb008e..e4d9e85 100644
--- a/camera/device/3.2/default/Android.bp
+++ b/camera/device/3.2/default/Android.bp
@@ -7,7 +7,6 @@
            "convert.cpp"],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "libcutils",
         "android.hardware.camera.device@3.2",
diff --git a/camera/device/3.3/Android.bp b/camera/device/3.3/Android.bp
index e21824f..679fad6 100644
--- a/camera/device/3.3/Android.bp
+++ b/camera/device/3.3/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/camera/device/3.3/default/Android.bp b/camera/device/3.3/default/Android.bp
index 39d379d..d964f3d 100644
--- a/camera/device/3.3/default/Android.bp
+++ b/camera/device/3.3/default/Android.bp
@@ -7,7 +7,6 @@
            "convert.cpp"],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
diff --git a/camera/device/3.4/Android.bp b/camera/device/3.4/Android.bp
index 6a2eac5..e6f42d6 100644
--- a/camera/device/3.4/Android.bp
+++ b/camera/device/3.4/Android.bp
@@ -20,4 +20,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index c22b13c..71a9e77 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -38,7 +38,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
@@ -75,7 +74,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index 9a2fddf..f518a15 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -754,11 +754,11 @@
         int fd, double fpsUpperBound, SupportedV4L2Format* format) {
     format->frameRates.clear();
 
-    v4l2_frmivalenum frameInterval {
-        .pixel_format = format->fourcc,
-        .width = format->width,
-        .height = format->height,
-        .index = 0
+    v4l2_frmivalenum frameInterval{
+            .index = 0,
+            .pixel_format = format->fourcc,
+            .width = format->width,
+            .height = format->height,
     };
 
     for (frameInterval.index = 0;
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index dc5579a..9ff0d74 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -2412,9 +2412,7 @@
     mV4L2BufferCount = req_buffers.count;
     for (uint32_t i = 0; i < req_buffers.count; i++) {
         v4l2_buffer buffer = {
-            .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-            .index = i,
-            .memory = V4L2_MEMORY_MMAP};
+                .index = i, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .memory = V4L2_MEMORY_MMAP};
 
         if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
             ALOGE("%s: QUERYBUF %d failed: %s", __FUNCTION__, i,  strerror(errno));
diff --git a/camera/device/3.5/Android.bp b/camera/device/3.5/Android.bp
index d51fd0e..362a5e6 100644
--- a/camera/device/3.5/Android.bp
+++ b/camera/device/3.5/Android.bp
@@ -22,4 +22,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
index 26b3b67..43362fd 100644
--- a/camera/device/3.5/default/Android.bp
+++ b/camera/device/3.5/default/Android.bp
@@ -37,7 +37,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
@@ -71,7 +70,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
diff --git a/camera/metadata/3.2/Android.bp b/camera/metadata/3.2/Android.bp
index 3271d91..f58fb28 100644
--- a/camera/metadata/3.2/Android.bp
+++ b/camera/metadata/3.2/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/metadata/3.3/Android.bp b/camera/metadata/3.3/Android.bp
index 4dddfad..885f4f9 100644
--- a/camera/metadata/3.3/Android.bp
+++ b/camera/metadata/3.3/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/metadata/3.4/Android.bp b/camera/metadata/3.4/Android.bp
index 2b75eba..6a92458 100644
--- a/camera/metadata/3.4/Android.bp
+++ b/camera/metadata/3.4/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/provider/2.4/Android.bp b/camera/provider/2.4/Android.bp
index 63d7fd5..876814d 100644
--- a/camera/provider/2.4/Android.bp
+++ b/camera/provider/2.4/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index cb78fcb..95e27fd 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -24,7 +24,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
@@ -63,7 +62,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libtinyxml2",
         "libutils",
@@ -108,7 +106,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libtinyxml2",
         "libutils",
@@ -146,7 +143,6 @@
         "libcamera_metadata",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
@@ -211,7 +207,6 @@
         "android.hardware.camera.provider@2.4",
         "libbinder",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libtinyxml2",
         "libutils",
diff --git a/camera/provider/2.5/Android.bp b/camera/provider/2.5/Android.bp
index a4af07e..4ca1efb 100644
--- a/camera/provider/2.5/Android.bp
+++ b/camera/provider/2.5/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp
index cd1caeb..4563362 100644
--- a/camera/provider/2.5/default/Android.bp
+++ b/camera/provider/2.5/default/Android.bp
@@ -24,7 +24,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
@@ -64,7 +63,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libtinyxml2",
         "libutils",
@@ -103,7 +101,6 @@
         "libcamera_metadata",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
@@ -170,7 +167,6 @@
         "android.hardware.graphics.mapper@2.0",
         "libbinder",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libtinyxml2",
         "libutils",
diff --git a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc
index aa070d9..955b28e 100644
--- a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc
+++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc
@@ -1,6 +1,6 @@
 service vendor.camera-provider-2-5 /vendor/bin/hw/android.hardware.camera.provider@2.5-service-lazy_64
     interface android.hardware.camera.provider@2.5::ICameraProvider legacy/0
-    interface android.hardware.camera.provider@2.5::ICameraProvider legacy/0
+    interface android.hardware.camera.provider@2.4::ICameraProvider legacy/0
     oneshot
     disabled
     class hal
diff --git a/camera/provider/2.5/default/service.cpp b/camera/provider/2.5/default/service.cpp
index 604215d..ec30cbc 100644
--- a/camera/provider/2.5/default/service.cpp
+++ b/camera/provider/2.5/default/service.cpp
@@ -49,8 +49,8 @@
 
     status_t status;
     if (kLazyService) {
-        auto serviceRegistrar = std::make_shared<::android::hardware::LazyServiceRegistrar>();
-        status = serviceRegistrar->registerService(provider, "legacy/0");
+        auto serviceRegistrar = ::android::hardware::LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(provider, "legacy/0");
     } else {
         status = provider->registerAsService("legacy/0");
     }
diff --git a/cas/1.0/Android.bp b/cas/1.0/Android.bp
index 8d8e946..4982e20 100644
--- a/cas/1.0/Android.bp
+++ b/cas/1.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/cas/1.0/default/Android.bp b/cas/1.0/default/Android.bp
index aa080f4..f9977ff 100644
--- a/cas/1.0/default/Android.bp
+++ b/cas/1.0/default/Android.bp
@@ -21,7 +21,6 @@
       "libbinder",
       "libhidlbase",
       "libhidlmemory",
-      "libhidltransport",
       "liblog",
       "libstagefright_foundation",
       "libutils",
diff --git a/cas/1.0/default/service.cpp b/cas/1.0/default/service.cpp
index 516acfb..754c0c5 100644
--- a/cas/1.0/default/service.cpp
+++ b/cas/1.0/default/service.cpp
@@ -46,8 +46,8 @@
     android::sp<IMediaCasService> service = new MediaCasService();
     android::status_t status;
     if (kLazyService) {
-        auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
-        status = serviceRegistrar->registerService(service);
+        auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(service);
     } else {
         status = service->registerAsService();
     }
diff --git a/cas/1.1/Android.bp b/cas/1.1/Android.bp
index bb0edb9..13217b6 100644
--- a/cas/1.1/Android.bp
+++ b/cas/1.1/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/cas/1.1/default/Android.bp b/cas/1.1/default/Android.bp
index 68a49cf..66a1eb8 100644
--- a/cas/1.1/default/Android.bp
+++ b/cas/1.1/default/Android.bp
@@ -22,7 +22,6 @@
       "libbinder",
       "libhidlbase",
       "libhidlmemory",
-      "libhidltransport",
       "liblog",
       "libutils",
     ],
diff --git a/cas/1.1/default/service.cpp b/cas/1.1/default/service.cpp
index 9625303..bf0e159 100644
--- a/cas/1.1/default/service.cpp
+++ b/cas/1.1/default/service.cpp
@@ -46,8 +46,8 @@
     android::sp<IMediaCasService> service = new MediaCasService();
     android::status_t status;
     if (kLazyService) {
-        auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
-        status = serviceRegistrar->registerService(service);
+        auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(service);
     } else {
         status = service->registerAsService();
     }
diff --git a/cas/1.2/Android.bp b/cas/1.2/Android.bp
new file mode 100644
index 0000000..fbb38b0
--- /dev/null
+++ b/cas/1.2/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.cas@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ICas.hal",
+        "ICasListener.hal",
+        "IMediaCasService.hal",
+    ],
+    interfaces: [
+        "android.hardware.cas@1.0",
+        "android.hardware.cas@1.1",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/cas/1.2/ICas.hal b/cas/1.2/ICas.hal
new file mode 100644
index 0000000..23edc50
--- /dev/null
+++ b/cas/1.2/ICas.hal
@@ -0,0 +1,43 @@
+/*
+ * 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.cas@1.2;
+
+import @1.0::HidlCasSessionId;
+import @1.1::ICas;
+import ScramblingMode;
+import SessionIntent;
+import Status;
+
+/**
+ * ICas is the API to control the cas system and is accessible from both
+ * Java and native level. It is used to manage sessions, provision/refresh
+ * the cas system, and process the EMM/ECM messages. It also allows bi-directional,
+ * scheme-specific communications between the client and the cas system.
+ */
+interface ICas extends @1.1::ICas {
+    /**
+     * Open a session to descramble one or more streams by specifying intention
+     * and scrambling mode.
+     *
+     * @param intent the intention of the session to be opened.
+     * @param mode the scrambling mode the session will use.
+     * @return status the status of the call.
+     * @return sessionId the id of the newly opened session.
+     */
+    openSession_1_2(SessionIntent intent, ScramblingMode mode)
+        generates (Status status, HidlCasSessionId sessionId);
+};
diff --git a/cas/1.2/ICasListener.hal b/cas/1.2/ICasListener.hal
new file mode 100644
index 0000000..9a8be20
--- /dev/null
+++ b/cas/1.2/ICasListener.hal
@@ -0,0 +1,37 @@
+/*
+ * 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.cas@1.2;
+
+import @1.1::ICasListener;
+import StatusEvent;
+
+interface ICasListener extends @1.1::ICasListener {
+    /**
+     * Notify the listener that the status of CAS system has changed.
+     *
+     * @param event the event type of status change.
+     * @param number value for status event.
+     *               For PLUGIN_PHYSICAL_MODULE_CHANGED event:
+     *               the positive number presents how many plugins are inserted;
+     *               the negative number presents how many plugins are removed.
+     *               Client must enumerate plugins after receive the event.
+     *               For PLUGIN_SESSION_NUMBER_CHANGED event:
+     *               the number presents how many sessions are supported
+     *               in the plugin.
+     */
+    onStatusUpdate(StatusEvent event, int32_t number);
+};
diff --git a/cas/1.2/IMediaCasService.hal b/cas/1.2/IMediaCasService.hal
new file mode 100644
index 0000000..a0bec7e
--- /dev/null
+++ b/cas/1.2/IMediaCasService.hal
@@ -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.
+ */
+
+package android.hardware.cas@1.2;
+
+import ICas;
+import ICasListener;
+import @1.1::IMediaCasService;
+
+/**
+ * IMediaCasService is the main entry point for interacting with a vendor's
+ * cas HAL to create cas and descrambler plugin instances. A cas plugin instance
+ * opens cas sessions which are used to obtain keys for a descrambler session,
+ * which can in turn be used to descramble protected video content.
+ *
+ * The 1.2 must always create 1.2 ICas interfaces, which are
+ * returned via the 1.1 createPluginExt method.
+ *
+ * To use 1.2 features the caller must cast the returned interface to a
+ * 1.2 HAL, using V1_2::ICas::castFrom().
+ */
+interface IMediaCasService extends @1.1::IMediaCasService {};
diff --git a/cas/1.2/default/Android.bp b/cas/1.2/default/Android.bp
new file mode 100644
index 0000000..9e53148
--- /dev/null
+++ b/cas/1.2/default/Android.bp
@@ -0,0 +1,49 @@
+cc_defaults {
+    name: "cas_service_defaults@1.2",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+      "CasImpl.cpp",
+      "DescramblerImpl.cpp",
+      "MediaCasService.cpp",
+      "service.cpp",
+      "SharedLibrary.cpp",
+      "TypeConvert.cpp",
+    ],
+
+    compile_multilib: "32",
+
+    shared_libs: [
+      "android.hardware.cas@1.0",
+      "android.hardware.cas@1.1",
+      "android.hardware.cas@1.2",
+      "android.hardware.cas.native@1.0",
+      "android.hidl.memory@1.0",
+      "libbinder",
+      "libhidlbase",
+      "libhidlmemory",
+      "liblog",
+      "libutils",
+    ],
+    header_libs: [
+      "libstagefright_foundation_headers",
+      "media_plugin_headers",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.cas@1.2-service",
+    vintf_fragments: ["android.hardware.cas@1.2-service.xml"],
+    defaults: ["cas_service_defaults@1.2"],
+    init_rc: ["android.hardware.cas@1.2-service.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.cas@1.2-service-lazy",
+    vintf_fragments: ["android.hardware.cas@1.2-service-lazy.xml"],
+    overrides: ["android.hardware.cas@1.2-service"],
+    defaults: ["cas_service_defaults@1.2"],
+    init_rc: ["android.hardware.cas@1.2-service-lazy.rc"],
+    cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/cas/1.2/default/CasImpl.cpp b/cas/1.2/default/CasImpl.cpp
new file mode 100644
index 0000000..46dd251
--- /dev/null
+++ b/cas/1.2/default/CasImpl.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ icensed 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-CasImpl"
+
+#include <android/hardware/cas/1.1/ICasListener.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "SharedLibrary.h"
+#include "TypeConvert.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+CasImpl::CasImpl(const sp<ICasListener>& listener) : mListener(listener) {
+    ALOGV("CTOR");
+}
+
+CasImpl::~CasImpl() {
+    ALOGV("DTOR");
+    release();
+}
+
+// static
+void CasImpl::OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onEvent(event, arg, data, size);
+}
+
+// static
+void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+                          const CasSessionId* sessionId) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onEvent(sessionId, event, arg, data, size);
+}
+
+// static
+void CasImpl::StatusUpdate(void* appData, int32_t event, int32_t arg) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onStatusUpdate(event, arg);
+}
+
+void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin* plugin) {
+    mLibrary = library;
+    std::shared_ptr<CasPlugin> holder(plugin);
+    std::atomic_store(&mPluginHolder, holder);
+}
+
+void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    HidlCasData eventData;
+    if (data != NULL) {
+        eventData.setToExternal(data, size);
+    }
+
+    mListener->onEvent(event, arg, eventData);
+}
+
+void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+                      size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    HidlCasData eventData;
+    if (data != NULL) {
+        eventData.setToExternal(data, size);
+    }
+
+    if (sessionId != NULL) {
+        mListener->onSessionEvent(*sessionId, event, arg, eventData);
+    } else {
+        mListener->onEvent(event, arg, eventData);
+    }
+}
+
+void CasImpl::onStatusUpdate(int32_t event, int32_t arg) {
+    if (mListener == NULL) {
+        return;
+    }
+    sp<V1_2::ICasListener> listenerV1_2 = V1_2::ICasListener::castFrom(mListener);
+
+    if (listenerV1_2 != NULL) {
+        listenerV1_2->onStatusUpdate(static_cast<StatusEvent>(event), arg);
+    }
+}
+
+Return<Status> CasImpl::setPluginStatusUpdateCallback() {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setStatusCallback(&CasImpl::StatusUpdate));
+}
+
+Return<Status> CasImpl::setPrivateData(const HidlCasData& pvtData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setPrivateData(pvtData));
+}
+
+Return<void> CasImpl::openSession(openSession_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+    CasSessionId sessionId;
+
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    status_t err = INVALID_OPERATION;
+    if (holder.get() != nullptr) {
+        err = holder->openSession(&sessionId);
+        holder.reset();
+    }
+
+    _hidl_cb(toStatus(err), sessionId);
+
+    return Void();
+}
+
+Return<void> CasImpl::openSession_1_2(const SessionIntent intent, const ScramblingMode mode,
+                                      openSession_1_2_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+    CasSessionId sessionId;
+
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    status_t err = INVALID_OPERATION;
+    if (holder.get() != nullptr) {
+        err = holder->openSession(static_cast<uint32_t>(intent), static_cast<uint32_t>(mode),
+                                  &sessionId);
+        holder.reset();
+    }
+
+    _hidl_cb(toStatus_1_2(err), sessionId);
+
+    return Void();
+}
+
+Return<Status> CasImpl::setSessionPrivateData(const HidlCasSessionId& sessionId,
+                                              const HidlCasData& pvtData) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setSessionPrivateData(sessionId, pvtData));
+}
+
+Return<Status> CasImpl::closeSession(const HidlCasSessionId& sessionId) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->closeSession(sessionId));
+}
+
+Return<Status> CasImpl::processEcm(const HidlCasSessionId& sessionId, const HidlCasData& ecm) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->processEcm(sessionId, ecm));
+}
+
+Return<Status> CasImpl::processEmm(const HidlCasData& emm) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->processEmm(emm));
+}
+
+Return<Status> CasImpl::sendEvent(int32_t event, int32_t arg, const HidlCasData& eventData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->sendEvent(event, arg, eventData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event,
+                                         int32_t arg, const HidlCasData& eventData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::provision(const hidl_string& provisionString) {
+    ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->provision(String8(provisionString.c_str())));
+}
+
+Return<Status> CasImpl::refreshEntitlements(int32_t refreshType, const HidlCasData& refreshData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->refreshEntitlements(refreshType, refreshData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::release() {
+    ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+    std::shared_ptr<CasPlugin> holder(nullptr);
+    std::atomic_store(&mPluginHolder, holder);
+
+    return Status::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.2/default/CasImpl.h b/cas/1.2/default/CasImpl.h
new file mode 100644
index 0000000..4325c20
--- /dev/null
+++ b/cas/1.2/default/CasImpl.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
+#define ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
+
+#include <android/hardware/cas/1.1/ICas.h>
+#include <android/hardware/cas/1.2/ICas.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+struct CasPlugin;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+struct ICasListener;
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasData;
+using ::android::hardware::cas::V1_0::HidlCasSessionId;
+using ::android::hardware::cas::V1_0::Status;
+using ::android::hardware::cas::V1_2::ScramblingMode;
+using ::android::hardware::cas::V1_2::SessionIntent;
+using ::android::hardware::cas::V1_2::StatusEvent;
+
+class SharedLibrary;
+
+class CasImpl : public V1_2::ICas {
+  public:
+    CasImpl(const sp<ICasListener>& listener);
+    virtual ~CasImpl();
+
+    static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+    static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+                            const CasSessionId* sessionId);
+
+    static void StatusUpdate(void* appData, int32_t event, int32_t arg);
+
+    void init(const sp<SharedLibrary>& library, CasPlugin* plugin);
+    void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+    void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+                 size_t size);
+
+    void onStatusUpdate(int32_t event, int32_t arg);
+
+    // ICas inherits
+
+    Return<Status> setPluginStatusUpdateCallback();
+
+    virtual Return<Status> setPrivateData(const HidlCasData& pvtData) override;
+
+    virtual Return<void> openSession(openSession_cb _hidl_cb) override;
+
+    virtual Return<void> openSession_1_2(const SessionIntent intent, const ScramblingMode mode,
+                                         openSession_1_2_cb _hidl_cb) override;
+
+    virtual Return<Status> closeSession(const HidlCasSessionId& sessionId) override;
+
+    virtual Return<Status> setSessionPrivateData(const HidlCasSessionId& sessionId,
+                                                 const HidlCasData& pvtData) override;
+
+    virtual Return<Status> processEcm(const HidlCasSessionId& sessionId,
+                                      const HidlCasData& ecm) override;
+
+    virtual Return<Status> processEmm(const HidlCasData& emm) override;
+
+    virtual Return<Status> sendEvent(int32_t event, int32_t arg,
+                                     const HidlCasData& eventData) override;
+
+    virtual Return<Status> sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event,
+                                            int32_t arg, const HidlCasData& eventData) override;
+
+    virtual Return<Status> provision(const hidl_string& provisionString) override;
+
+    virtual Return<Status> refreshEntitlements(int32_t refreshType,
+                                               const HidlCasData& refreshData) override;
+
+    virtual Return<Status> release() override;
+
+  private:
+    struct PluginHolder;
+    sp<SharedLibrary> mLibrary;
+    std::shared_ptr<CasPlugin> mPluginHolder;
+    sp<ICasListener> mListener;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
diff --git a/cas/1.2/default/DescramblerImpl.cpp b/cas/1.2/default/DescramblerImpl.cpp
new file mode 100644
index 0000000..36dc1a5
--- /dev/null
+++ b/cas/1.2/default/DescramblerImpl.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-DescramblerImpl"
+
+#include <hidlmemory/mapping.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <utils/Log.h>
+
+#include "DescramblerImpl.h"
+#include "SharedLibrary.h"
+#include "TypeConvert.h"
+
+namespace android {
+using hidl::memory::V1_0::IMemory;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+#define CHECK_SUBSAMPLE_DEF(type)                                                                 \
+    static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \
+    static_assert(offsetof(SubSample, numBytesOfClearData) ==                                     \
+                          offsetof(type::SubSample, mNumBytesOfClearData),                        \
+                  "SubSample: numBytesOfClearData offset doesn't match");                         \
+    static_assert(offsetof(SubSample, numBytesOfEncryptedData) ==                                 \
+                          offsetof(type::SubSample, mNumBytesOfEncryptedData),                    \
+                  "SubSample: numBytesOfEncryptedData offset doesn't match")
+
+CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
+CHECK_SUBSAMPLE_DEF(CryptoPlugin);
+
+DescramblerImpl::DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin* plugin)
+    : mLibrary(library), mPluginHolder(plugin) {
+    ALOGV("CTOR: plugin=%p", mPluginHolder.get());
+}
+
+DescramblerImpl::~DescramblerImpl() {
+    ALOGV("DTOR: plugin=%p", mPluginHolder.get());
+    release();
+}
+
+Return<Status> DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+
+    std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->setMediaCasSession(sessionId));
+}
+
+Return<bool> DescramblerImpl::requiresSecureDecoderComponent(const hidl_string& mime) {
+    std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return false;
+    }
+
+    return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
+}
+
+static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) {
+    return isInRange<uint64_t, uint64_t>(0, size, offset, length);
+}
+
+Return<void> DescramblerImpl::descramble(ScramblingControl scramblingControl,
+                                         const hidl_vec<SubSample>& subSamples,
+                                         const SharedBuffer& srcBuffer, uint64_t srcOffset,
+                                         const DestinationBuffer& dstBuffer, uint64_t dstOffset,
+                                         descramble_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    // hidl_memory's size is stored in uint64_t, but mapMemory's mmap will map
+    // size in size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed
+    // but the mapped memory's actual size will be smaller than the reported size.
+    if (srcBuffer.heapBase.size() > SIZE_MAX) {
+        ALOGE("Invalid hidl_memory size: %llu", srcBuffer.heapBase.size());
+        android_errorWriteLog(0x534e4554, "79376389");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+
+    sp<IMemory> srcMem = mapMemory(srcBuffer.heapBase);
+
+    // Validate if the offset and size in the SharedBuffer is consistent with the
+    // mapped ashmem, since the offset and size is controlled by client.
+    if (srcMem == NULL) {
+        ALOGE("Failed to map src buffer.");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+    if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize())) {
+        ALOGE("Invalid src buffer range: offset %llu, size %llu, srcMem size %llu",
+              srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize());
+        android_errorWriteLog(0x534e4554, "67962232");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+
+    // use 64-bit here to catch bad subsample size that might be overflowing.
+    uint64_t totalBytesInSubSamples = 0;
+    for (size_t i = 0; i < subSamples.size(); i++) {
+        totalBytesInSubSamples +=
+                (uint64_t)subSamples[i].numBytesOfClearData + subSamples[i].numBytesOfEncryptedData;
+    }
+    // Further validate if the specified srcOffset and requested total subsample size
+    // is consistent with the source shared buffer size.
+    if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) {
+        ALOGE("Invalid srcOffset and subsample size: "
+              "srcOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
+              srcOffset, totalBytesInSubSamples, srcBuffer.size);
+        android_errorWriteLog(0x534e4554, "67962232");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+
+    void* srcPtr = (uint8_t*)(void*)srcMem->getPointer() + srcBuffer.offset;
+    void* dstPtr = NULL;
+    if (dstBuffer.type == BufferType::SHARED_MEMORY) {
+        // When using shared memory, src buffer is also used as dst,
+        // we don't map it again here.
+        dstPtr = srcPtr;
+
+        // In this case the dst and src would be the same buffer, need to validate
+        // dstOffset against the buffer size too.
+        if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) {
+            ALOGE("Invalid dstOffset and subsample size: "
+                  "dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
+                  dstOffset, totalBytesInSubSamples, srcBuffer.size);
+            android_errorWriteLog(0x534e4554, "67962232");
+            _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+            return Void();
+        }
+    } else {
+        native_handle_t* handle =
+                const_cast<native_handle_t*>(dstBuffer.secureMemory.getNativeHandle());
+        dstPtr = static_cast<void*>(handle);
+    }
+
+    // Get a local copy of the shared_ptr for the plugin. Note that before
+    // calling the HIDL callback, this shared_ptr must be manually reset,
+    // since the client side could proceed as soon as the callback is called
+    // without waiting for this method to go out of scope.
+    std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        _hidl_cb(toStatus(INVALID_OPERATION), 0, NULL);
+        return Void();
+    }
+
+    // Casting hidl SubSample to DescramblerPlugin::SubSample, but need
+    // to ensure structs are actually idential
+
+    int32_t result =
+            holder->descramble(dstBuffer.type != BufferType::SHARED_MEMORY,
+                               (DescramblerPlugin::ScramblingControl)scramblingControl,
+                               subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
+                               srcPtr, srcOffset, dstPtr, dstOffset, NULL);
+
+    holder.reset();
+    _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL);
+    return Void();
+}
+
+Return<Status> DescramblerImpl::release() {
+    ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+    std::shared_ptr<DescramblerPlugin> holder(nullptr);
+    std::atomic_store(&mPluginHolder, holder);
+
+    return Status::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.2/default/DescramblerImpl.h b/cas/1.2/default/DescramblerImpl.h
new file mode 100644
index 0000000..011eace
--- /dev/null
+++ b/cas/1.2/default/DescramblerImpl.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
+#define ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
+
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+struct DescramblerPlugin;
+using namespace hardware::cas::native::V1_0;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasSessionId;
+using ::android::hardware::cas::V1_0::Status;
+
+class SharedLibrary;
+
+class DescramblerImpl : public IDescrambler {
+  public:
+    DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin* plugin);
+    virtual ~DescramblerImpl();
+
+    virtual Return<Status> setMediaCasSession(const HidlCasSessionId& sessionId) override;
+
+    virtual Return<bool> requiresSecureDecoderComponent(const hidl_string& mime) override;
+
+    virtual Return<void> descramble(ScramblingControl scramblingControl,
+                                    const hidl_vec<SubSample>& subSamples,
+                                    const SharedBuffer& srcBuffer, uint64_t srcOffset,
+                                    const DestinationBuffer& dstBuffer, uint64_t dstOffset,
+                                    descramble_cb _hidl_cb) override;
+
+    virtual Return<Status> release() override;
+
+  private:
+    sp<SharedLibrary> mLibrary;
+    std::shared_ptr<DescramblerPlugin> mPluginHolder;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
diff --git a/cas/1.2/default/FactoryLoader.h b/cas/1.2/default/FactoryLoader.h
new file mode 100644
index 0000000..7403f86
--- /dev/null
+++ b/cas/1.2/default/FactoryLoader.h
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
+#define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/cas/CasAPI.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+#include "SharedLibrary.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+
+template <class T>
+class FactoryLoader {
+  public:
+    FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+    virtual ~FactoryLoader() { closeFactory(); }
+
+    bool findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library = NULL,
+                              T** factory = NULL);
+
+    bool enumeratePlugins(vector<HidlCasPluginDescriptor>* results);
+
+  private:
+    typedef T* (*CreateFactoryFunc)();
+
+    Mutex mMapLock;
+    T* mFactory;
+    const char* mCreateFactoryFuncName;
+    sp<SharedLibrary> mLibrary;
+    KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+    KeyedVector<String8, wp<SharedLibrary>> mLibraryPathToOpenLibraryMap;
+
+    bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+                                      sp<SharedLibrary>* library, T** factory);
+
+    bool queryPluginsFromPath(const String8& path, vector<HidlCasPluginDescriptor>* results);
+
+    bool openFactory(const String8& path);
+    void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library,
+                                            T** factory) {
+    if (library != NULL) {
+        library->clear();
+    }
+    if (factory != NULL) {
+        *factory = NULL;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    // first check cache
+    ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+    if (index >= 0) {
+        return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
+                                            library, factory);
+    }
+
+    // no luck, have to search
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
+                mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+                closedir(pDir);
+
+                return true;
+            }
+        }
+    }
+
+    closedir(pDir);
+
+    ALOGE("Failed to find plugin");
+    return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(vector<HidlCasPluginDescriptor>* results) {
+    ALOGI("enumeratePlugins");
+
+    results->clear();
+
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            queryPluginsFromPath(pluginPath, results);
+        }
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+                                                    sp<SharedLibrary>* library, T** factory) {
+    closeFactory();
+
+    if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+        closeFactory();
+        return false;
+    }
+
+    if (library != NULL) {
+        *library = mLibrary;
+    }
+    if (factory != NULL) {
+        *factory = mFactory;
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
+                                            vector<HidlCasPluginDescriptor>* results) {
+    closeFactory();
+
+    vector<CasPluginDescriptor> descriptors;
+    if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+        closeFactory();
+        return false;
+    }
+
+    for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+        results->push_back(
+                HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8& path) {
+    // get strong pointer to open shared library
+    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+    if (index >= 0) {
+        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+    } else {
+        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+    }
+
+    if (!mLibrary.get()) {
+        mLibrary = new SharedLibrary(path);
+        if (!*mLibrary) {
+            return false;
+        }
+
+        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+    }
+
+    CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+    if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+        return false;
+    }
+    return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+    delete mFactory;
+    mFactory = NULL;
+    mLibrary.clear();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
diff --git a/cas/1.2/default/MediaCasService.cpp b/cas/1.2/default/MediaCasService.cpp
new file mode 100644
index 0000000..4ecd52b
--- /dev/null
+++ b/cas/1.2/default/MediaCasService.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-MediaCasService"
+
+#include <android/hardware/cas/1.1/ICasListener.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "DescramblerImpl.h"
+#include "MediaCasService.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+class Wrapper : public V1_1::ICasListener {
+  public:
+    static sp<V1_1::ICasListener> wrap(sp<V1_0::ICasListener> impl) {
+        sp<V1_1::ICasListener> cast = V1_1::ICasListener::castFrom(impl);
+        if (cast == NULL) {
+            cast = new Wrapper(impl);
+        }
+        return cast;
+    }
+
+    virtual Return<void> onEvent(int32_t event, int32_t arg,
+                                 const hidl_vec<uint8_t>& data) override {
+        mImpl->onEvent(event, arg, data);
+        return Void();
+    }
+
+    virtual Return<void> onSessionEvent(const hidl_vec<uint8_t>& /* sessionId */,
+                                        int32_t /* event */, int32_t /* arg */,
+                                        const hidl_vec<uint8_t>& /*data*/) override {
+        ALOGV("Do nothing on Session Event for cas@1.0 client in cas@1.1");
+        return Void();
+    }
+
+  private:
+    Wrapper(sp<V1_0::ICasListener> impl) : mImpl(impl){};
+    sp<V1_0::ICasListener> mImpl;
+};
+
+MediaCasService::MediaCasService()
+    : mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {}
+
+MediaCasService::~MediaCasService() {}
+
+Return<void> MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<HidlCasPluginDescriptor> results;
+    mCasLoader.enumeratePlugins(&results);
+
+    _hidl_cb(results);
+    return Void();
+}
+
+Return<bool> MediaCasService::isSystemIdSupported(int32_t CA_system_id) {
+    ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+    return mCasLoader.findFactoryForScheme(CA_system_id);
+}
+
+Return<sp<V1_0::ICas>> MediaCasService::createPlugin(int32_t CA_system_id,
+                                                     const sp<V1_0::ICasListener>& listener) {
+    ALOGV("%s:Use createPluginExt to create plugin in cas@1.1", __FUNCTION__);
+
+    sp<ICas> result;
+
+    sp<V1_1::ICasListener> listenerV1_1 = Wrapper::wrap(listener);
+
+    result = createPluginExt(CA_system_id, listenerV1_1);
+
+    return result;
+}
+
+Return<sp<ICas>> MediaCasService::createPluginExt(int32_t CA_system_id,
+                                                  const sp<ICasListener>& listener) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+    if (listener == NULL) ALOGV("%s: Listener is NULL", __FUNCTION__);
+
+    sp<V1_2::ICas> result;
+
+    CasFactory* factory;
+    sp<SharedLibrary> library;
+    if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+        CasPlugin* plugin = NULL;
+        sp<CasImpl> casImpl = new CasImpl(listener);
+        if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) ==
+                    OK &&
+            plugin != NULL) {
+            casImpl->init(library, plugin);
+            result = casImpl;
+
+            sp<V1_2::ICasListener> listenerV1_2 = V1_2::ICasListener::castFrom(listener);
+            if (listenerV1_2 != NULL) {
+                casImpl->setPluginStatusUpdateCallback();
+            }
+        }
+    }
+
+    return result;
+}
+
+Return<bool> MediaCasService::isDescramblerSupported(int32_t CA_system_id) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    return mDescramblerLoader.findFactoryForScheme(CA_system_id);
+}
+
+Return<sp<IDescramblerBase>> MediaCasService::createDescrambler(int32_t CA_system_id) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    sp<IDescrambler> result;
+
+    DescramblerFactory* factory;
+    sp<SharedLibrary> library;
+    if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+        DescramblerPlugin* plugin = NULL;
+        if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) {
+            result = new DescramblerImpl(library, plugin);
+        }
+    }
+
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.2/default/MediaCasService.h b/cas/1.2/default/MediaCasService.h
new file mode 100644
index 0000000..01e11db
--- /dev/null
+++ b/cas/1.2/default/MediaCasService.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
+#define ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
+
+#include <android/hardware/cas/1.1/IMediaCasService.h>
+#include <android/hardware/cas/1.2/IMediaCasService.h>
+
+#include "FactoryLoader.h"
+
+namespace android {
+struct CasFactory;
+struct DescramblerFactory;
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+using ::android::hardware::cas::V1_0::IDescramblerBase;
+
+class MediaCasService : public V1_2::IMediaCasService {
+  public:
+    MediaCasService();
+
+    virtual Return<void> enumeratePlugins(enumeratePlugins_cb _hidl_cb) override;
+
+    virtual Return<bool> isSystemIdSupported(int32_t CA_system_id) override;
+
+    virtual Return<sp<V1_0::ICas>> createPlugin(int32_t CA_system_id,
+                                                const sp<V1_0::ICasListener>& listener) override;
+
+    virtual Return<sp<ICas>> createPluginExt(int32_t CA_system_id,
+                                             const sp<ICasListener>& listener) override;
+
+    virtual Return<bool> isDescramblerSupported(int32_t CA_system_id) override;
+
+    virtual Return<sp<IDescramblerBase>> createDescrambler(int32_t CA_system_id) override;
+
+  private:
+    FactoryLoader<CasFactory> mCasLoader;
+    FactoryLoader<DescramblerFactory> mDescramblerLoader;
+
+    virtual ~MediaCasService();
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
diff --git a/cas/1.2/default/SharedLibrary.cpp b/cas/1.2/default/SharedLibrary.cpp
new file mode 100644
index 0000000..ffe4bb9
--- /dev/null
+++ b/cas/1.2/default/SharedLibrary.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-SharedLibrary"
+
+#include "SharedLibrary.h"
+#include <dlfcn.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+SharedLibrary::SharedLibrary(const String8& path) {
+    mLibHandle = dlopen(path.string(), RTLD_NOW);
+}
+
+SharedLibrary::~SharedLibrary() {
+    if (mLibHandle != NULL) {
+        dlclose(mLibHandle);
+        mLibHandle = NULL;
+    }
+}
+
+bool SharedLibrary::operator!() const {
+    return mLibHandle == NULL;
+}
+
+void* SharedLibrary::lookup(const char* symbol) const {
+    if (!mLibHandle) {
+        return NULL;
+    }
+    // Clear last error before we load the symbol again,
+    // in case the caller didn't retrieve it.
+    (void)dlerror();
+    return dlsym(mLibHandle, symbol);
+}
+
+const char* SharedLibrary::lastError() const {
+    const char* error = dlerror();
+    return error ? error : "No errors or unknown error";
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.2/default/SharedLibrary.h b/cas/1.2/default/SharedLibrary.h
new file mode 100644
index 0000000..b85f557
--- /dev/null
+++ b/cas/1.2/default/SharedLibrary.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
+#define ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+class SharedLibrary : public RefBase {
+  public:
+    explicit SharedLibrary(const String8& path);
+    ~SharedLibrary();
+
+    bool operator!() const;
+    void* lookup(const char* symbol) const;
+    const char* lastError() const;
+
+  private:
+    void* mLibHandle;
+    DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
diff --git a/cas/1.2/default/TypeConvert.cpp b/cas/1.2/default/TypeConvert.cpp
new file mode 100644
index 0000000..c4bd0dd
--- /dev/null
+++ b/cas/1.2/default/TypeConvert.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-TypeConvert"
+
+#include "TypeConvert.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+Status toStatus(status_t legacyStatus) {
+    Status status;
+    switch (legacyStatus) {
+        case android::OK:
+            status = Status::OK;
+            break;
+        case android::ERROR_CAS_NO_LICENSE:
+            status = Status::ERROR_CAS_NO_LICENSE;
+            break;
+        case android::ERROR_CAS_LICENSE_EXPIRED:
+            status = Status::ERROR_CAS_LICENSE_EXPIRED;
+            break;
+        case android::ERROR_CAS_SESSION_NOT_OPENED:
+            status = Status::ERROR_CAS_SESSION_NOT_OPENED;
+            break;
+        case android::ERROR_CAS_CANNOT_HANDLE:
+            status = Status::ERROR_CAS_CANNOT_HANDLE;
+            break;
+        case android::ERROR_CAS_TAMPER_DETECTED:
+            status = Status::ERROR_CAS_INVALID_STATE;
+            break;
+        case android::BAD_VALUE:
+            status = Status::BAD_VALUE;
+            break;
+        case android::ERROR_CAS_NOT_PROVISIONED:
+            status = Status::ERROR_CAS_NOT_PROVISIONED;
+            break;
+        case android::ERROR_CAS_RESOURCE_BUSY:
+            status = Status::ERROR_CAS_RESOURCE_BUSY;
+            break;
+        case android::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
+            status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION;
+            break;
+        case android::ERROR_CAS_DEVICE_REVOKED:
+            status = Status::ERROR_CAS_DEVICE_REVOKED;
+            break;
+        case android::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
+            status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
+            break;
+        case android::ERROR_CAS_DECRYPT:
+            status = Status::ERROR_CAS_DECRYPT;
+            break;
+        default:
+            ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus);
+            status = Status::ERROR_CAS_UNKNOWN;
+            break;
+    }
+    return status;
+}
+
+V1_2::Status toStatus_1_2(status_t legacyStatus) {
+    V1_2::Status status = static_cast<V1_2::Status>(toStatus(legacyStatus));
+    if (status == V1_2::Status::ERROR_CAS_UNKNOWN) {
+        switch (legacyStatus) {
+            case android::ERROR_CAS_NEED_ACTIVATION:
+                status = V1_2::Status::ERROR_CAS_NEED_ACTIVATION;
+                break;
+            case android::ERROR_CAS_NEED_PAIRING:
+                status = V1_2::Status::ERROR_CAS_NEED_PAIRING;
+                break;
+            case android::ERROR_CAS_NO_CARD:
+                status = V1_2::Status::ERROR_CAS_NO_CARD;
+                break;
+            case android::ERROR_CAS_CARD_MUTE:
+                status = V1_2::Status::ERROR_CAS_CARD_MUTE;
+                break;
+            case android::ERROR_CAS_CARD_INVALID:
+                status = V1_2::Status::ERROR_CAS_CARD_INVALID;
+                break;
+            case android::ERROR_CAS_BLACKOUT:
+                status = V1_2::Status::ERROR_CAS_BLACKOUT;
+                break;
+        }
+    }
+    return status;
+}
+
+String8 sessionIdToString(const CasSessionId& sessionId) {
+    String8 result;
+    for (size_t i = 0; i < sessionId.size(); i++) {
+        result.appendFormat("%02x ", sessionId[i]);
+    }
+    if (result.isEmpty()) {
+        result.append("(null)");
+    }
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.2/default/TypeConvert.h b/cas/1.2/default/TypeConvert.h
new file mode 100644
index 0000000..018f310
--- /dev/null
+++ b/cas/1.2/default/TypeConvert.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
+#define ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
+
+#include <android/hardware/cas/1.0/types.h>
+#include <android/hardware/cas/1.2/types.h>
+#include <media/cas/CasAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::Status;
+
+Status toStatus(status_t legacyStatus);
+
+V1_2::Status toStatus_1_2(status_t legacyStatus);
+
+String8 sessionIdToString(const CasSessionId& sessionId);
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
new file mode 100644
index 0000000..1c75100
--- /dev/null
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
@@ -0,0 +1,11 @@
+service vendor.cas-hal-1-2 /vendor/bin/hw/android.hardware.cas@1.2-service-lazy
+    interface android.hardware.cas@1.0::IMediaCasService default
+    interface android.hardware.cas@1.1::IMediaCasService default
+    interface android.hardware.cas@1.2::IMediaCasService default
+    oneshot
+    disabled
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
new file mode 100644
index 0000000..9b36406
--- /dev/null
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.cas</name>
+        <transport>hwbinder</transport>
+        <version>1.2</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.rc b/cas/1.2/default/android.hardware.cas@1.2-service.rc
new file mode 100644
index 0000000..d1c853e
--- /dev/null
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.rc
@@ -0,0 +1,6 @@
+service vendor.cas-hal-1-2 /vendor/bin/hw/android.hardware.cas@1.2-service
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.xml b/cas/1.2/default/android.hardware.cas@1.2-service.xml
new file mode 100644
index 0000000..9b36406
--- /dev/null
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.cas</name>
+        <transport>hwbinder</transport>
+        <version>1.2</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/cas/1.2/default/service.cpp b/cas/1.2/default/service.cpp
new file mode 100644
index 0000000..a623447
--- /dev/null
+++ b/cas/1.2/default/service.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.cas@1.1-service-lazy"
+#else
+#define LOG_TAG "android.hardware.cas@1.1-service"
+#endif
+
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+#include "MediaCasService.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::cas::V1_1::implementation::MediaCasService;
+using android::hardware::cas::V1_2::IMediaCasService;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main() {
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    android::sp<IMediaCasService> service = new MediaCasService();
+    android::status_t status;
+    if (kLazyService) {
+        auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(service);
+    } else {
+        status = service->registerAsService();
+    }
+    LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering cas service: %d", status);
+
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/cas/1.2/types.hal b/cas/1.2/types.hal
new file mode 100644
index 0000000..40c06cf
--- /dev/null
+++ b/cas/1.2/types.hal
@@ -0,0 +1,149 @@
+/*
+ * 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.cas@1.2;
+
+import android.hardware.cas@1.0;
+import android.hardware.cas@1.1;
+
+enum Status : @1.0::Status {
+    /**
+     * ERROR_CAS_NEED_ACTIVATION is used to trigger device activation process.
+     */
+    ERROR_CAS_NEED_ACTIVATION,
+    /**
+     * ERROR_CAS_NEED_PAIRING is used to trigger pairing process.
+     */
+    ERROR_CAS_NEED_PAIRING,
+    /**
+     * ERROR_CAS_NO_CARD is used to report no smart card for descrambling.
+     */
+    ERROR_CAS_NO_CARD,
+    /**
+     * ERROR_CAS_CARD_MUTE is used to report smart card is muted for
+     * descrambling.
+     */
+    ERROR_CAS_CARD_MUTE,
+    /**
+     *  ERROR_CAS_CARD_INVALID is used to report smart card isn't valid.
+     */
+    ERROR_CAS_CARD_INVALID,
+    /**
+     *  ERROR_CAS_BLACKOUT is used to report geographical blackout.
+     */
+    ERROR_CAS_BLACKOUT,
+};
+
+/**
+ * The intented usage for the session.
+ */
+enum SessionIntent : uint32_t {
+    /**
+     * Live Stream.
+     */
+    LIVE,
+    /**
+     * Playback Recorded Stream.
+     */
+    PLAYBACK,
+    /**
+     * Record Live Stream.
+     */
+    RECORD,
+    /**
+     * View the content with Time Shift capability
+     */
+    TIMESHIFT,
+};
+
+/**
+ * The Scrambling Mode.
+ */
+enum ScramblingMode : uint32_t {
+    RESERVED = 0,
+    /**
+     * DVB (Digital Video Broadcasting) CSA1 (Common Scrambling Algorithm 1) is
+     * the default mode and shall be used when the scrambling descriptor
+     * is not present in the program map section. DVB scrambling mode is
+     * specified in ETSI EN 300 468 specification.
+     */
+    DVB_CSA1,
+    DVB_CSA2,
+    /**
+     * DVB-CSA3 in standard mode.
+     */
+    DVB_CSA3_STANDARD,
+    /**
+     * DVB-CSA3 in minimally enhanced mode.
+     */
+    DVB_CSA3_MINIMAL,
+    /**
+     * DVB-CSA3 in fully enhanced mode.
+     */
+    DVB_CSA3_ENHANCE,
+    /**
+     * DVB-CISSA version 1.
+     */
+    DVB_CISSA_V1,
+    /**
+     * ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
+     */
+    DVB_IDSA,
+    /**
+     * a symmetric key algorithm.
+     */
+    MULTI2,
+    /**
+     * Advanced Encryption System (AES) 128-bit Encryption mode.
+     */
+    AES128,
+    /**
+     * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
+     */
+    AES_ECB,
+    /**
+     * Advanced Encryption System (AES) Society of Cable Telecommunications
+     * Engineers (SCTE) 52 mode.
+     */
+    AES_SCTE52,
+    /**
+     * Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
+     */
+    TDES_ECB,
+    /**
+     * Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications
+     * Engineers (SCTE) 52 mode.
+     */
+    TDES_SCTE52,
+ };
+
+/**
+ * The Event Type for status change.
+ */
+enum StatusEvent : uint8_t {
+    /**
+     * The status of CAS plugin was changed due to physical module insertion or
+     * removal. Client must call enumeratePlugins to update plugins' status.
+     */
+    PLUGIN_PHYSICAL_MODULE_CHANGED,
+    /**
+     * The status of supported session number was changed due to physical module
+     * insertion or removal. Client must update session resource according to
+     * latest StatusMessage from the StatusEvent. The plugin supports unlimited
+     * sesssion by default.
+     */
+    PLUGIN_SESSION_NUMBER_CHANGED,
+};
diff --git a/cas/1.2/vts/functional/Android.bp b/cas/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..9bc372c
--- /dev/null
+++ b/cas/1.2/vts/functional/Android.bp
@@ -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.
+//
+
+cc_test {
+    name: "VtsHalCasV1_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalCasV1_2TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.cas@1.0",
+        "android.hardware.cas@1.1",
+        "android.hardware.cas@1.2",
+        "android.hardware.cas.native@1.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlallocatorutils",
+        "libhidlmemory",
+    ],
+    shared_libs: [
+        "libbinder",
+    ],
+    test_suites: ["general-tests"],
+}
+
diff --git a/cas/1.2/vts/functional/OWNERS b/cas/1.2/vts/functional/OWNERS
new file mode 100644
index 0000000..29246ed
--- /dev/null
+++ b/cas/1.2/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+nchalko@google.com
+chz@google.com
+quxiangfang@google.com
diff --git a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
new file mode 100644
index 0000000..8439ceb
--- /dev/null
+++ b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
@@ -0,0 +1,619 @@
+/*
+ * 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 "mediacas_hidl_hal_test"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/cas/1.0/IDescramblerBase.h>
+#include <android/hardware/cas/1.0/types.h>
+#include <android/hardware/cas/1.2/ICas.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <android/hardware/cas/1.2/IMediaCasService.h>
+#include <android/hardware/cas/1.2/types.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/cas/native/1.0/types.h>
+#include <binder/MemoryDealer.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#define CLEAR_KEY_SYSTEM_ID 0xF6D8
+#define INVALID_SYSTEM_ID 0
+#define WAIT_TIMEOUT 3000000000
+
+#define PROVISION_STR                                      \
+    "{                                                   " \
+    "  \"id\": 21140844,                                 " \
+    "  \"name\": \"Test Title\",                         " \
+    "  \"lowercase_organization_name\": \"Android\",     " \
+    "  \"asset_key\": {                                  " \
+    "  \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\"  " \
+    "  },                                                " \
+    "  \"cas_type\": 1,                                  " \
+    "  \"track_types\": [ ]                              " \
+    "}                                                   "
+
+using android::Condition;
+using android::IMemory;
+using android::IMemoryHeap;
+using android::MemoryDealer;
+using android::Mutex;
+using android::sp;
+using android::hardware::fromHeap;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::HidlMemory;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::cas::native::V1_0::BufferType;
+using android::hardware::cas::native::V1_0::DestinationBuffer;
+using android::hardware::cas::native::V1_0::IDescrambler;
+using android::hardware::cas::native::V1_0::ScramblingControl;
+using android::hardware::cas::native::V1_0::SharedBuffer;
+using android::hardware::cas::native::V1_0::SubSample;
+using android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+using android::hardware::cas::V1_0::IDescramblerBase;
+using android::hardware::cas::V1_0::Status;
+using android::hardware::cas::V1_2::ICas;
+using android::hardware::cas::V1_2::ICasListener;
+using android::hardware::cas::V1_2::IMediaCasService;
+using android::hardware::cas::V1_2::ScramblingMode;
+using android::hardware::cas::V1_2::SessionIntent;
+using android::hardware::cas::V1_2::StatusEvent;
+
+namespace {
+
+const uint8_t kEcmBinaryBuffer[] = {
+        0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00,
+        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00,
+        0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60, 0x4f,
+        0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+        0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c,
+        0x62, 0x19, 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48,
+};
+
+const SubSample kSubSamples[] = {{162, 0}, {0, 184}, {0, 184}};
+
+const uint8_t kInBinaryBuffer[] = {
+        0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+        0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+        0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+        0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+        0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+        0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+        0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+        0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+        0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+        0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+        0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x6e, 0x45, 0x21,
+        0x82, 0x38, 0xf0, 0x9d, 0x7d, 0x96, 0xe6, 0x94, 0xae, 0xe2, 0x87, 0x8f, 0x04, 0x49, 0xe5,
+        0xf6, 0x8c, 0x8b, 0x9a, 0x10, 0x18, 0xba, 0x94, 0xe9, 0x22, 0x31, 0x04, 0x7e, 0x60, 0x5b,
+        0xc4, 0x24, 0x00, 0x90, 0x62, 0x0d, 0xdc, 0x85, 0x74, 0x75, 0x78, 0xd0, 0x14, 0x08, 0xcb,
+        0x02, 0x1d, 0x7d, 0x9d, 0x34, 0xe8, 0x81, 0xb9, 0xf7, 0x09, 0x28, 0x79, 0x29, 0x8d, 0xe3,
+        0x14, 0xed, 0x5f, 0xca, 0xaf, 0xf4, 0x1c, 0x49, 0x15, 0xe1, 0x80, 0x29, 0x61, 0x76, 0x80,
+        0x43, 0xf8, 0x58, 0x53, 0x40, 0xd7, 0x31, 0x6d, 0x61, 0x81, 0x41, 0xe9, 0x77, 0x9f, 0x9c,
+        0xe1, 0x6d, 0xf2, 0xee, 0xd9, 0xc8, 0x67, 0xd2, 0x5f, 0x48, 0x73, 0xe3, 0x5c, 0xcd, 0xa7,
+        0x45, 0x58, 0xbb, 0xdd, 0x28, 0x1d, 0x68, 0xfc, 0xb4, 0xc6, 0xf6, 0x92, 0xf6, 0x30, 0x03,
+        0xaa, 0xe4, 0x32, 0xf6, 0x34, 0x51, 0x4b, 0x0f, 0x8c, 0xf9, 0xac, 0x98, 0x22, 0xfb, 0x49,
+        0xc8, 0xbf, 0xca, 0x8c, 0x80, 0x86, 0x5d, 0xd7, 0xa4, 0x52, 0xb1, 0xd9, 0xa6, 0x04, 0x4e,
+        0xb3, 0x2d, 0x1f, 0xb8, 0x35, 0xcc, 0x45, 0x6d, 0x9c, 0x20, 0xa7, 0xa4, 0x34, 0x59, 0x72,
+        0xe3, 0xae, 0xba, 0x49, 0xde, 0xd1, 0xaa, 0xee, 0x3d, 0x77, 0xfc, 0x5d, 0xc6, 0x1f, 0x9d,
+        0xac, 0xc2, 0x15, 0x66, 0xb8, 0xe1, 0x54, 0x4e, 0x74, 0x93, 0xdb, 0x9a, 0x24, 0x15, 0x6e,
+        0x20, 0xa3, 0x67, 0x3e, 0x5a, 0x24, 0x41, 0x5e, 0xb0, 0xe6, 0x35, 0x87, 0x1b, 0xc8, 0x7a,
+        0xf9, 0x77, 0x65, 0xe0, 0x01, 0xf2, 0x4c, 0xe4, 0x2b, 0xa9, 0x64, 0x96, 0x96, 0x0b, 0x46,
+        0xca, 0xea, 0x79, 0x0e, 0x78, 0xa3, 0x5f, 0x43, 0xfc, 0x47, 0x6a, 0x12, 0xfa, 0xc4, 0x33,
+        0x0e, 0x88, 0x1c, 0x19, 0x3a, 0x00, 0xc3, 0x4e, 0xb5, 0xd8, 0xfa, 0x8e, 0xf1, 0xbc, 0x3d,
+        0xb2, 0x7e, 0x50, 0x8d, 0x67, 0xc3, 0x6b, 0xed, 0xe2, 0xea, 0xa6, 0x1f, 0x25, 0x24, 0x7c,
+        0x94, 0x74, 0x50, 0x49, 0xe3, 0xc6, 0x58, 0x2e, 0xfd, 0x28, 0xb4, 0xc6, 0x73, 0xb1, 0x53,
+        0x74, 0x27, 0x94, 0x5c, 0xdf, 0x69, 0xb7, 0xa1, 0xd7, 0xf5, 0xd3, 0x8a, 0x2c, 0x2d, 0xb4,
+        0x5e, 0x8a, 0x16, 0x14, 0x54, 0x64, 0x6e, 0x00, 0x6b, 0x11, 0x59, 0x8a, 0x63, 0x38, 0x80,
+        0x76, 0xc3, 0xd5, 0x59, 0xf7, 0x3f, 0xd2, 0xfa, 0xa5, 0xca, 0x82, 0xff, 0x4a, 0x62, 0xf0,
+        0xe3, 0x42, 0xf9, 0x3b, 0x38, 0x27, 0x8a, 0x89, 0xaa, 0x50, 0x55, 0x4b, 0x29, 0xf1, 0x46,
+        0x7c, 0x75, 0xef, 0x65, 0xaf, 0x9b, 0x0d, 0x6d, 0xda, 0x25, 0x94, 0x14, 0xc1, 0x1b, 0xf0,
+        0xc5, 0x4c, 0x24, 0x0e, 0x65,
+};
+
+const uint8_t kOutRefBinaryBuffer[] = {
+        0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+        0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+        0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+        0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+        0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+        0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+        0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+        0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+        0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+        0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+        0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
+        0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
+        0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+        0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
+        0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
+        0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
+        0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
+        0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
+        0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
+        0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
+        0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
+        0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
+        0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
+        0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
+        0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
+        0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
+        0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
+        0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
+        0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
+        0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
+        0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
+        0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
+        0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
+        0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
+        0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
+        0x73, 0x63, 0x65, 0x6e, 0x65,
+};
+
+class MediaCasListener : public ICasListener {
+  public:
+    virtual Return<void> onEvent(int32_t event, int32_t arg,
+                                 const hidl_vec<uint8_t>& data) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mEvent = event;
+        mEventArg = arg;
+        mEventData = data;
+
+        mEventReceived = true;
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    virtual Return<void> onSessionEvent(const hidl_vec<uint8_t>& sessionId, int32_t event,
+                                        int32_t arg, const hidl_vec<uint8_t>& data) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mSessionId = sessionId;
+        mEvent = event;
+        mEventArg = arg;
+        mEventData = data;
+
+        mEventReceived = true;
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    virtual Return<void> onStatusUpdate(StatusEvent event, int32_t arg) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mStatusEvent = event;
+        mEventArg = arg;
+
+        mEventReceived = true;
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    void testEventEcho(sp<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+                       hidl_vec<uint8_t>& eventData);
+
+    void testSessionEventEcho(sp<ICas>& mediaCas, const hidl_vec<uint8_t>& sessionId,
+                              int32_t& event, int32_t& eventArg, hidl_vec<uint8_t>& eventData);
+
+    void testStatusUpdate(sp<ICas>& mediaCas, std::vector<uint8_t>* sessionId, SessionIntent intent,
+                          ScramblingMode mode);
+
+  private:
+    int32_t mEvent = -1;
+    int32_t mEventArg = -1;
+    StatusEvent mStatusEvent;
+    bool mEventReceived = false;
+    hidl_vec<uint8_t> mEventData;
+    hidl_vec<uint8_t> mSessionId;
+    android::Mutex mMsgLock;
+    android::Condition mMsgCondition;
+};
+
+void MediaCasListener::testEventEcho(sp<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+                                     hidl_vec<uint8_t>& eventData) {
+    mEventReceived = false;
+    auto returnStatus = mediaCas->sendEvent(event, eventArg, eventData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "event not received within timeout";
+            return;
+        }
+    }
+
+    EXPECT_EQ(mEvent, event);
+    EXPECT_EQ(mEventArg, eventArg);
+    EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testSessionEventEcho(sp<ICas>& mediaCas, const hidl_vec<uint8_t>& sessionId,
+                                            int32_t& event, int32_t& eventArg,
+                                            hidl_vec<uint8_t>& eventData) {
+    mEventReceived = false;
+    auto returnStatus = mediaCas->sendSessionEvent(sessionId, event, eventArg, eventData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "event not received within timeout";
+            return;
+        }
+    }
+
+    EXPECT_TRUE(mSessionId == sessionId);
+    EXPECT_EQ(mEvent, event);
+    EXPECT_EQ(mEventArg, eventArg);
+    EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testStatusUpdate(sp<ICas>& mediaCas, std::vector<uint8_t>* sessionId,
+                                        SessionIntent intent, ScramblingMode mode) {
+    mEventReceived = false;
+    android::hardware::cas::V1_2::Status sessionStatus;
+    auto returnVoid = mediaCas->openSession_1_2(
+            intent, mode,
+            [&](android::hardware::cas::V1_2::Status status, const hidl_vec<uint8_t>& id) {
+                sessionStatus = status;
+                *sessionId = id;
+            });
+    EXPECT_TRUE(returnVoid.isOk());
+    EXPECT_EQ(android::hardware::cas::V1_2::Status::OK, sessionStatus);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "event not received within timeout";
+            return;
+        }
+    }
+    EXPECT_EQ(mStatusEvent, static_cast<StatusEvent>(intent));
+    EXPECT_EQ(mEventArg, static_cast<int32_t>(mode));
+}
+
+// Test environment for Cas HIDL HAL.
+class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    // get the test environment singleton
+    static CasHidlEnvironment* Instance() {
+        static CasHidlEnvironment* instance = new CasHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
+};
+
+class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+  public:
+    virtual void SetUp() override {
+        mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
+                CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+        ASSERT_NE(mService, nullptr);
+    }
+
+    sp<IMediaCasService> mService;
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<ICas> mMediaCas;
+    sp<IDescramblerBase> mDescramblerBase;
+    sp<MediaCasListener> mCasListener;
+    typedef struct _OobInputTestParams {
+        const SubSample* subSamples;
+        uint32_t numSubSamples;
+        size_t imemSizeActual;
+        uint64_t imemOffset;
+        uint64_t imemSize;
+        uint64_t srcOffset;
+        uint64_t dstOffset;
+    } OobInputTestParams;
+
+    ::testing::AssertionResult createCasPlugin(int32_t caSystemId);
+    ::testing::AssertionResult openCasSession(std::vector<uint8_t>* sessionId);
+    ::testing::AssertionResult openCasSession_1_2(std::vector<uint8_t>* sessionId,
+                                                  SessionIntent intent, ScramblingMode mode);
+    ::testing::AssertionResult descrambleTestInputBuffer(const sp<IDescrambler>& descrambler,
+                                                         Status* descrambleStatus,
+                                                         sp<IMemory>* hidlInMemory);
+    ::testing::AssertionResult descrambleTestOobInput(const sp<IDescrambler>& descrambler,
+                                                      Status* descrambleStatus,
+                                                      const OobInputTestParams& params);
+};
+
+::testing::AssertionResult MediaCasHidlTest::createCasPlugin(int32_t caSystemId) {
+    auto status = mService->isSystemIdSupported(caSystemId);
+    if (!status.isOk() || !status) {
+        return ::testing::AssertionFailure();
+    }
+    status = mService->isDescramblerSupported(caSystemId);
+    if (!status.isOk() || !status) {
+        return ::testing::AssertionFailure();
+    }
+
+    mCasListener = new MediaCasListener();
+    auto pluginStatus = mService->createPluginExt(caSystemId, mCasListener);
+    if (!pluginStatus.isOk()) {
+        return ::testing::AssertionFailure();
+    }
+    mMediaCas = ICas::castFrom(pluginStatus);
+    if (mMediaCas == nullptr) {
+        return ::testing::AssertionFailure();
+    }
+
+    auto descramblerStatus = mService->createDescrambler(caSystemId);
+    if (!descramblerStatus.isOk()) {
+        return ::testing::AssertionFailure();
+    }
+    mDescramblerBase = descramblerStatus;
+    return ::testing::AssertionResult(mDescramblerBase != nullptr);
+}
+
+::testing::AssertionResult MediaCasHidlTest::openCasSession(std::vector<uint8_t>* sessionId) {
+    Status sessionStatus;
+    auto returnVoid = mMediaCas->openSession([&](Status status, const hidl_vec<uint8_t>& id) {
+        sessionStatus = status;
+        *sessionId = id;
+    });
+    return ::testing::AssertionResult(returnVoid.isOk() && (Status::OK == sessionStatus));
+}
+
+::testing::AssertionResult MediaCasHidlTest::descrambleTestInputBuffer(
+        const sp<IDescrambler>& descrambler, Status* descrambleStatus, sp<IMemory>* inMemory) {
+    hidl_vec<SubSample> hidlSubSamples;
+    hidlSubSamples.setToExternal(const_cast<SubSample*>(kSubSamples),
+                                 (sizeof(kSubSamples) / sizeof(SubSample)), false /*own*/);
+
+    sp<MemoryDealer> dealer = new MemoryDealer(sizeof(kInBinaryBuffer), "vts-cas");
+    if (nullptr == dealer.get()) {
+        ALOGE("couldn't get MemoryDealer!");
+        return ::testing::AssertionFailure();
+    }
+
+    sp<IMemory> mem = dealer->allocate(sizeof(kInBinaryBuffer));
+    if (nullptr == mem.get()) {
+        ALOGE("couldn't allocate IMemory!");
+        return ::testing::AssertionFailure();
+    }
+    *inMemory = mem;
+
+    // build HidlMemory from memory heap
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+    if (nullptr == heap.get()) {
+        ALOGE("couldn't get memory heap!");
+        return ::testing::AssertionFailure();
+    }
+
+    uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->unsecurePointer()));
+    memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer));
+
+    // hidlMemory is not to be passed out of scope!
+    sp<HidlMemory> hidlMemory = fromHeap(heap);
+
+    SharedBuffer srcBuffer = {
+            .heapBase = *hidlMemory, .offset = (uint64_t)offset, .size = (uint64_t)size};
+
+    DestinationBuffer dstBuffer;
+    dstBuffer.type = BufferType::SHARED_MEMORY;
+    dstBuffer.nonsecureMemory = srcBuffer;
+
+    uint32_t outBytes;
+    hidl_string detailedError;
+    auto returnVoid = descrambler->descramble(
+            ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, 0, dstBuffer, 0,
+            [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) {
+                *descrambleStatus = status;
+                outBytes = bytesWritten;
+                detailedError = detailedErr;
+            });
+    if (!returnVoid.isOk() || *descrambleStatus != Status::OK) {
+        ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s",
+              returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str());
+    }
+    return ::testing::AssertionResult(returnVoid.isOk());
+}
+
+::testing::AssertionResult MediaCasHidlTest::descrambleTestOobInput(
+        const sp<IDescrambler>& descrambler, Status* descrambleStatus,
+        const OobInputTestParams& params) {
+    hidl_vec<SubSample> hidlSubSamples;
+    hidlSubSamples.setToExternal(const_cast<SubSample*>(params.subSamples), params.numSubSamples,
+                                 false /*own*/);
+
+    sp<MemoryDealer> dealer = new MemoryDealer(params.imemSizeActual, "vts-cas");
+    if (nullptr == dealer.get()) {
+        ALOGE("couldn't get MemoryDealer!");
+        return ::testing::AssertionFailure();
+    }
+
+    sp<IMemory> mem = dealer->allocate(params.imemSizeActual);
+    if (nullptr == mem.get()) {
+        ALOGE("couldn't allocate IMemory!");
+        return ::testing::AssertionFailure();
+    }
+
+    // build HidlMemory from memory heap
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+    if (nullptr == heap.get()) {
+        ALOGE("couldn't get memory heap!");
+        return ::testing::AssertionFailure();
+    }
+
+    // hidlMemory is not to be passed out of scope!
+    sp<HidlMemory> hidlMemory = fromHeap(heap);
+
+    SharedBuffer srcBuffer = {
+            .heapBase = *hidlMemory,
+            .offset = (uint64_t)offset + params.imemOffset,
+            .size = (uint64_t)params.imemSize,
+    };
+
+    DestinationBuffer dstBuffer;
+    dstBuffer.type = BufferType::SHARED_MEMORY;
+    dstBuffer.nonsecureMemory = srcBuffer;
+
+    uint32_t outBytes;
+    hidl_string detailedError;
+    auto returnVoid = descrambler->descramble(
+            ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, params.srcOffset,
+            dstBuffer, params.dstOffset,
+            [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) {
+                *descrambleStatus = status;
+                outBytes = bytesWritten;
+                detailedError = detailedErr;
+            });
+    if (!returnVoid.isOk() || *descrambleStatus != Status::OK) {
+        ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s",
+              returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str());
+    }
+    return ::testing::AssertionResult(returnVoid.isOk());
+}
+
+TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) {
+    description("Test that valid call sequences with SessionEvent send and receive");
+
+    ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+    auto returnStatus = mMediaCas->provision(hidl_string(PROVISION_STR));
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    hidl_vec<uint8_t> hidlPvtData;
+    hidlPvtData.resize(256);
+    returnStatus = mMediaCas->setPrivateData(hidlPvtData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    std::vector<uint8_t> sessionId;
+    ASSERT_TRUE(openCasSession(&sessionId));
+    returnStatus = mMediaCas->setSessionPrivateData(sessionId, hidlPvtData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    std::vector<uint8_t> streamSessionId;
+    ASSERT_TRUE(openCasSession(&streamSessionId));
+    returnStatus = mMediaCas->setSessionPrivateData(streamSessionId, hidlPvtData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    returnStatus = mDescramblerBase->setMediaCasSession(sessionId);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    returnStatus = mDescramblerBase->setMediaCasSession(streamSessionId);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    hidl_vec<uint8_t> hidlNullPtr;
+    hidlNullPtr.setToExternal(static_cast<uint8_t*>(nullptr), 0);
+    returnStatus = mMediaCas->refreshEntitlements(3, hidlNullPtr);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    uint8_t refreshData[] = {0, 1, 2, 3};
+    hidl_vec<uint8_t> hidlRefreshData;
+    hidlRefreshData.setToExternal(static_cast<uint8_t*>(refreshData), sizeof(refreshData));
+    returnStatus = mMediaCas->refreshEntitlements(10, hidlRefreshData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    int32_t eventID = 1;
+    int32_t eventArg = 2;
+    mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlNullPtr);
+    mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, hidlNullPtr);
+
+    eventID = 3;
+    eventArg = 4;
+    uint8_t eventData[] = {'e', 'v', 'e', 'n', 't', 'd', 'a', 't', 'a'};
+    hidl_vec<uint8_t> hidlEventData;
+    hidlEventData.setToExternal(static_cast<uint8_t*>(eventData), sizeof(eventData));
+    mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlEventData);
+    mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, hidlEventData);
+
+    SessionIntent intent = SessionIntent::LIVE;
+    ScramblingMode mode = ScramblingMode::DVB_CSA1;
+    mCasListener->testStatusUpdate(mMediaCas, &sessionId, intent, mode);
+
+    uint8_t clearKeyEmmData[] = {'c', 'l', 'e', 'a', 'r', 'k', 'e', 'y', 'e', 'm', 'm'};
+    hidl_vec<uint8_t> hidlClearKeyEmm;
+    hidlClearKeyEmm.setToExternal(static_cast<uint8_t*>(clearKeyEmmData), sizeof(clearKeyEmmData));
+    returnStatus = mMediaCas->processEmm(hidlClearKeyEmm);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    hidl_vec<uint8_t> hidlEcm;
+    hidlEcm.setToExternal(const_cast<uint8_t*>(kEcmBinaryBuffer), sizeof(kEcmBinaryBuffer));
+    returnStatus = mMediaCas->processEcm(sessionId, hidlEcm);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+    returnStatus = mMediaCas->processEcm(streamSessionId, hidlEcm);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("video/avc"));
+
+    sp<IDescrambler> descrambler;
+    descrambler = IDescrambler::castFrom(mDescramblerBase);
+    ASSERT_NE(descrambler, nullptr);
+
+    Status descrambleStatus = Status::OK;
+    sp<IMemory> dataMemory;
+
+    ASSERT_TRUE(descrambleTestInputBuffer(descrambler, &descrambleStatus, &dataMemory));
+    EXPECT_EQ(Status::OK, descrambleStatus);
+
+    ASSERT_NE(nullptr, dataMemory.get());
+    uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->unsecurePointer()));
+
+    int compareResult =
+            memcmp(static_cast<const void*>(opBuffer),
+                   static_cast<const void*>(kOutRefBinaryBuffer), sizeof(kOutRefBinaryBuffer));
+    EXPECT_EQ(0, compareResult);
+
+    returnStatus = mDescramblerBase->release();
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    returnStatus = mMediaCas->release();
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    CasHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/cas/native/1.0/Android.bp b/cas/native/1.0/Android.bp
index 880eccd..633ceb9 100644
--- a/cas/native/1.0/Android.bp
+++ b/cas/native/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 7a779b9..7883dd9 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -75,3 +75,16 @@
         "kernel_config_q_4.19",
     ]
 }
+
+vintf_compatibility_matrix {
+    name: "framework_compatibility_matrix.current.xml",
+    stem: "compatibility_matrix.current.xml",
+    srcs: [
+        "compatibility_matrix.current.xml",
+    ],
+    kernel_configs: [
+        "kernel_config_current_4.14",
+        "kernel_config_current_4.19",
+        "kernel_config_current_5.4",
+    ]
+}
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index b0caa7c..7c7f87f 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -97,6 +97,7 @@
     framework_compatibility_matrix.2.xml \
     framework_compatibility_matrix.3.xml \
     framework_compatibility_matrix.4.xml \
+    framework_compatibility_matrix.current.xml \
     framework_compatibility_matrix.device.xml \
 
 my_framework_matrix_deps += \
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
new file mode 100644
index 0000000..2bd2c93
--- /dev/null
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -0,0 +1,522 @@
+<compatibility-matrix version="1.0" type="framework" level="5">
+    <hal format="hidl" optional="true">
+        <name>android.hardware.atrace</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAtraceDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.audio</name>
+        <version>5.0</version>
+        <version>6.0</version>
+        <interface>
+            <name>IDevicesFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.audio.effect</name>
+        <version>5.0</version>
+        <version>6.0</version>
+        <interface>
+            <name>IEffectsFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.authsecret</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAuthSecret</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.audiocontrol</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAudioControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.evs</name>
+        <version>1.0</version>
+        <interface>
+            <name>IEvsEnumerator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.vehicle</name>
+        <version>2.0</version>
+        <interface>
+            <name>IVehicle</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.biometrics.face</name>
+        <version>1.0</version>
+        <interface>
+            <name>IBiometricsFace</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.biometrics.fingerprint</name>
+        <version>2.1</version>
+        <interface>
+            <name>IBiometricsFingerprint</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.bluetooth</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IBluetoothHci</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.bluetooth.audio</name>
+        <version>2.0</version>
+        <interface>
+            <name>IBluetoothAudioProvidersFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.boot</name>
+        <version>1.1</version>
+        <interface>
+            <name>IBootControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.broadcastradio</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IBroadcastRadioFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.broadcastradio</name>
+        <version>2.0</version>
+        <interface>
+            <name>IBroadcastRadio</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.camera.provider</name>
+        <version>2.4-5</version>
+        <interface>
+            <name>ICameraProvider</name>
+            <regex-instance>[^/]+/[0-9]+</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.cas</name>
+        <version>1.1</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.configstore</name>
+        <version>1.1</version>
+        <interface>
+            <name>ISurfaceFlingerConfigs</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.confirmationui</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfirmationUI</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.contexthub</name>
+        <version>1.0</version>
+        <interface>
+            <name>IContexthub</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.drm</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>ICryptoFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+        <interface>
+            <name>IDrmFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.dumpstate</name>
+        <version>1.0</version>
+        <interface>
+            <name>IDumpstateDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.gatekeeper</name>
+        <version>1.0</version>
+        <interface>
+            <name>IGatekeeper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.gnss</name>
+        <!--
+         - Both versions are listed here as a workaround for libvintf since 2.0 extends 1.1.
+         - Devices launched with Q must support gnss@2.0, see VtsTrebleVendorVintfTest
+         - test DeviceManifestTest#GnssHalVersionCompatibility.
+        -->
+        <version>1.1</version>
+        <version>2.0</version>
+        <interface>
+            <name>IGnss</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.graphics.allocator</name>
+        <version>2.0</version>
+        <version>3.0</version>
+        <interface>
+            <name>IAllocator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.graphics.composer</name>
+        <version>2.1-3</version>
+        <interface>
+            <name>IComposer</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.graphics.mapper</name>
+        <version>2.1</version>
+        <version>3.0</version>
+        <interface>
+            <name>IMapper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.health</name>
+        <version>2.1</version>
+        <interface>
+            <name>IHealth</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.health.storage</name>
+        <version>1.0</version>
+        <interface>
+            <name>IStorage</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.ir</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConsumerIr</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.input.classifier</name>
+        <version>1.0</version>
+        <interface>
+            <name>IInputClassifier</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.keymaster</name>
+        <version>3.0</version>
+        <version>4.0-1</version>
+        <interface>
+            <name>IKeymasterDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.keymaster</name>
+        <version>4.0-1</version>
+        <interface>
+            <name>IKeymasterDevice</name>
+            <instance>strongbox</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.light</name>
+        <version>2.0</version>
+        <interface>
+            <name>ILight</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IComponentStore</name>
+            <regex-instance>default[0-9]*</regex-instance>
+            <regex-instance>vendor[0-9]*_software</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.media.omx</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOmx</name>
+            <instance>default</instance>
+        </interface>
+        <interface>
+            <name>IOmxStore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.memtrack</name>
+        <version>1.0</version>
+        <interface>
+            <name>IMemtrack</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.neuralnetworks</name>
+        <version>1.0-3</version>
+        <interface>
+            <name>IDevice</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.nfc</name>
+        <version>1.2</version>
+        <interface>
+            <name>INfc</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.oemlock</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOemLock</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.power</name>
+        <version>1.0-3</version>
+        <interface>
+            <name>IPower</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.power.stats</name>
+        <version>1.0</version>
+        <interface>
+            <name>IPowerStats</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.radio</name>
+        <version>1.5</version>
+        <interface>
+            <name>IRadio</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.radio</name>
+        <version>1.2</version>
+        <interface>
+            <name>ISap</name>
+            <instance>slot1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.radio.config</name>
+        <version>1.3</version>
+        <interface>
+            <name>IRadioConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.renderscript</name>
+        <version>1.0</version>
+        <interface>
+            <name>IDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.secure_element</name>
+        <version>1.0</version>
+        <interface>
+            <name>ISecureElement</name>
+            <regex-instance>eSE[1-9][0-9]*</regex-instance>
+            <regex-instance>SIM[1-9][0-9]*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.sensors</name>
+        <version>1.0</version>
+        <version>2.0</version>
+        <interface>
+            <name>ISensors</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.soundtrigger</name>
+        <version>2.0-2</version>
+        <interface>
+            <name>ISoundTriggerHw</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tetheroffload.config</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOffloadConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tetheroffload.control</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOffloadControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.thermal</name>
+        <version>1.0</version>
+        <version>2.0</version>
+        <interface>
+            <name>IThermal</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tv.cec</name>
+        <version>1.0</version>
+        <interface>
+            <name>IHdmiCec</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tv.input</name>
+        <version>1.0</version>
+        <interface>
+            <name>ITvInput</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.usb</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>IUsb</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.usb.gadget</name>
+        <version>1.0</version>
+        <interface>
+            <name>IUsbGadget</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.vibrator</name>
+        <interface>
+            <name>IVibrator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.vibrator</name>
+        <version>1.0-3</version>
+        <interface>
+            <name>IVibrator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.vr</name>
+        <version>1.0</version>
+        <interface>
+            <name>IVr</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.weaver</name>
+        <version>1.0</version>
+        <interface>
+            <name>IWeaver</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi</name>
+        <version>1.0-3</version>
+        <interface>
+            <name>IWifi</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi.hostapd</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IHostapd</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi.supplicant</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>ISupplicant</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</compatibility-matrix>
diff --git a/configstore/1.0/Android.bp b/configstore/1.0/Android.bp
index a6fd656..d92f252 100644
--- a/configstore/1.0/Android.bp
+++ b/configstore/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/configstore/1.0/vts/functional/Android.bp b/configstore/1.0/vts/functional/Android.bp
index 008b59d..31d4b1c 100644
--- a/configstore/1.0/vts/functional/Android.bp
+++ b/configstore/1.0/vts/functional/Android.bp
@@ -19,6 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalConfigstoreV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.configstore@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
index 70b5830..8a1a313 100644
--- a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
+++ b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
@@ -16,11 +16,12 @@
 
 #define LOG_TAG "ConfigstoreHidlHalTest"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <unistd.h>
 
 using ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
@@ -35,25 +36,12 @@
 #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
 #define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
 
-// Test environment for Configstore HIDL HAL.
-class ConfigstoreHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static ConfigstoreHidlEnvironment* Instance() {
-        static ConfigstoreHidlEnvironment* instance = new ConfigstoreHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<ISurfaceFlingerConfigs>(); }
-};
-
-class ConfigstoreHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ConfigstoreHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     sp<ISurfaceFlingerConfigs> sfConfigs;
 
     virtual void SetUp() override {
-        sfConfigs = ::testing::VtsHalHidlTargetTestBase::getService<ISurfaceFlingerConfigs>(
-            ConfigstoreHidlEnvironment::Instance()->getServiceName<ISurfaceFlingerConfigs>());
+        sfConfigs = ISurfaceFlingerConfigs::getService(GetParam());
         ASSERT_NE(sfConfigs, nullptr);
     }
 
@@ -63,7 +51,7 @@
 /**
  * Ensure all ISurfaceFlingerConfigs.hal function calls are successful.
  */
-TEST_F(ConfigstoreHidlTest, TestFunctionCalls) {
+TEST_P(ConfigstoreHidlTest, TestFunctionCalls) {
     bool tmp;
 
     Return<void> status = sfConfigs->vsyncEventPhaseOffsetNs(
@@ -118,7 +106,7 @@
 /**
  * Ensure repeated call to the same function returns the same result.
  */
-TEST_F(ConfigstoreHidlTest, TestSameReturnValue) {
+TEST_P(ConfigstoreHidlTest, TestSameReturnValue) {
     int64_t original_ret;
     Return<void> status = sfConfigs->vsyncEventPhaseOffsetNs(
         [&original_ret](OptionalInt64 arg) { original_ret = arg.value; });
@@ -135,7 +123,7 @@
  * Make sure the constrains of hasWideColorDisplay, hasHDRDisplay
  * are enforced.
  */
-TEST_F(ConfigstoreHidlTest, TestColorConstrainsBasic) {
+TEST_P(ConfigstoreHidlTest, TestColorConstrainsBasic) {
     bool hasWideColorDisplay;
     bool hasHDRDisplay;
 
@@ -152,11 +140,7 @@
     }
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(ConfigstoreHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    ConfigstoreHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, ConfigstoreHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISurfaceFlingerConfigs::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/configstore/1.1/Android.bp b/configstore/1.1/Android.bp
index 3900d9b..7c5f3f7 100644
--- a/configstore/1.1/Android.bp
+++ b/configstore/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/configstore/1.1/default/Android.mk b/configstore/1.1/default/Android.mk
index 104e15e..e7edc34 100644
--- a/configstore/1.1/default/Android.mk
+++ b/configstore/1.1/default/Android.mk
@@ -17,7 +17,6 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libhidlbase \
-    libhidltransport \
     libbase \
     libhwminijail \
     liblog \
diff --git a/configstore/1.1/default/android.hardware.configstore@1.1-service.rc b/configstore/1.1/default/android.hardware.configstore@1.1-service.rc
index 105678a..d62c4a8 100644
--- a/configstore/1.1/default/android.hardware.configstore@1.1-service.rc
+++ b/configstore/1.1/default/android.hardware.configstore@1.1-service.rc
@@ -1,4 +1,6 @@
 service vendor.configstore-hal /vendor/bin/hw/android.hardware.configstore@1.1-service
+    interface android.hardware.configstore@1.0::ISurfaceFlingerConfigs default
+    interface android.hardware.configstore@1.1::ISurfaceFlingerConfigs default
     class hal animation
     user system
     group system
diff --git a/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy b/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy
index 937fddd..a609620 100644
--- a/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy
+++ b/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy
@@ -45,6 +45,7 @@
 getdents64: 1
 clock_gettime: 1
 getpid: 1
+gettid: 1
 
 # used during process crash by crash_dump to dump process info
 rt_sigprocmask: 1
diff --git a/confirmationui/1.0/Android.bp b/confirmationui/1.0/Android.bp
index e6b0414..a22067a 100644
--- a/confirmationui/1.0/Android.bp
+++ b/confirmationui/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/confirmationui/1.0/default/Android.bp b/confirmationui/1.0/default/Android.bp
index 10018e8..ecba064 100644
--- a/confirmationui/1.0/default/Android.bp
+++ b/confirmationui/1.0/default/Android.bp
@@ -36,7 +36,6 @@
         "libcrypto",
         "libbase",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
diff --git a/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
index c04e55e..adc7222 100644
--- a/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
+++ b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service
+    interface android.hardware.confirmationui@1.0::IConfirmationUI default
     class hal
     user nobody
     group drmrpc
diff --git a/confirmationui/1.0/vts/functional/Android.bp b/confirmationui/1.0/vts/functional/Android.bp
index d19d702..fd088cd 100644
--- a/confirmationui/1.0/vts/functional/Android.bp
+++ b/confirmationui/1.0/vts/functional/Android.bp
@@ -23,7 +23,7 @@
     static_libs: [
         "android.hardware.confirmationui@1.0",
         "android.hardware.keymaster@4.0",
-        "libcrypto",
+        "libcrypto_static",
         "libcn-cbor",
         "android.hardware.confirmationui-support-lib",
     ],
diff --git a/confirmationui/support/include/ConfirmationUITranslations.h b/confirmationui/support/include/ConfirmationUITranslations.h
new file mode 100644
index 0000000..a55dc08
--- /dev/null
+++ b/confirmationui/support/include/ConfirmationUITranslations.h
@@ -0,0 +1,27 @@
+/*
+**
+** Copyright 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.
+*/
+
+/* Generated by generate-translations.py - DO NOT EDIT */
+
+#ifndef ConfirmationUITranslations_H
+#define ConfirmationUITranslations_H
+
+const char* ConfirmationUITranslations_select_lang_id(const char* lang_id);
+
+const char* ConfirmationUITranslations_lookup(const char* translation_id);
+
+#endif // ConfirmationUITranslations_H
diff --git a/confirmationui/support/src/ConfirmationUITranslations.c b/confirmationui/support/src/ConfirmationUITranslations.c
new file mode 100644
index 0000000..4d616ae
--- /dev/null
+++ b/confirmationui/support/src/ConfirmationUITranslations.c
@@ -0,0 +1,1158 @@
+/*
+**
+** Copyright 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.
+*/
+
+/* Generated by generate-translations.py - DO NOT EDIT */
+
+#include "ConfirmationUITranslations.h"
+#include "string.h"
+
+static const char* ConfirmationUITranslations_language_ids[] = {
+  "en", /* untranslated */
+  "af",
+  "am",
+  "ar",
+  "ar-EG",
+  "ar-JO",
+  "ar-MA",
+  "ar-SA",
+  "ar-XB",
+  "as",
+  "az",
+  "be",
+  "bg",
+  "bn",
+  "bs",
+  "ca",
+  "cs",
+  "da",
+  "de",
+  "de-AT",
+  "de-CH",
+  "el",
+  "en-AU",
+  "en-CA",
+  "en-GB",
+  "en-IE",
+  "en-IN",
+  "en-SG",
+  "en-XA",
+  "en-XC",
+  "en-ZA",
+  "es",
+  "es-419",
+  "es-AR",
+  "es-BO",
+  "es-CL",
+  "es-CO",
+  "es-CR",
+  "es-DO",
+  "es-EC",
+  "es-GT",
+  "es-HN",
+  "es-MX",
+  "es-NI",
+  "es-PA",
+  "es-PE",
+  "es-PR",
+  "es-PY",
+  "es-SV",
+  "es-US",
+  "es-UY",
+  "es-VE",
+  "et",
+  "eu",
+  "fa",
+  "fi",
+  "fil",
+  "fr",
+  "fr-CA",
+  "fr-CH",
+  "gl",
+  "gsw",
+  "gu",
+  "he",
+  "hi",
+  "hr",
+  "hu",
+  "hy",
+  "id",
+  "in",
+  "is",
+  "it",
+  "iw",
+  "ja",
+  "ka",
+  "kk",
+  "km",
+  "kn",
+  "ko",
+  "ky",
+  "ln",
+  "lo",
+  "lt",
+  "lv",
+  "mk",
+  "ml",
+  "mn",
+  "mo",
+  "mr",
+  "ms",
+  "my",
+  "nb",
+  "ne",
+  "nl",
+  "no",
+  "or",
+  "pa",
+  "pl",
+  "pt",
+  "pt-BR",
+  "pt-PT",
+  "ro",
+  "ru",
+  "si",
+  "sk",
+  "sl",
+  "sq",
+  "sr",
+  "sr-Latn",
+  "sv",
+  "sw",
+  "ta",
+  "te",
+  "th",
+  "tl",
+  "tr",
+  "uk",
+  "ur",
+  "uz",
+  "vi",
+  "zh",
+  "zh-CN",
+  "zh-HK",
+  "zh-TW",
+  "zu",
+  NULL,
+};
+
+#define ARRAY_ELEMENTS(arr) \
+    (sizeof(arr)/sizeof(arr[0]))
+
+#define ConfirmationUITranslations_NUM_LANGUAGE_IDS \
+    (ARRAY_ELEMENTS(ConfirmationUITranslations_language_ids) - 1)
+
+static const struct {
+  const char* translation_id;
+  const char* translations[ConfirmationUITranslations_NUM_LANGUAGE_IDS];
+} ConfirmationUITranslations_translation_ids[] = {
+  {
+    "1424834532030812203",
+    {
+      "Double-press power to confirm", /* en (untranslated) */
+      "Dubbeldruk aan/af-skakelaar om te bevestig", /* af */
+      "ለማረጋገጥ ኃይልን ሁለቴ ይጫኑ", /* am */
+      "اضغط على زر التشغيل مرتين لتأكيد الإجراء.", /* ar */
+      "اضغط على زر التشغيل مرتين لتأكيد الإجراء.", /* ar-EG */
+      "اضغط على زر التشغيل مرتين لتأكيد الإجراء.", /* ar-JO */
+      "اضغط على زر التشغيل مرتين لتأكيد الإجراء.", /* ar-MA */
+      "اضغط على زر التشغيل مرتين لتأكيد الإجراء.", /* ar-SA */
+      "‏‮Double‬‏-‏‮press‬‏ ‏‮power‬‏ ‏‮to‬‏ ‏‮confirm‬‏", /* ar-XB */
+      "নিশ্চিত কৰিবলৈ পাৱাৰ বুটামটো দুবাৰ হেঁচক", /* as */
+      "Təsdiqləmək üçün iki dəfə yandırıb-söndürmək düyməsinə basın", /* az */
+      "Двойчы націсніце кнопку сілкавання, каб пацвердзіць", /* be */
+      "Натиснете два пъти бутона за захранване, за да потвърдите", /* bg */
+      "নিশ্চিত করতে পাওয়ার বোতাম দুবার টিপুন", /* bn */
+      "Dva puta pritisnite dugme za napajanje da potvrdite", /* bs */
+      "Prem dos cops el botó d'engegada per confirmar", /* ca */
+      "Potvrďte dvojitým stisknutím vypínače", /* cs */
+      "Tryk to gange på afbryderknappen for at bekræfte", /* da */
+      "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken", /* de */
+      "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken", /* de-AT */
+      "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken", /* de-CH */
+      "Πατήστε δύο φορές το κουμπί λειτουργίας για επιβεβαίωση", /* el */
+      "Double-press power to confirm", /* en-AU */
+      "Double-press power to confirm", /* en-CA */
+      "Double-press power to confirm", /* en-GB */
+      "Double-press power to confirm", /* en-IE */
+      "Double-press power to confirm", /* en-IN */
+      "Double-press power to confirm", /* en-SG */
+      "[Ðöûбļé-þŕéšš þöŵéŕ ţö çöñƒîŕm one two three four five six seven]", /* en-XA */
+      "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‎‏‎‏‏‎Double-press power to confirm‎‏‎‎‏‎", /* en-XC */
+      "Double-press power to confirm", /* en-ZA */
+      "Pulsa dos veces el botón de encendido para confirmar", /* es */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-419 */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-AR */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-BO */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-CL */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-CO */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-CR */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-DO */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-EC */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-GT */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-HN */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-MX */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-NI */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-PA */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-PE */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-PR */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-PY */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-SV */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-US */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-UY */
+      "Presiona dos veces el botón de encendido para confirmar", /* es-VE */
+      "Kinnitamiseks topeltvajutage toitenuppu", /* et */
+      "Berresteko, sakatu birritan pizteko botoia", /* eu */
+      "برای تأیید، دکمه روشن/خاموش را دوبار فشار دهید", /* fa */
+      "Vahvista painamalla virtapainiketta kahdesti", /* fi */
+      "Pindutin nang dalawang beses ang power para kumpirmahin", /* fil */
+      "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération", /* fr */
+      "Appuyez deux fois sur l'interrupteur pour confirmer", /* fr-CA */
+      "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération", /* fr-CH */
+      "Preme o botón de acendido dúas veces para confirmar", /* gl */
+      "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken", /* gsw */
+      "કન્ફર્મ કરવા માટે પાવર પર બે વાર ટૅપ કરો", /* gu */
+      "יש ללחוץ פעמיים על לחצן ההפעלה כדי לאשר", /* he */
+      "पुष्टि करने के लिए पावर बटन दो बार दबाएं", /* hi */
+      "Dvaput pritisnite tipku za uključivanje/isključivanje da biste potvrdili", /* hr */
+      "A megerősítéshez nyomja meg duplán a bekapcsológombot", /* hu */
+      "Հաստատելու համար կրկնակի սեղմեք սնուցման կոճակը", /* hy */
+      "Tekan dua kali tombol power untuk mengonfirmasi", /* id */
+      "Tekan dua kali tombol power untuk mengonfirmasi", /* in */
+      "Ýttu tvisvar á aflrofann til að staðfesta", /* is */
+      "Premi due volte il tasto di accensione per confermare", /* it */
+      "יש ללחוץ פעמיים על לחצן ההפעלה כדי לאשר", /* iw */
+      "確認するには、電源を 2 回押します", /* ja */
+      "დასადასტურებლად ორმაგად დააჭირეთ ჩართვის ღილაკს", /* ka */
+      "Растау үшін қуат түймесін екі рет басыңыз", /* kk */
+      "ចុច​ប៊ូតុង​ថាមពល​ពីរដង​ដើម្បី​បញ្ជាក់", /* km */
+      "ದೃಢೀಕರಿಸಲು ಪವರ್‌ ಬಟನ್‌ ಅನ್ನು ಎರಡು ಬಾರಿ ಒತ್ತಿರಿ", /* kn */
+      "확인하려면 전원 버튼을 두 번 누르세요.", /* ko */
+      "Ырастоо үчүн \"Кубат\" баскычын эки жолу басыңыз", /* ky */
+      "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération", /* ln */
+      "ກົດປຸ່ມປິດເປີດເຄື່ອງສອງຄັ້ງເພື່ອຢືນຢັນ", /* lo */
+      "Dukart paspauskite maitinimo mygtuką, kad patvirtintumėte", /* lt */
+      "Lai apstiprinātu, divreiz nospiediet barošanas pogu", /* lv */
+      "Притиснете на копчето за напојување двапати за да потврдите", /* mk */
+      "സ്ഥിരീകരിക്കാൻ പവർ രണ്ടുതവണ അമർത്തുക", /* ml */
+      "Баталгаажуулахын тулд унтраах/асаахыг хоёр удаа дарах", /* mn */
+      "Apăsați de două ori butonul de pornire pentru a confirma", /* mo */
+      "खात्री करण्‍यासाठी पॉवर बटण दोनदा दाबा", /* mr */
+      "Tekan dua kali butang kuasa untuk mengesahkan", /* ms */
+      "အတည်ပြုရန် ပါဝါခလုတ်ကို နှစ်ချက်နှိပ်ပါ", /* my */
+      "Dobbelttrykk på av/på-knappen for å bekrefte", /* nb */
+      "पुष्टि गर्न पावर बटनमा दुई पटक थिच्नुहोस्", /* ne */
+      "Druk twee keer op de aan/uit-knop om te bevestigen", /* nl */
+      "Dobbelttrykk på av/på-knappen for å bekrefte", /* no */
+      "ସୁନିଶ୍ଚିତ କରିବା ପାଇଁ ପାୱାର୍‍ ବଟନ୍‍କୁ ଦୁଇଥର ଦବାନ୍ତୁ", /* or */
+      "ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਪਾਵਰ ਬਟਨ ਨੂੰ ਦੋ ਬਾਰ ਦੱਬੋ", /* pa */
+      "Kliknij dwukrotnie przycisk zasilania, by potwierdzić", /* pl */
+      "Pressione o botão liga/desliga duas vezes para confirmar", /* pt */
+      "Pressione o botão liga/desliga duas vezes para confirmar", /* pt-BR */
+      "Prima duas vezes ligar/desligar para confirmar.", /* pt-PT */
+      "Apăsați de două ori butonul de pornire pentru a confirma", /* ro */
+      "Для подтверждения дважды нажмите кнопку питания.", /* ru */
+      "තහවුරු කිරීමට බල බොත්තම දෙවරක් ඔබන්න", /* si */
+      "Potvrďte dvojitým stlačením vypínača", /* sk */
+      "Dvakrat pritisnite za potrditev", /* sl */
+      "Shtyp dy herë butonin e energjisë për të konfirmuar", /* sq */
+      "Двапут притисните дугме за напајање да бисте потврдили", /* sr */
+      "Dvaput pritisnite dugme za napajanje da biste potvrdili", /* sr-Latn */
+      "Bekräfta genom att trycka två gånger på avstängningsknappen", /* sv */
+      "Bonyeza kitufe cha kuwasha mara mbili ili uthibitishe", /* sw */
+      "உறுதிப்படுத்த, பவர் பட்டனை இருமுறை அழுத்தவும்", /* ta */
+      "నిర్ధారించడానికి పవర్ బటన్‌ని రెండు సార్లు నొక్కండి", /* te */
+      "กดปุ่มเปิด/ปิด 2 ครั้งเพื่อยืนยัน", /* th */
+      "Pindutin nang dalawang beses ang power para kumpirmahin", /* tl */
+      "Onaylamak için güç düğmesine iki kez basın", /* tr */
+      "Двічі натисніть кнопку живлення, щоб підтвердити", /* uk */
+      "تصدیق کرنے کے لئے پاور بٹن دوبار دبائیں", /* ur */
+      "Tasdiqlash uchun quvvat tugmasini ikki marta bosing", /* uz */
+      "Nhấn hai lần vào nút nguồn để xác nhận", /* vi */
+      "连按两次电源按钮即可确认", /* zh */
+      "连按两次电源按钮即可确认", /* zh-CN */
+      "按兩下電源按鈕即可確認", /* zh-HK */
+      "按兩下電源按鈕即可確認操作", /* zh-TW */
+      "Cindezela kabili ukuze uqinisekise", /* zu */
+    }
+  },
+  {
+    "1796282799666106567",
+    {
+      "Cancel", /* en (untranslated) */
+      "Kanselleer", /* af */
+      "ይቅር", /* am */
+      "إلغاء", /* ar */
+      "إلغاء", /* ar-EG */
+      "إلغاء", /* ar-JO */
+      "إلغاء", /* ar-MA */
+      "إلغاء", /* ar-SA */
+      "‏‮Cancel‬‏", /* ar-XB */
+      "বাতিল কৰক", /* as */
+      "Ləğv edin", /* az */
+      "Скасаваць", /* be */
+      "Отказ", /* bg */
+      "বাতিল করুন", /* bn */
+      "Otkaži", /* bs */
+      "Cancel·la", /* ca */
+      "Zrušit", /* cs */
+      "Annuller", /* da */
+      "Abbrechen", /* de */
+      "Abbrechen", /* de-AT */
+      "Abbrechen", /* de-CH */
+      "Ακύρωση", /* el */
+      "Cancel", /* en-AU */
+      "Cancel", /* en-CA */
+      "Cancel", /* en-GB */
+      "Cancel", /* en-IE */
+      "Cancel", /* en-IN */
+      "Cancel", /* en-SG */
+      "[Çåñçéļ one]", /* en-XA */
+      "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‎‎‏‎‎‎‎‏‏‎‎‎‏‏‏‎Cancel‎‏‎‎‏‎", /* en-XC */
+      "Cancel", /* en-ZA */
+      "Cancelar", /* es */
+      "Cancelar", /* es-419 */
+      "Cancelar", /* es-AR */
+      "Cancelar", /* es-BO */
+      "Cancelar", /* es-CL */
+      "Cancelar", /* es-CO */
+      "Cancelar", /* es-CR */
+      "Cancelar", /* es-DO */
+      "Cancelar", /* es-EC */
+      "Cancelar", /* es-GT */
+      "Cancelar", /* es-HN */
+      "Cancelar", /* es-MX */
+      "Cancelar", /* es-NI */
+      "Cancelar", /* es-PA */
+      "Cancelar", /* es-PE */
+      "Cancelar", /* es-PR */
+      "Cancelar", /* es-PY */
+      "Cancelar", /* es-SV */
+      "Cancelar", /* es-US */
+      "Cancelar", /* es-UY */
+      "Cancelar", /* es-VE */
+      "Tühista", /* et */
+      "Utzi", /* eu */
+      "لغو", /* fa */
+      "Peruuta", /* fi */
+      "Kanselahin", /* fil */
+      "Annuler", /* fr */
+      "Annuler", /* fr-CA */
+      "Annuler", /* fr-CH */
+      "Cancelar", /* gl */
+      "Abbrechen", /* gsw */
+      "રદ કરો", /* gu */
+      "ביטול", /* he */
+      "रद्द करें", /* hi */
+      "Otkaži", /* hr */
+      "Mégse", /* hu */
+      "Չեղարկել", /* hy */
+      "Batal", /* id */
+      "Batal", /* in */
+      "Hætta við", /* is */
+      "Annulla", /* it */
+      "ביטול", /* iw */
+      "キャンセル", /* ja */
+      "გაუქმება", /* ka */
+      "Бас тарту", /* kk */
+      "បោះបង់", /* km */
+      "ರದ್ದು", /* kn */
+      "취소", /* ko */
+      "Жокко чыгаруу", /* ky */
+      "Annuler", /* ln */
+      "ຍົກເລີກ", /* lo */
+      "Atšaukti", /* lt */
+      "Atcelt", /* lv */
+      "Откажи", /* mk */
+      "റദ്ദാക്കുക", /* ml */
+      "Болих", /* mn */
+      "Anulați", /* mo */
+      "रद्द करा", /* mr */
+      "Batal", /* ms */
+      "မလုပ်တော့", /* my */
+      "Avbryt", /* nb */
+      "रद्द गर्नुहोस्", /* ne */
+      "Annuleren", /* nl */
+      "Avbryt", /* no */
+      "କ୍ୟାନ୍ସଲ୍‍ କରନ୍ତୁ", /* or */
+      "ਰੱਦ ਕਰੋ", /* pa */
+      "Anuluj", /* pl */
+      "Cancelar", /* pt */
+      "Cancelar", /* pt-BR */
+      "Cancelar", /* pt-PT */
+      "Anulați", /* ro */
+      "Отмена", /* ru */
+      "අවලංගු කරන්න", /* si */
+      "Zrušiť", /* sk */
+      "Prekliči", /* sl */
+      "Anulo", /* sq */
+      "Откажи", /* sr */
+      "Otkaži", /* sr-Latn */
+      "Avbryt", /* sv */
+      "Ghairi", /* sw */
+      "ரத்துசெய்", /* ta */
+      "రద్దు చేయండి", /* te */
+      "ยกเลิก", /* th */
+      "Kanselahin", /* tl */
+      "İptal", /* tr */
+      "Скасувати", /* uk */
+      "منسوخ کریں", /* ur */
+      "Bekor qilish", /* uz */
+      "Hủy", /* vi */
+      "取消", /* zh */
+      "取消", /* zh-CN */
+      "取消", /* zh-HK */
+      "取消", /* zh-TW */
+      "Khansela", /* zu */
+    }
+  },
+  {
+    "217688588483778177",
+    {
+      "This confirmation provides an extra layer of security for the action you're about to take.", /* en (untranslated) */
+      "Hierdie bevestiging verskaf 'n ekstra laag sekuriteit vir die handeling wat jy op die punt is om uit te voer.", /* af */
+      "ይህ ማረጋገጫ እርስዎ ለሚወስዱት እርምጃ ተጨማሪ ትርፍ ጥበቃን ይሰጣል።", /* am */
+      "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.", /* ar */
+      "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.", /* ar-EG */
+      "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.", /* ar-JO */
+      "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.", /* ar-MA */
+      "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.", /* ar-SA */
+      "‏‮This‬‏ ‏‮confirmation‬‏ ‏‮provides‬‏ ‏‮an‬‏ ‏‮extra‬‏ ‏‮layer‬‏ ‏‮of‬‏ ‏‮security‬‏ ‏‮for‬‏ ‏‮the‬‏ ‏‮action‬‏ ‏‮you‬‏'‏‮re‬‏ ‏‮about‬‏ ‏‮to‬‏ ‏‮take‬‏.", /* ar-XB */
+      "এই প্ৰতিশ্ৰুতিয়ে আপুনি কৰিব বিচৰা কোনো কাৰ্যৰ বাবে অতিৰিক্ত সুৰক্ষা প্ৰদান কৰে।", /* as */
+      "Bu təsdiq etmək üzrə olduğunuz əməliyyat üçün əlavə təhlükəsizlik qatı təmin edir.", /* az */
+      "Гэта пацвярджэнне забяспечвае дадатковы ўзровень бяспекі для дзеянняў, якія вы збіраецеся выконваць.", /* be */
+      "Това потвърждение осигурява допълнителна защита за действието, което сте напът да предприемете.", /* bg */
+      "আপনি যে কাজটি করতে চলেছেন, এই কনফার্মেশনের ফলে সেটির জন্য অতিরিক্ত সুরক্ষার ব্যবস্থা করা হয়।", /* bn */
+      "Ova potvrda pruža dodatni sloj zaštite za radnju koju namjeravate preduzeti.", /* bs */
+      "Aquesta confirmació proporciona una capa de seguretat addicional per a l'acció que estàs a punt de dur a terme.", /* ca */
+      "Toto potvrzení tvoří dodatečnou úroveň zabezpečení akce, kterou se chystáte podniknout.", /* cs */
+      "Denne bekræftelse giver et ekstra beskyttelsesniveau for den handling, du er ved at foretage.", /* da */
+      "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.", /* de */
+      "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.", /* de-AT */
+      "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmassnahme angewandt.", /* de-CH */
+      "Αυτή η επιβεβαίωση παρέχει ένα επιπλέον επίπεδο ασφάλειας για την ενέργεια που πρόκειται να εκτελέσετε.", /* el */
+      "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-AU */
+      "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-CA */
+      "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-GB */
+      "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-IE */
+      "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-IN */
+      "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-SG */
+      "[Ţĥîš çöñƒîŕmåţîöñ þŕövîðéš åñ éxţŕå ļåýéŕ öƒ šéçûŕîţý ƒöŕ ţĥé åçţîöñ ýöû'ŕé åбöûţ ţö ţåķé. one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen]", /* en-XA */
+      "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎This confirmation provides an extra layer of security for the action you're about to take.‎‏‎‎‏‎", /* en-XC */
+      "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-ZA */
+      "Esta confirmación proporciona una capa de seguridad adicional a la acción que vas a realizar.", /* es */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-419 */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-AR */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-BO */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-CL */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-CO */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-CR */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-DO */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-EC */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-GT */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-HN */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-MX */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-NI */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-PA */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-PE */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-PR */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-PY */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-SV */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-US */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-UY */
+      "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-VE */
+      "See kinnitus annab veel ühe turvakihi toimingu puhul, mille nüüd teete.", /* et */
+      "Berrespen honek segurtasun handiagoa ematen dizu hurrengo ekintza gauzatzeko.", /* eu */
+      "این تأیید یک لایه امنیتی اضافی برای کنشی که می‌خواهید انجام دهید فراهم می‌کند.", /* fa */
+      "Tämä vahvistus tarkoittaa, että seuraava toimintosi on entistä paremmin suojattu.", /* fi */
+      "Ang pagkumpirmang ito ay nagbibigay ng karagdagang layer ng seguridad para sa pagkilos na gagawin mo.", /* fil */
+      "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.", /* fr */
+      "Cette confirmation fournit une couche supplémentaire de sécurité pour l'action que vous êtes sur le point d'effectuer.", /* fr-CA */
+      "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.", /* fr-CH */
+      "Esta confirmación proporciona unha capa adicional de seguranza para a acción que estás a piques de levar a cabo.", /* gl */
+      "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.", /* gsw */
+      "તમે જે ક્રિયા કરવાના છો તેના માટે આ કન્ફર્મેશન એક અતિરિક્ત સુરક્ષાનું સ્તર પ્રદાન કરે છે.", /* gu */
+      "אישור זה מספק שכבת אבטחה נוספת לפעולה שאתה עומד לבצע.", /* he */
+      "यह पुष्टि मिलने पर आप जो काम करने वाले हैं, उसके लिए सुरक्षा और बढ़ जाती है.", /* hi */
+      "Ta potvrda pruža dodatan sloj zaštite za radnju koju ćete izvršiti.", /* hr */
+      "Ez a megerősítés extra réteg biztonságot nyújt a végrehajtani kívánt művelet számára.", /* hu */
+      "Այս հաստատումն ապահովում է պաշտպանության լրացուցիչ մակարդակ՝ նախքան գործողություն կատարելը", /* hy */
+      "Konfirmasi ini memberikan lapisan keamanan tambahan untuk tindakan yang akan Anda ambil.", /* id */
+      "Konfirmasi ini memberikan lapisan keamanan tambahan untuk tindakan yang akan Anda ambil.", /* in */
+      "Þessi staðfesting veitir aukið öryggi fyrir aðgerðina sem þú ert að fara að framkvæma.", /* is */
+      "Questa conferma garantisce un ulteriore livello di sicurezza per l'azione che stai per compiere.", /* it */
+      "אישור זה מספק שכבת אבטחה נוספת לפעולה שאתה עומד לבצע.", /* iw */
+      "この確認により、これから行う操作のセキュリティが強化されます。", /* ja */
+      "დადასტურება უსაფრთხოების დამატებით შრეს უზრუნველყოფს იმ ქმედების განსახორციელებლად, რომელსაც აპირებთ.", /* ka */
+      "Бұл растау функциясы орындағалы тұрған әрекеттің қауіпсіздігін қосымша күшейтеді.", /* kk */
+      "ការបញ្ជាក់នេះ​ផ្ដល់ស្រទាប់​សុវត្ថិភាព​បន្ថែម​សម្រាប់​សកម្មភាព​ដែលអ្នកហៀប​នឹងធ្វើ។", /* km */
+      "ಈ ದೃಢೀಕರಣವು ನೀವು ನಿರ್ವಹಿಸಲು ಬಯಸುವ ಕ್ರಿಯೆಗೆ ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯನ್ನು ಒದಗಿಸುತ್ತದೆ.", /* kn */
+      "이 확인 단계를 사용하면 실행하려는 작업의 보안을 한층 강화할 수 있습니다.", /* ko */
+      "Бул ырастоо сиз аткара турган аракеттин коопсуздугун коргоонун дагы бир катмарын камсыздайт.", /* ky */
+      "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.", /* ln */
+      "ການຢືນຢັນນີ້ຈະເພີ່ມຄວາມປອດໄພເພີ່ມເຕີມອີກໜຶ່ງຊັ້ນໃຫ້ກັບຄຳສັ່ງທີ່ທ່ານກຳລັງຈະໃຊ້.", /* lo */
+      "Naudojant šį patvirtinimą, veiksmui, kurį ketinate atlikti, taikomas papildomas saugos lygmuo.", /* lt */
+      "Šis apstiprinājums sniedz papildu aizsardzību darbībai, kuru veiksiet.", /* lv */
+      "Оваа потврда обезбедува дополнителен слој на безбедност за дејството што ќе го преземете.", /* mk */
+      "നിങ്ങൾ സ്വീകരിക്കാൻ പോകുന്ന നടപടിക്കായി, ഈ സ്ഥിരീകരണം ഒരു അധിക സുരക്ഷാ പാളി നൽകുന്നു.", /* ml */
+      "Энэ баталгаажуулалт нь таны авах гэж буй арга хэмжээнд хамгаалалтын нэмэлт давхаргыг олгодог.", /* mn */
+      "Această confirmare oferă un nivel suplimentar de securitate pentru acțiunea pe care urmează să o faceți.", /* mo */
+      "हे निश्चित झाल्‍यावर, तुम्‍ही जे काम करणार आहात, त्‍यासाठी सुरक्षा आणखी वाढते.", /* mr */
+      "Pengesahan ini memberikan lapisan keselamatan tambahan untuk tindakan yang akan anda ambil.", /* ms */
+      "ဤအတည်ပြုချက်က သင်ပြုလုပ်တော့မည့် လုပ်ဆောင်ချက်အတွက် အပိုဆောင်းလုံခြုံရေးကို ပေးထားသည်။", /* my */
+      "Denne bekreftelsen gir et ekstra sikkerhetslag for handlingen du er i ferd med å utføre.", /* nb */
+      "यो पुष्टिले तपाईंले गर्न ऑंट्नुभएको कारबाहीका लागि सुरक्षाको अतिरिक्त तह प्रदान गर्छ।", /* ne */
+      "Deze bevestiging biedt een extra beveiligingslaag voor de actie die je wilt uitvoeren.", /* nl */
+      "Denne bekreftelsen gir et ekstra sikkerhetslag for handlingen du er i ferd med å utføre.", /* no */
+      "ଏହି ସୁନିଶ୍ଚିତତା, ଆପଣ କରିବାକୁ ଯାଉଥିବା କାର୍ଯ୍ୟ ପାଇଁ ଅତିରିକ୍ତ ସୁରକ୍ଷା ପରତ ପ୍ରଦାନ କରିଥାଏ।", /* or */
+      "ਇਹ ਪੁਸ਼ਟੀਕਰਨ ਤੁਹਾਡੇ ਵੱਲੋਂ ਕਾਰਵਾਈ ਨੂੰ ਕੀਤੇ ਜਾਣ ਲਈ ਸੁਰੱਖਿਆ ਦੇ ਇੱਕ ਵਾਧੂ ਪੱਧਰ ਮੁਹੱਈਆ ਕਰਦੀ ਹੈ।", /* pa */
+      "To potwierdzenie stanowi dodatkowe zabezpieczenie czynności, którą zamierzasz wykonać.", /* pl */
+      "Essa confirmação oferece uma camada adicional de segurança para a ação que você está prestes a realizar.", /* pt */
+      "Essa confirmação oferece uma camada adicional de segurança para a ação que você está prestes a realizar.", /* pt-BR */
+      "Esta confirmação oferece um nível extra de segurança para a ação que está prestes a realizar.", /* pt-PT */
+      "Această confirmare oferă un nivel suplimentar de securitate pentru acțiunea pe care urmează să o faceți.", /* ro */
+      "Дополнительный уровень защиты для действия, которое вы собираетесь выполнить.", /* ru */
+      "මෙම තහවුරු කිරිම ඔබ ගැනීමට යන ක්‍රියාමාර්ගය සඳහා ආරක්ෂාව පිළිබඳ අමතර ස්තරයක් සපයයි.", /* si */
+      "Toto potvrdenie zaistí dodatočnú úroveň zabezpečenia akcie, ktorú sa chystáte vykonať.", /* sk */
+      "Ta potrditev zagotavlja dodatno plast zaščite za dejanje, ki ga boste izvedli.", /* sl */
+      "Konfirmim ofron një shtresë sigurie shtesë për veprimin që je gati për të ndërmarrë.", /* sq */
+      "Ова потврда пружа додатни слој безбедности за радњу коју се спремате да извршите.", /* sr */
+      "Ova potvrda pruža dodatni sloj bezbednosti za radnju koju se spremate da izvršite.", /* sr-Latn */
+      "Bekräftelsen ger extra skydd för åtgärden du ska vidta.", /* sv */
+      "Uthibitishaji huu hutoa ulinzi zaidi wa usalama kwa hatua unayotaka kuchukua.", /* sw */
+      "நீங்கள் மேற்கொள்ளவிருக்கும் செயலுக்கு, கூடுதல் பாதுகாப்பை இந்த உறுதிப்படுத்தல் வழங்கும்.", /* ta */
+      "ఈ నిర్ధారణ మీరు తీసుకోబోయే చర్య కోసం అదనపు భద్రతా లేయర్‌ను అందిస్తుంది.", /* te */
+      "การยืนยันนี้จะช่วยเพิ่มความปลอดภัยอีกขั้นสำหรับสิ่งที่คุณกำลังจะดำเนินการ", /* th */
+      "Ang pagkumpirmang ito ay nagbibigay ng karagdagang layer ng seguridad para sa pagkilos na gagawin mo.", /* tl */
+      "Bu onay, yapmak üzere olduğunuz işlem için ek güvenlik katmanı sağlar.", /* tr */
+      "Це підтвердження є додатковим рівнем захисту, коли ви збираєтеся виконати дію.", /* uk */
+      "آپ جو کارروائی کرنے والے ہیں اس کے لئے یہ تصدیق ایک اضافی پرت فراہم کرتی ہے۔", /* ur */
+      "Tasdiqlangandan keyin bajarilayotgan amal uchun qo‘shimcha xavfsizlik qatlami taqdim etiladi.", /* uz */
+      "Xác nhận này cung cấp thêm một lớp bảo mật cho hành động bạn sắp thực hiện.", /* vi */
+      "这项确认可为您即将执行的操作增添一层额外的安全保障。", /* zh */
+      "这项确认可为您即将执行的操作增添一层额外的安全保障。", /* zh-CN */
+      "此確認可為你即將執行的操作提供額外安全保障。", /* zh-HK */
+      "這項確認作業可為你即將執行的動作提供多一層安全保障。", /* zh-TW */
+      "Lokhu kuqinisekiswa kunikeza isendlalelo esingeziwe sokuvikelwa sesenzo osuzosithatha.", /* zu */
+    }
+  },
+  {
+    "2181224373757710937",
+    {
+      "Press power to confirm", /* en (untranslated) */
+      "Druk aan/af-skakelaar om te bevestig", /* af */
+      "ለማረጋገጥ ኃይልን ይጫኑ", /* am */
+      "اضغط على زر التشغيل لتأكيد الإجراء.", /* ar */
+      "اضغط على زر التشغيل لتأكيد الإجراء.", /* ar-EG */
+      "اضغط على زر التشغيل لتأكيد الإجراء.", /* ar-JO */
+      "اضغط على زر التشغيل لتأكيد الإجراء.", /* ar-MA */
+      "اضغط على زر التشغيل لتأكيد الإجراء.", /* ar-SA */
+      "‏‮Press‬‏ ‏‮power‬‏ ‏‮to‬‏ ‏‮confirm‬‏", /* ar-XB */
+      "নিশ্চিত কৰিবলৈ পাৱাৰ বুটাম হেঁচক", /* as */
+      "Təsdiq etmək üçün yandırıb-söndürmə düyməsinə basın", /* az */
+      "Націсніце кнопку сілкавання, каб пацвердзіць", /* be */
+      "Натиснете бутона за захранване, за да потвърдите", /* bg */
+      "নিশ্চিত করতে পাওয়ার বোতাম টিপুন", /* bn */
+      "Pritisnite dugme za napajanje za potvrdu", /* bs */
+      "Prem el botó d'engegada per confirmar", /* ca */
+      "Potvrďte stisknutím vypínače", /* cs */
+      "Tryk på afbryderknappen for at bekræfte", /* da */
+      "Drücke zum Bestätigen die Ein-/Aus-Taste", /* de */
+      "Drücke zum Bestätigen die Ein-/Aus-Taste", /* de-AT */
+      "Drücke zum Bestätigen die Ein-/Aus-Taste", /* de-CH */
+      "Πατήστε το κουμπί λειτουργίας για επιβεβαίωση", /* el */
+      "Press power to confirm", /* en-AU */
+      "Press power to confirm", /* en-CA */
+      "Press power to confirm", /* en-GB */
+      "Press power to confirm", /* en-IE */
+      "Press power to confirm", /* en-IN */
+      "Press power to confirm", /* en-SG */
+      "[Þŕéšš þöŵéŕ ţö çöñƒîŕm one two three four five]", /* en-XA */
+      "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‎Press power to confirm‎‏‎‎‏‎", /* en-XC */
+      "Press power to confirm", /* en-ZA */
+      "Pulsa el botón de encendido para confirmar", /* es */
+      "Presiona el botón de encendido para confirmar", /* es-419 */
+      "Presiona el botón de encendido para confirmar", /* es-AR */
+      "Presiona el botón de encendido para confirmar", /* es-BO */
+      "Presiona el botón de encendido para confirmar", /* es-CL */
+      "Presiona el botón de encendido para confirmar", /* es-CO */
+      "Presiona el botón de encendido para confirmar", /* es-CR */
+      "Presiona el botón de encendido para confirmar", /* es-DO */
+      "Presiona el botón de encendido para confirmar", /* es-EC */
+      "Presiona el botón de encendido para confirmar", /* es-GT */
+      "Presiona el botón de encendido para confirmar", /* es-HN */
+      "Presiona el botón de encendido para confirmar", /* es-MX */
+      "Presiona el botón de encendido para confirmar", /* es-NI */
+      "Presiona el botón de encendido para confirmar", /* es-PA */
+      "Presiona el botón de encendido para confirmar", /* es-PE */
+      "Presiona el botón de encendido para confirmar", /* es-PR */
+      "Presiona el botón de encendido para confirmar", /* es-PY */
+      "Presiona el botón de encendido para confirmar", /* es-SV */
+      "Presiona el botón de encendido para confirmar", /* es-US */
+      "Presiona el botón de encendido para confirmar", /* es-UY */
+      "Presiona el botón de encendido para confirmar", /* es-VE */
+      "Kinnitamiseks vajutage toitenuppu", /* et */
+      "Berresteko, sakatu etengailua", /* eu */
+      "برای تأیید، دکمه روشن/خاموش را فشار دهید", /* fa */
+      "Vahvista painamalla virtapainiketta", /* fi */
+      "Pindutin ang power para kumpirmahin", /* fil */
+      "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération", /* fr */
+      "Appuyez sur l'interrupteur pour confirmer", /* fr-CA */
+      "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération", /* fr-CH */
+      "Preme o botón de acendido para confirmar", /* gl */
+      "Drücke zum Bestätigen die Ein-/Aus-Taste", /* gsw */
+      "કન્ફર્મ કરવા માટે પાવર બટન દબાવો", /* gu */
+      "יש ללחוץ על לחצן ההפעלה כדי לאשר", /* he */
+      "पुष्टि करने के लिए पावर बटन दबाएं", /* hi */
+      "Pritisnite tipku za uključivanje/isključivanje da biste potvrdili", /* hr */
+      "Nyomja meg a bekapcsológombot a megerősítéshez", /* hu */
+      "Հաստատելու համար սեղմեք սնուցման կոճակը", /* hy */
+      "Tekan tombol power untuk mengonfirmasi", /* id */
+      "Tekan tombol power untuk mengonfirmasi", /* in */
+      "Ýttu á aflrofann til að staðfesta", /* is */
+      "Premi il tasto di accensione per confermare", /* it */
+      "יש ללחוץ על לחצן ההפעלה כדי לאשר", /* iw */
+      "確認するには、電源を押します", /* ja */
+      "დასადასტურებლად დააჭირეთ ჩართვის ღილაკს", /* ka */
+      "Растау үшін қуат түймесін басыңыз", /* kk */
+      "ចុច​ប៊ូតុង​ថាមពល​ដើម្បី​បញ្ជាក់", /* km */
+      "ದೃಢೀಕರಿಸಲು ಪವರ್ ಬಟನ್ ಒತ್ತಿರಿ", /* kn */
+      "확인하려면 전원 버튼을 누르세요.", /* ko */
+      "Ырастоо үчүн \"Кубат\" баскычын басыңыз", /* ky */
+      "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération", /* ln */
+      "ກົດປຸ່ມເປີດປິດເພື່ອຢືນຢັນ", /* lo */
+      "Paspauskite maitinimo mygtuką, kad patvirtintumėte", /* lt */
+      "Lai apstiprinātu, nospiediet barošanas pogu", /* lv */
+      "Притиснете на копчето за напојување за да потврдите", /* mk */
+      "സ്ഥിരീകരിക്കാൻ പവർ അമർത്തുക", /* ml */
+      "Баталгаажуулахын тулд унтраах/асаахыг дарах", /* mn */
+      "Apăsați butonul de pornire pentru a confirma", /* mo */
+      "निश्चित करण्‍यासाठी पॉवर दाबा", /* mr */
+      "Tekan kuasa untuk mengesahkan", /* ms */
+      "အတည်ပြုရန် ပါဝါခလုတ်နှိပ်ပါ", /* my */
+      "Trykk på av/på-knappen for å bekrefte", /* nb */
+      "पुष्टि गर्न पावर बटनमा थिच्नुहोस्", /* ne */
+      "Druk op de aan/uit-knop om te bevestigen", /* nl */
+      "Trykk på av/på-knappen for å bekrefte", /* no */
+      "ସୁନିଶ୍ଚିତ କରିବା ପାଇଁ ପାୱର୍‌ ବଟନ୍‌କୁ ଦାବନ୍ତୁ", /* or */
+      "ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਪਾਵਰ ਬਟਨ ਦਬਾਓ", /* pa */
+      "Naciśnij przycisk zasilania, aby potwierdzić", /* pl */
+      "Pressione o botão liga/desliga para confirmar", /* pt */
+      "Pressione o botão liga/desliga para confirmar", /* pt-BR */
+      "Prima ligar/desligar para confirmar.", /* pt-PT */
+      "Apăsați butonul de pornire pentru a confirma", /* ro */
+      "Для подтверждения нажмите кнопку питания.", /* ru */
+      "තහවුරු කිරීමට බල බොත්තම ඔබන්න", /* si */
+      "Potvrďte stlačením vypínača", /* sk */
+      "Za potrditev pritisnite gumb za vklop", /* sl */
+      "Shtyp butonin e energjisë për të konfirmuar", /* sq */
+      "Притисните дугме за напајање да бисте потврдили", /* sr */
+      "Pritisnite dugme za napajanje da biste potvrdili", /* sr-Latn */
+      "Bekräfta genom att trycka på strömbrytaren", /* sv */
+      "Bonyeza kitufe cha kuwasha ili uthibitishe", /* sw */
+      "உறுதிப்படுத்த, பவரை அழுத்தவும்", /* ta */
+      "నిర్ధారించడానికి పవర్‌ను నొక్కండి", /* te */
+      "กดปุ่มเปิด/ปิดเพื่อยืนยัน", /* th */
+      "Pindutin ang power para kumpirmahin", /* tl */
+      "Onaylamak için güç düğmesine basın", /* tr */
+      "Натисніть кнопку живлення, щоб підтвердити", /* uk */
+      "تصدیق کرنے کے لئے پاور بٹن دبائیں", /* ur */
+      "Tasdiqlash uchun quvvat tugmasini bosing", /* uz */
+      "Nhấn vào nút nguồn để xác nhận", /* vi */
+      "按电源按钮即可确认", /* zh */
+      "按电源按钮即可确认", /* zh-CN */
+      "按下電源按鈕即可確認", /* zh-HK */
+      "按下電源按鈕即可確認操作", /* zh-TW */
+      "Cindezela amandla ukuze uqinisekise", /* zu */
+    }
+  },
+  {
+    "2213954494039981979",
+    {
+      "Press any volume button to cancel", /* en (untranslated) */
+      "Druk enige volumeknoppie om te kanselleer", /* af */
+      "ለመሰረዝ ማናቸውንም የድምፅ አዝራር ይጫኑ", /* am */
+      "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.", /* ar */
+      "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.", /* ar-EG */
+      "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.", /* ar-JO */
+      "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.", /* ar-MA */
+      "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.", /* ar-SA */
+      "‏‮Press‬‏ ‏‮any‬‏ ‏‮volume‬‏ ‏‮button‬‏ ‏‮to‬‏ ‏‮cancel‬‏", /* ar-XB */
+      "বাতিল কৰিবলৈ যিকোনো ভলিউম বুটাম হেঁচক", /* as */
+      "Ləğv etmək üçün istənilən səs düyməsinə basın", /* az */
+      "Націсніце любую кнопку гучнасці, каб cкасаваць", /* be */
+      "Натиснете някой от бутоните за силата на звука, за да анулирате", /* bg */
+      "বাতিল করতে ভলিউমের যেকোনও বোতাম টিপুন", /* bn */
+      "Pritisnite bilo koje dugme za podešavanje jačine zvuka da otkažete", /* bs */
+      "Prem qualsevol botó de volum per cancel·lar", /* ca */
+      "Zrušte stisknutím tlačítka hlasitosti", /* cs */
+      "Tryk på en af lydstyrkeknapperne for at annullere", /* da */
+      "Zum Abbrechen eine beliebige Lautstärketaste drücken", /* de */
+      "Zum Abbrechen eine beliebige Lautstärketaste drücken", /* de-AT */
+      "Zum Abbrechen eine beliebige Lautstärketaste drücken", /* de-CH */
+      "Πατήστε οποιοδήποτε κουμπί έντασης ήχου για ακύρωση", /* el */
+      "Press any volume button to cancel", /* en-AU */
+      "Press any volume button to cancel", /* en-CA */
+      "Press any volume button to cancel", /* en-GB */
+      "Press any volume button to cancel", /* en-IE */
+      "Press any volume button to cancel", /* en-IN */
+      "Press any volume button to cancel", /* en-SG */
+      "[Þŕéšš åñý vöļûmé бûţţöñ ţö çåñçéļ one two three four five six seven]", /* en-XA */
+      "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎Press any volume button to cancel‎‏‎‎‏‎", /* en-XC */
+      "Press any volume button to cancel", /* en-ZA */
+      "Pulsa cualquier botón de volumen para cancelar", /* es */
+      "Presiona cualquier botón de volumen para cancelar", /* es-419 */
+      "Presiona cualquier botón de volumen para cancelar", /* es-AR */
+      "Presiona cualquier botón de volumen para cancelar", /* es-BO */
+      "Presiona cualquier botón de volumen para cancelar", /* es-CL */
+      "Presiona cualquier botón de volumen para cancelar", /* es-CO */
+      "Presiona cualquier botón de volumen para cancelar", /* es-CR */
+      "Presiona cualquier botón de volumen para cancelar", /* es-DO */
+      "Presiona cualquier botón de volumen para cancelar", /* es-EC */
+      "Presiona cualquier botón de volumen para cancelar", /* es-GT */
+      "Presiona cualquier botón de volumen para cancelar", /* es-HN */
+      "Presiona cualquier botón de volumen para cancelar", /* es-MX */
+      "Presiona cualquier botón de volumen para cancelar", /* es-NI */
+      "Presiona cualquier botón de volumen para cancelar", /* es-PA */
+      "Presiona cualquier botón de volumen para cancelar", /* es-PE */
+      "Presiona cualquier botón de volumen para cancelar", /* es-PR */
+      "Presiona cualquier botón de volumen para cancelar", /* es-PY */
+      "Presiona cualquier botón de volumen para cancelar", /* es-SV */
+      "Presiona cualquier botón de volumen para cancelar", /* es-US */
+      "Presiona cualquier botón de volumen para cancelar", /* es-UY */
+      "Presiona cualquier botón de volumen para cancelar", /* es-VE */
+      "Tühistamiseks vajutage mis tahes helitugevuse nuppu", /* et */
+      "Bertan behera uzteko, sakatu bolumen-tekla bat", /* eu */
+      "برای لغو، یکی از دکمه‌های میزان صدا را فشار دهید", /* fa */
+      "Peruuta painamalla äänenvoimakkuuspainiketta", /* fi */
+      "Pindutin ang anumang button ng volume para kanselahin", /* fil */
+      "Appuyez sur l'un des boutons de volume pour annuler l'opération", /* fr */
+      "Appuyez sur un bouton de volume pour annuler l'action", /* fr-CA */
+      "Appuyez sur l'un des boutons de volume pour annuler l'opération", /* fr-CH */
+      "Preme calquera botón de volume para cancelar", /* gl */
+      "Zum Abbrechen eine beliebige Lautstärketaste drücken", /* gsw */
+      "રદ કરવા માટે કોઈપણ વૉલ્યૂમનું બટન દબાવો", /* gu */
+      "יש ללחוץ על לחצן כלשהו של עוצמת הקול כדי לבטל", /* he */
+      "रद्द करने के लिए कोई भी वॉल्यूम बटन दबाएं", /* hi */
+      "Pritisnite bilo koju tipku za glasnoću da biste otkazali", /* hr */
+      "Nyomja meg valamelyik hangerőgombot az elvetéshez", /* hu */
+      "Չեղարկելու համար սեղմեք ձայնի կագավորման որևէ կոճակ", /* hy */
+      "Tekan tombol volume apa saja untuk membatalkan", /* id */
+      "Tekan tombol volume apa saja untuk membatalkan", /* in */
+      "Ýttu á hvaða hljóðstyrkshnapp sem er til að hætta við", /* is */
+      "Premi qualsiasi pulsante del volume per annullare", /* it */
+      "יש ללחוץ על לחצן כלשהו של עוצמת הקול כדי לבטל", /* iw */
+      "キャンセルするには、いずれかの音量ボタンを押します", /* ja */
+      "გასაუქმებლად დააჭირეთ ხმის რეგულირების ნებისმიერ ღილაკს", /* ka */
+      "Бас тарту үшін кез келген дыбыс деңгейі түймесін басыңыз", /* kk */
+      "ចុចប៊ូតុង​កម្រិតសំឡេង​ណាមួយ​ដើម្បីបោះបង់", /* km */
+      "ರದ್ದುಗೊಳಿಸಲು ಯಾವುದೇ ವಾಲ್ಯೂಮ್‌ ಬಟನ್ ಒತ್ತಿರಿ", /* kn */
+      "취소하려면 볼륨 버튼 중 하나를 누르세요.", /* ko */
+      "Жокко чыгаруу үчүн үн көлөмүнүн баскычтарынын бирин басыңыз", /* ky */
+      "Appuyez sur l'un des boutons de volume pour annuler l'opération", /* ln */
+      "ກົດປຸ່ມສຽງຂຶ້ນ ຫຼື ລົງເພື່ອຍົກເລີກ", /* lo */
+      "Paspauskite bet kurį garsumo mygtuką, kad atšauktumėte", /* lt */
+      "Lai atceltu, nospiediet jebkuru skaļuma pogu", /* lv */
+      "Притиснете на кое било копче за јачина на звук за да откажете", /* mk */
+      "റദ്ദാക്കാൻ എതെങ്കിലും വോളിയം ബട്ടൺ അമർത്തുക", /* ml */
+      "Болихын тулд дууны түвшний товчлуурын аль нэгийг нь дарах", /* mn */
+      "Apăsați orice buton de volum pentru a anula", /* mo */
+      "रद्द करण्‍यासाठी कोणतेही व्‍हॉल्‍यूम बटण दाबा", /* mr */
+      "Tekan sebarang butang kelantangan untuk membatalkan tindakan", /* ms */
+      "ပယ်ဖျက်ရန် အသံအတိုးအကျယ်ခလုတ် တစ်ခုခုကိုနှိပ်ပါ", /* my */
+      "Trykk på en volumknapp for å avbryte", /* nb */
+      "रद्द गर्नका लागि कुनै भोल्युम बटन थिच्नुहोस्", /* ne */
+      "Druk op een volumeknop om te annuleren", /* nl */
+      "Trykk på en volumknapp for å avbryte", /* no */
+      "କ୍ୟାନ୍ସଲ୍ କରିବା ପାଇଁ ଯେକୌଣସି ଭଲ୍ୟୁମ୍ ବଟନ୍‌କୁ ଦାବନ୍ତୁ", /* or */
+      "ਰੱਦ ਕਰਨ ਲਈ ਕਿਸੇ ਵੀ ਵੌਲਿਊਮ ਬਟਨ ਨੂੰ ਦਬਾਓ", /* pa */
+      "Naciśnij dowolny przycisk głośności, aby anulować", /* pl */
+      "Pressione um dos botões de volume para cancelar", /* pt */
+      "Pressione um dos botões de volume para cancelar", /* pt-BR */
+      "Prima qualquer botão de volume para cancelar.", /* pt-PT */
+      "Apăsați orice buton de volum pentru a anula", /* ro */
+      "Для отмены нажмите на любую кнопку регулировки громкости.", /* ru */
+      "අවලංගු කිරීමට ඕනෑම හඬ පරිමා බොත්තමක් ඔබන්න", /* si */
+      "Zrušte stlačením ľubovoľného tlačidla hlasitosti", /* sk */
+      "Za preklic pritisnite poljuben gumb za glasnost", /* sl */
+      "Shtyp çdo buton volumi për ta anuluar", /* sq */
+      "Притисните било које дугме за јачину звука да бисте отказали", /* sr */
+      "Pritisnite bilo koje dugme za jačinu zvuka da biste otkazali", /* sr-Latn */
+      "Avbryt genom att trycka på valfri volymknapp", /* sv */
+      "Bonyeza kitufe chochote cha sauti ili ughairi", /* sw */
+      "ரத்துசெய்ய, ஏதேனும் ஒலியளவு பட்டனை அழுத்தவும்", /* ta */
+      "రద్దు చేయడానికి ఏదైనా వాల్యూమ్ బటన్‌ను నొక్కండి", /* te */
+      "กดปุ่มปรับระดับเสียงเพื่อยกเลิก", /* th */
+      "Pindutin ang anumang button ng volume para kanselahin", /* tl */
+      "İptal etmek için herhangi bir ses düğmesine basın", /* tr */
+      "Натисніть будь-яку клавішу гучності, щоб скасувати", /* uk */
+      "منسوخ کرنے کے لئے کوئی بھی والیوم بٹن دبائیں", /* ur */
+      "Bekor qilish uchun istalgan tovush tugmasini bosing", /* uz */
+      "Nhấn vào nút âm lượng bất kỳ để hủy", /* vi */
+      "按任意音量按钮即可取消", /* zh */
+      "按任意音量按钮即可取消", /* zh-CN */
+      "按下任何音量按鈕即可取消", /* zh-HK */
+      "按下任一音量按鈕即可取消操作", /* zh-TW */
+      "Cindezela noma iyiphi inkinobho yevolumu ukuze ukhansele", /* zu */
+    }
+  },
+  {
+    "3999296476990449149",
+    {
+      "Cancel", /* en (untranslated) */
+      "Kanselleer", /* af */
+      "ይቅር", /* am */
+      "إلغاء", /* ar */
+      "إلغاء", /* ar-EG */
+      "إلغاء", /* ar-JO */
+      "إلغاء", /* ar-MA */
+      "إلغاء", /* ar-SA */
+      "‏‮Cancel‬‏", /* ar-XB */
+      "বাতিল কৰক", /* as */
+      "Ləğv edin", /* az */
+      "Скасаваць", /* be */
+      "Отказ", /* bg */
+      "বাতিল করুন", /* bn */
+      "Otkaži", /* bs */
+      "Cancel·la", /* ca */
+      "Zrušit", /* cs */
+      "Annuller", /* da */
+      "Abbrechen", /* de */
+      "Abbrechen", /* de-AT */
+      "Abbrechen", /* de-CH */
+      "Ακύρωση", /* el */
+      "Cancel", /* en-AU */
+      "Cancel", /* en-CA */
+      "Cancel", /* en-GB */
+      "Cancel", /* en-IE */
+      "Cancel", /* en-IN */
+      "Cancel", /* en-SG */
+      "[Çåñçéļ one]", /* en-XA */
+      "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎Cancel‎‏‎‎‏‎", /* en-XC */
+      "Cancel", /* en-ZA */
+      "Cancelar", /* es */
+      "Cancelar", /* es-419 */
+      "Cancelar", /* es-AR */
+      "Cancelar", /* es-BO */
+      "Cancelar", /* es-CL */
+      "Cancelar", /* es-CO */
+      "Cancelar", /* es-CR */
+      "Cancelar", /* es-DO */
+      "Cancelar", /* es-EC */
+      "Cancelar", /* es-GT */
+      "Cancelar", /* es-HN */
+      "Cancelar", /* es-MX */
+      "Cancelar", /* es-NI */
+      "Cancelar", /* es-PA */
+      "Cancelar", /* es-PE */
+      "Cancelar", /* es-PR */
+      "Cancelar", /* es-PY */
+      "Cancelar", /* es-SV */
+      "Cancelar", /* es-US */
+      "Cancelar", /* es-UY */
+      "Cancelar", /* es-VE */
+      "Tühista", /* et */
+      "Utzi", /* eu */
+      "لغو", /* fa */
+      "Peruuta", /* fi */
+      "Kanselahin", /* fil */
+      "Annuler", /* fr */
+      "Annuler", /* fr-CA */
+      "Annuler", /* fr-CH */
+      "Cancelar", /* gl */
+      "Abbrechen", /* gsw */
+      "રદ કરો", /* gu */
+      "ביטול", /* he */
+      "रद्द करें", /* hi */
+      "Otkaži", /* hr */
+      "Mégse", /* hu */
+      "Չեղարկել", /* hy */
+      "Batal", /* id */
+      "Batal", /* in */
+      "Hætta við", /* is */
+      "Annulla", /* it */
+      "ביטול", /* iw */
+      "キャンセル", /* ja */
+      "გაუქმება", /* ka */
+      "Бас тарту", /* kk */
+      "បោះបង់", /* km */
+      "ರದ್ದು", /* kn */
+      "취소", /* ko */
+      "Жокко чыгаруу", /* ky */
+      "Annuler", /* ln */
+      "ຍົກເລີກ", /* lo */
+      "Atšaukti", /* lt */
+      "Atcelt", /* lv */
+      "Откажи", /* mk */
+      "റദ്ദാക്കുക", /* ml */
+      "Болих", /* mn */
+      "Anulați", /* mo */
+      "रद्द करा", /* mr */
+      "Batal", /* ms */
+      "မလုပ်တော့", /* my */
+      "Avbryt", /* nb */
+      "रद्द गर्नुहोस्", /* ne */
+      "Annuleren", /* nl */
+      "Avbryt", /* no */
+      "କ୍ୟାନ୍ସଲ୍‍ କରନ୍ତୁ", /* or */
+      "ਰੱਦ ਕਰੋ", /* pa */
+      "Anuluj", /* pl */
+      "Cancelar", /* pt */
+      "Cancelar", /* pt-BR */
+      "Cancelar", /* pt-PT */
+      "Anulați", /* ro */
+      "Отмена", /* ru */
+      "අවලංගු කරන්න", /* si */
+      "Zrušiť", /* sk */
+      "Prekliči", /* sl */
+      "Anulo", /* sq */
+      "Откажи", /* sr */
+      "Otkaži", /* sr-Latn */
+      "Avbryt", /* sv */
+      "Ghairi", /* sw */
+      "ரத்துசெய்", /* ta */
+      "రద్దు చేయండి", /* te */
+      "ยกเลิก", /* th */
+      "Kanselahin", /* tl */
+      "İptal", /* tr */
+      "Скасувати", /* uk */
+      "منسوخ کریں", /* ur */
+      "Bekor qilish", /* uz */
+      "Hủy", /* vi */
+      "取消", /* zh */
+      "取消", /* zh-CN */
+      "取消", /* zh-HK */
+      "取消", /* zh-TW */
+      "Khansela", /* zu */
+    }
+  },
+  {
+    "6973195374358399966",
+    {
+      "Android Protected Confirmation", /* en (untranslated) */
+      "Android se Beskermde Bevestiging", /* af */
+      "በAndroid ጥበቃ የሚደረግለት ማረጋገጫ", /* am */
+      "تأكيد حماية Android", /* ar */
+      "تأكيد حماية Android", /* ar-EG */
+      "تأكيد حماية Android", /* ar-JO */
+      "تأكيد حماية Android", /* ar-MA */
+      "تأكيد حماية Android", /* ar-SA */
+      "‏‮Android‬‏ ‏‮Protected‬‏ ‏‮Confirmation‬‏", /* ar-XB */
+      "Androidৰ সুৰক্ষা সম্পৰ্কীয় প্ৰতিশ্ৰুতি", /* as */
+      "Qorunan Android Təsdiqi", /* az */
+      "Пацвярджэнне Android Protected", /* be */
+      "Защитно потвърждение за Android", /* bg */
+      "Android প্রোটেক্টেড কনফার্মেশন", /* bn */
+      "Potvrda zaštite na Androidu", /* bs */
+      "Confirmació de protecció d'Android", /* ca */
+      "Potvrzení ochrany Androidu", /* cs */
+      "Beskyttet bekræftelse i Android", /* da */
+      "Bestätigung für Android Protected", /* de */
+      "Bestätigung für Android Protected", /* de-AT */
+      "Bestätigung für Android Protected", /* de-CH */
+      "Επιβεβαίωση προστασίας Android", /* el */
+      "Android Protected Confirmation", /* en-AU */
+      "Android Protected Confirmation", /* en-CA */
+      "Android Protected Confirmation", /* en-GB */
+      "Android Protected Confirmation", /* en-IE */
+      "Android Protected Confirmation", /* en-IN */
+      "Android Protected Confirmation", /* en-SG */
+      "[Åñðŕöîð Þŕöţéçţéð Çöñƒîŕmåţîöñ one two three four]", /* en-XA */
+      "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎Android Protected Confirmation‎‏‎‎‏‎", /* en-XC */
+      "Android Protected Confirmation", /* en-ZA */
+      "Confirmación protegida por Android", /* es */
+      "Confirmación de protección de Android", /* es-419 */
+      "Confirmación de protección de Android", /* es-AR */
+      "Confirmación de protección de Android", /* es-BO */
+      "Confirmación de protección de Android", /* es-CL */
+      "Confirmación de protección de Android", /* es-CO */
+      "Confirmación de protección de Android", /* es-CR */
+      "Confirmación de protección de Android", /* es-DO */
+      "Confirmación de protección de Android", /* es-EC */
+      "Confirmación de protección de Android", /* es-GT */
+      "Confirmación de protección de Android", /* es-HN */
+      "Confirmación de protección de Android", /* es-MX */
+      "Confirmación de protección de Android", /* es-NI */
+      "Confirmación de protección de Android", /* es-PA */
+      "Confirmación de protección de Android", /* es-PE */
+      "Confirmación de protección de Android", /* es-PR */
+      "Confirmación de protección de Android", /* es-PY */
+      "Confirmación de protección de Android", /* es-SV */
+      "Confirmación de protección de Android", /* es-US */
+      "Confirmación de protección de Android", /* es-UY */
+      "Confirmación de protección de Android", /* es-VE */
+      "Androidi kaitstud kinnitus", /* et */
+      "Android-en babesa izatearen berrespena", /* eu */
+      "تأیید محافظت‌شده Android", /* fa */
+      "Vahvistus Android-suojauksesta", /* fi */
+      "Pagkumpirmang Pinoprotektahan ng Android", /* fil */
+      "Confirmation de protection Android", /* fr */
+      "Confirmation protégée Android", /* fr-CA */
+      "Confirmation de protection Android", /* fr-CH */
+      "Android Protected Confirmation", /* gl */
+      "Bestätigung für Android Protected", /* gsw */
+      "Android પ્રોટેક્ટેડ કન્ફર્મેશન", /* gu */
+      "Android Protected Confirmation", /* he */
+      "Android की ओर से सुरक्षा की पुष्टि", /* hi */
+      "Potvrda zaštite na Androidu", /* hr */
+      "Android – védett megerősítés", /* hu */
+      "Android Protected-ի հաստատում", /* hy */
+      "Konfirmasi yang Dilindungi Android", /* id */
+      "Konfirmasi yang Dilindungi Android", /* in */
+      "Varin staðfesting Android", /* is */
+      "Conferma Android Protected", /* it */
+      "Android Protected Confirmation", /* iw */
+      "Android Protected の確認", /* ja */
+      "Android-ის დაცული დადასტურება", /* ka */
+      "Android қорғалған растау", /* kk */
+      "ការ​បញ្ជាក់​ដែលបាន​ការពារ Android", /* km */
+      "Android ಸಂರಕ್ಷಿತ ದೃಢೀಕರಣ", /* kn */
+      "Android 보안 확인", /* ko */
+      "Android Protected ырастоосу", /* ky */
+      "Confirmation de protection Android", /* ln */
+      "ການຢືນຢັນ Android ທີ່ໄດ້ຮັບການປົກປ້ອງ", /* lo */
+      "„Android Protected“ patvirtinimas", /* lt */
+      "Android aizsargātā informācija", /* lv */
+      "Потврда за заштита на Android", /* mk */
+      "Android സംരക്ഷിത സ്ഥിരീകരണം", /* ml */
+      "Андройдоор хамгаалсан баталгаажуулалт", /* mn */
+      "Confirmare protecție pentru Android", /* mo */
+      "Android कडून सुरक्षा निश्चित करणे", /* mr */
+      "Pengesahan Dilindungi Android", /* ms */
+      "Android ကာကွယ်မှု အတည်ပြုချက်", /* my */
+      "Android-beskyttet bekreftelse", /* nb */
+      "Android द्वारा संरक्षण गरिएको पुष्टि", /* ne */
+      "Bevestiging van Android-beveiliging", /* nl */
+      "Android-beskyttet bekreftelse", /* no */
+      "Android ଦ୍ୱାରା ସୁରକ୍ଷିତ ହୋଇଥିବାର ସୁନିଶ୍ଚିତତା", /* or */
+      "Android ਵੱਲੋਂ ਸੁਰੱਖਿਆ ਦੀ ਪੁਸ਼ਟੀ", /* pa */
+      "Zabezpieczone potwierdzenie w Androidzie", /* pl */
+      "Confirmação protegida pelo Android", /* pt */
+      "Confirmação protegida pelo Android", /* pt-BR */
+      "Confirmação protegida do Android", /* pt-PT */
+      "Confirmare protecție pentru Android", /* ro */
+      "Подтверждение Android Protected", /* ru */
+      "Android ආරක්ෂිත තහවුරු කිරීම", /* si */
+      "Chránené potvrdenie Androidu", /* sk */
+      "Zaščitena potrditev v Androidu", /* sl */
+      "Android Protected Confirmation", /* sq */
+      "Потврда заштите на Android-у", /* sr */
+      "Potvrda zaštite na Android-u", /* sr-Latn */
+      "Bekräftelseskydd för Android", /* sv */
+      "Uthibitishaji Unaolindwa wa Android", /* sw */
+      "Android பாதுகாப்பு தொடர்பான உறுதிப்படுத்தல்", /* ta */
+      "Android సురక్షిత నిర్ధారణ", /* te */
+      "ยืนยันการป้องกัน Android", /* th */
+      "Pagkumpirmang Pinoprotektahan ng Android", /* tl */
+      "Android Korumalı Onayı", /* tr */
+      "Підтвердження Android Protected", /* uk */
+      "Android کی تحفظ یافتہ تصدیق", /* ur */
+      "Android Protected nomli tasdiq", /* uz */
+      "Xác nhận bảo vệ Android", /* vi */
+      "Android 保护确认", /* zh */
+      "Android 保护确认", /* zh-CN */
+      "Android 保護確認", /* zh-HK */
+      "Android Protected 確認", /* zh-TW */
+      "Ukuqinisekiswa okuvikelwe i-Android", /* zu */
+    }
+  },
+};
+
+#define ConfirmationUITranslations_NUM_TRANSLATION_IDS \
+    (ARRAY_ELEMENTS(ConfirmationUITranslations_translation_ids))
+
+static int ConfirmationUITranslations_selected_lang_id_index = 0;
+
+static int ConfirmationUITranslations_find_str(const char** haystack, const char* needle) {
+    for (int n = 0; haystack[n] != NULL; n++) {
+        if (strcmp(needle, haystack[n]) == 0) {
+            return n;
+        }
+    }
+    return -1;
+}
+
+#define MAX_LANG_ID_SIZE 256
+
+/* Non-static linkage to allow calling by the test. */
+int ConfirmationUITranslations_lang_id_match(const char** lang_ids, const char* lang_id) {
+    int ret;
+    char lang_id_buf[MAX_LANG_ID_SIZE + 1];
+    size_t n;
+
+    ret = ConfirmationUITranslations_find_str(lang_ids, lang_id);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    /* strncpy.. */
+    for (n = 0; lang_id[n] != '\0' && n < MAX_LANG_ID_SIZE; n++) {
+        lang_id_buf[n] = lang_id[n];
+    }
+    lang_id_buf[n] = '\0';
+
+    while (n >= 1) {
+        /* Remove last component */
+        while (n >= 1 && lang_id_buf[n - 1] != '-') {
+            n--;
+        }
+        if (n < 1) {
+            return -1;
+        }
+        lang_id_buf[n - 1] = '\0';
+        n--;
+        ret = ConfirmationUITranslations_find_str(lang_ids, lang_id_buf);
+        if (ret >= 0) {
+            return ret;
+        }
+    }
+    return -1;
+}
+
+const char* ConfirmationUITranslations_select_lang_id(const char* lang_id) {
+    ConfirmationUITranslations_selected_lang_id_index = 0;
+    if (lang_id == NULL) {
+        return ConfirmationUITranslations_language_ids[0];
+    }
+
+    int ret = ConfirmationUITranslations_lang_id_match(ConfirmationUITranslations_language_ids, lang_id);
+    if (ret < 0) {
+        return ConfirmationUITranslations_language_ids[0];
+    }
+    ConfirmationUITranslations_selected_lang_id_index = ret;
+    return ConfirmationUITranslations_language_ids[ConfirmationUITranslations_selected_lang_id_index];
+}
+
+const char* ConfirmationUITranslations_lookup(const char* translation_id) {
+    for (size_t n = 0; n < ConfirmationUITranslations_NUM_TRANSLATION_IDS; n++) {
+        if (strcmp(translation_id, ConfirmationUITranslations_translation_ids[n].translation_id) == 0) {
+            const char* result;
+            if (ConfirmationUITranslations_selected_lang_id_index < 0 || ConfirmationUITranslations_selected_lang_id_index >= ConfirmationUITranslations_NUM_LANGUAGE_IDS) {
+                return ConfirmationUITranslations_translation_ids[n].translations[0];
+            }
+            result = ConfirmationUITranslations_translation_ids[n].translations[ConfirmationUITranslations_selected_lang_id_index];
+            if (result != NULL) {
+                return result;
+            }
+            return ConfirmationUITranslations_translation_ids[n].translations[0];
+        }
+    }
+    return NULL;
+}
+
+const char* const* ConfirmationUITranslations_get_languages(void) {
+    return (const char* const*) (ConfirmationUITranslations_language_ids);
+}
diff --git a/confirmationui/support/test/ConfirmationUITranslations-test.c b/confirmationui/support/test/ConfirmationUITranslations-test.c
new file mode 100644
index 0000000..a73a8af
--- /dev/null
+++ b/confirmationui/support/test/ConfirmationUITranslations-test.c
@@ -0,0 +1,1338 @@
+/*
+**
+** Copyright 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.
+*/
+
+/* Generated by generate-translations.py - DO NOT EDIT */
+
+#include "ConfirmationUITranslations.h"
+#include "string.h"
+
+#include <stdio.h>
+
+#define ASSERT_STR(str1, str2) \
+    do { \
+        if (strcmp(str1, str2) != 0) { \
+            printf("%s:%d: Assertion failed: '%s' != '%s'\n", \
+                    __FILE__, __LINE__, str1, str2); \
+            return 1; \
+        } \
+    } while (0)
+
+extern int ConfirmationUITranslations_lang_id_match(const char** lang_ids,
+                                                    const char* lang_id);
+
+static const char* test_lang_id_match(const char* lang_ids[], const char* lang_id) {
+    int ret = ConfirmationUITranslations_lang_id_match(lang_ids, lang_id);
+    if (ret < 0) {
+        return "";
+    }
+    return lang_ids[ret];
+}
+
+int main(int argc, char* argv[]) {
+    /* Tests for untranslated languages */
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action you're about to take.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for languages without translation */
+    ConfirmationUITranslations_select_lang_id("nosuch-LA");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action you're about to take.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for untranslated language (en) */
+    ConfirmationUITranslations_select_lang_id("en");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action you're about to take.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language af */
+    ConfirmationUITranslations_select_lang_id("af");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dubbeldruk aan/af-skakelaar om te bevestig");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Kanselleer");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Hierdie bevestiging verskaf 'n ekstra laag sekuriteit vir die handeling wat jy op die punt is om uit te voer.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Druk aan/af-skakelaar om te bevestig");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Druk enige volumeknoppie om te kanselleer");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Kanselleer");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android se Beskermde Bevestiging");
+
+    /* Tests for language am */
+    ConfirmationUITranslations_select_lang_id("am");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ለማረጋገጥ ኃይልን ሁለቴ ይጫኑ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ይቅር");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ይህ ማረጋገጫ እርስዎ ለሚወስዱት እርምጃ ተጨማሪ ትርፍ ጥበቃን ይሰጣል።");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ለማረጋገጥ ኃይልን ይጫኑ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ለመሰረዝ ማናቸውንም የድምፅ አዝራር ይጫኑ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ይቅር");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "በAndroid ጥበቃ የሚደረግለት ማረጋገጫ");
+
+    /* Tests for language ar */
+    ConfirmationUITranslations_select_lang_id("ar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "اضغط على زر التشغيل مرتين لتأكيد الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "إلغاء");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "اضغط على زر التشغيل لتأكيد الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "إلغاء");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأكيد حماية Android");
+
+    /* Tests for language ar-EG */
+    ConfirmationUITranslations_select_lang_id("ar-EG");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "اضغط على زر التشغيل مرتين لتأكيد الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "إلغاء");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "اضغط على زر التشغيل لتأكيد الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "إلغاء");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأكيد حماية Android");
+
+    /* Tests for language ar-JO */
+    ConfirmationUITranslations_select_lang_id("ar-JO");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "اضغط على زر التشغيل مرتين لتأكيد الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "إلغاء");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "اضغط على زر التشغيل لتأكيد الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "إلغاء");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأكيد حماية Android");
+
+    /* Tests for language ar-MA */
+    ConfirmationUITranslations_select_lang_id("ar-MA");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "اضغط على زر التشغيل مرتين لتأكيد الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "إلغاء");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "اضغط على زر التشغيل لتأكيد الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "إلغاء");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأكيد حماية Android");
+
+    /* Tests for language ar-SA */
+    ConfirmationUITranslations_select_lang_id("ar-SA");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "اضغط على زر التشغيل مرتين لتأكيد الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "إلغاء");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "اضغط على زر التشغيل لتأكيد الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "إلغاء");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأكيد حماية Android");
+
+    /* Tests for language ar-XB */
+    ConfirmationUITranslations_select_lang_id("ar-XB");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "‏‮Double‬‏-‏‮press‬‏ ‏‮power‬‏ ‏‮to‬‏ ‏‮confirm‬‏");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "‏‮Cancel‬‏");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "‏‮This‬‏ ‏‮confirmation‬‏ ‏‮provides‬‏ ‏‮an‬‏ ‏‮extra‬‏ ‏‮layer‬‏ ‏‮of‬‏ ‏‮security‬‏ ‏‮for‬‏ ‏‮the‬‏ ‏‮action‬‏ ‏‮you‬‏'‏‮re‬‏ ‏‮about‬‏ ‏‮to‬‏ ‏‮take‬‏.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "‏‮Press‬‏ ‏‮power‬‏ ‏‮to‬‏ ‏‮confirm‬‏");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "‏‮Press‬‏ ‏‮any‬‏ ‏‮volume‬‏ ‏‮button‬‏ ‏‮to‬‏ ‏‮cancel‬‏");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "‏‮Cancel‬‏");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "‏‮Android‬‏ ‏‮Protected‬‏ ‏‮Confirmation‬‏");
+
+    /* Tests for language as */
+    ConfirmationUITranslations_select_lang_id("as");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "নিশ্চিত কৰিবলৈ পাৱাৰ বুটামটো দুবাৰ হেঁচক");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "বাতিল কৰক");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "এই প্ৰতিশ্ৰুতিয়ে আপুনি কৰিব বিচৰা কোনো কাৰ্যৰ বাবে অতিৰিক্ত সুৰক্ষা প্ৰদান কৰে।");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "নিশ্চিত কৰিবলৈ পাৱাৰ বুটাম হেঁচক");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "বাতিল কৰিবলৈ যিকোনো ভলিউম বুটাম হেঁচক");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "বাতিল কৰক");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Androidৰ সুৰক্ষা সম্পৰ্কীয় প্ৰতিশ্ৰুতি");
+
+    /* Tests for language az */
+    ConfirmationUITranslations_select_lang_id("az");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Təsdiqləmək üçün iki dəfə yandırıb-söndürmək düyməsinə basın");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Ləğv edin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Bu təsdiq etmək üzrə olduğunuz əməliyyat üçün əlavə təhlükəsizlik qatı təmin edir.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Təsdiq etmək üçün yandırıb-söndürmə düyməsinə basın");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Ləğv etmək üçün istənilən səs düyməsinə basın");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Ləğv edin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Qorunan Android Təsdiqi");
+
+    /* Tests for language be */
+    ConfirmationUITranslations_select_lang_id("be");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Двойчы націсніце кнопку сілкавання, каб пацвердзіць");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Скасаваць");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Гэта пацвярджэнне забяспечвае дадатковы ўзровень бяспекі для дзеянняў, якія вы збіраецеся выконваць.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Націсніце кнопку сілкавання, каб пацвердзіць");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Націсніце любую кнопку гучнасці, каб cкасаваць");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Скасаваць");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Пацвярджэнне Android Protected");
+
+    /* Tests for language bg */
+    ConfirmationUITranslations_select_lang_id("bg");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Натиснете два пъти бутона за захранване, за да потвърдите");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Отказ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Това потвърждение осигурява допълнителна защита за действието, което сте напът да предприемете.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Натиснете бутона за захранване, за да потвърдите");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Натиснете някой от бутоните за силата на звука, за да анулирате");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Отказ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Защитно потвърждение за Android");
+
+    /* Tests for language bn */
+    ConfirmationUITranslations_select_lang_id("bn");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "নিশ্চিত করতে পাওয়ার বোতাম দুবার টিপুন");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "বাতিল করুন");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "আপনি যে কাজটি করতে চলেছেন, এই কনফার্মেশনের ফলে সেটির জন্য অতিরিক্ত সুরক্ষার ব্যবস্থা করা হয়।");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "নিশ্চিত করতে পাওয়ার বোতাম টিপুন");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "বাতিল করতে ভলিউমের যেকোনও বোতাম টিপুন");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "বাতিল করুন");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android প্রোটেক্টেড কনফার্মেশন");
+
+    /* Tests for language bs */
+    ConfirmationUITranslations_select_lang_id("bs");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dva puta pritisnite dugme za napajanje da potvrdite");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Otkaži");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ova potvrda pruža dodatni sloj zaštite za radnju koju namjeravate preduzeti.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pritisnite dugme za napajanje za potvrdu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pritisnite bilo koje dugme za podešavanje jačine zvuka da otkažete");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Otkaži");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Potvrda zaštite na Androidu");
+
+    /* Tests for language ca */
+    ConfirmationUITranslations_select_lang_id("ca");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Prem dos cops el botó d'engegada per confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel·la");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Aquesta confirmació proporciona una capa de seguretat addicional per a l'acció que estàs a punt de dur a terme.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Prem el botó d'engegada per confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Prem qualsevol botó de volum per cancel·lar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel·la");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmació de protecció d'Android");
+
+    /* Tests for language cs */
+    ConfirmationUITranslations_select_lang_id("cs");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Potvrďte dvojitým stisknutím vypínače");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Zrušit");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Toto potvrzení tvoří dodatečnou úroveň zabezpečení akce, kterou se chystáte podniknout.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Potvrďte stisknutím vypínače");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zrušte stisknutím tlačítka hlasitosti");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Zrušit");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Potvrzení ochrany Androidu");
+
+    /* Tests for language da */
+    ConfirmationUITranslations_select_lang_id("da");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Tryk to gange på afbryderknappen for at bekræfte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuller");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Denne bekræftelse giver et ekstra beskyttelsesniveau for den handling, du er ved at foretage.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Tryk på afbryderknappen for at bekræfte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Tryk på en af lydstyrkeknapperne for at annullere");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuller");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Beskyttet bekræftelse i Android");
+
+    /* Tests for language de */
+    ConfirmationUITranslations_select_lang_id("de");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Abbrechen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Drücke zum Bestätigen die Ein-/Aus-Taste");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zum Abbrechen eine beliebige Lautstärketaste drücken");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Abbrechen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bestätigung für Android Protected");
+
+    /* Tests for language de-AT */
+    ConfirmationUITranslations_select_lang_id("de-AT");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Abbrechen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Drücke zum Bestätigen die Ein-/Aus-Taste");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zum Abbrechen eine beliebige Lautstärketaste drücken");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Abbrechen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bestätigung für Android Protected");
+
+    /* Tests for language de-CH */
+    ConfirmationUITranslations_select_lang_id("de-CH");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Abbrechen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmassnahme angewandt.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Drücke zum Bestätigen die Ein-/Aus-Taste");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zum Abbrechen eine beliebige Lautstärketaste drücken");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Abbrechen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bestätigung für Android Protected");
+
+    /* Tests for language el */
+    ConfirmationUITranslations_select_lang_id("el");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Πατήστε δύο φορές το κουμπί λειτουργίας για επιβεβαίωση");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Ακύρωση");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Αυτή η επιβεβαίωση παρέχει ένα επιπλέον επίπεδο ασφάλειας για την ενέργεια που πρόκειται να εκτελέσετε.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Πατήστε το κουμπί λειτουργίας για επιβεβαίωση");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Πατήστε οποιοδήποτε κουμπί έντασης ήχου για ακύρωση");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Ακύρωση");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Επιβεβαίωση προστασίας Android");
+
+    /* Tests for language en-AU */
+    ConfirmationUITranslations_select_lang_id("en-AU");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language en-CA */
+    ConfirmationUITranslations_select_lang_id("en-CA");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language en-GB */
+    ConfirmationUITranslations_select_lang_id("en-GB");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language en-IE */
+    ConfirmationUITranslations_select_lang_id("en-IE");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language en-IN */
+    ConfirmationUITranslations_select_lang_id("en-IN");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language en-SG */
+    ConfirmationUITranslations_select_lang_id("en-SG");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language en-XA */
+    ConfirmationUITranslations_select_lang_id("en-XA");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "[Ðöûбļé-þŕéšš þöŵéŕ ţö çöñƒîŕm one two three four five six seven]");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "[Çåñçéļ one]");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "[Ţĥîš çöñƒîŕmåţîöñ þŕövîðéš åñ éxţŕå ļåýéŕ öƒ šéçûŕîţý ƒöŕ ţĥé åçţîöñ ýöû'ŕé åбöûţ ţö ţåķé. one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen]");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "[Þŕéšš þöŵéŕ ţö çöñƒîŕm one two three four five]");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "[Þŕéšš åñý vöļûmé бûţţöñ ţö çåñçéļ one two three four five six seven]");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "[Çåñçéļ one]");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "[Åñðŕöîð Þŕöţéçţéð Çöñƒîŕmåţîöñ one two three four]");
+
+    /* Tests for language en-XC */
+    ConfirmationUITranslations_select_lang_id("en-XC");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‎‏‎‏‏‎Double-press power to confirm‎‏‎‎‏‎");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‎‎‏‎‎‎‎‏‏‎‎‎‏‏‏‎Cancel‎‏‎‎‏‎");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎This confirmation provides an extra layer of security for the action you're about to take.‎‏‎‎‏‎");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‎Press power to confirm‎‏‎‎‏‎");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎Press any volume button to cancel‎‏‎‎‏‎");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎Cancel‎‏‎‎‏‎");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎Android Protected Confirmation‎‏‎‎‏‎");
+
+    /* Tests for language en-ZA */
+    ConfirmationUITranslations_select_lang_id("en-ZA");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language es */
+    ConfirmationUITranslations_select_lang_id("es");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Pulsa dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona una capa de seguridad adicional a la acción que vas a realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pulsa el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pulsa cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación protegida por Android");
+
+    /* Tests for language es-419 */
+    ConfirmationUITranslations_select_lang_id("es-419");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-AR */
+    ConfirmationUITranslations_select_lang_id("es-AR");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-BO */
+    ConfirmationUITranslations_select_lang_id("es-BO");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-CL */
+    ConfirmationUITranslations_select_lang_id("es-CL");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-CO */
+    ConfirmationUITranslations_select_lang_id("es-CO");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-CR */
+    ConfirmationUITranslations_select_lang_id("es-CR");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-DO */
+    ConfirmationUITranslations_select_lang_id("es-DO");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-EC */
+    ConfirmationUITranslations_select_lang_id("es-EC");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-GT */
+    ConfirmationUITranslations_select_lang_id("es-GT");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-HN */
+    ConfirmationUITranslations_select_lang_id("es-HN");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-MX */
+    ConfirmationUITranslations_select_lang_id("es-MX");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-NI */
+    ConfirmationUITranslations_select_lang_id("es-NI");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-PA */
+    ConfirmationUITranslations_select_lang_id("es-PA");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-PE */
+    ConfirmationUITranslations_select_lang_id("es-PE");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-PR */
+    ConfirmationUITranslations_select_lang_id("es-PR");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-PY */
+    ConfirmationUITranslations_select_lang_id("es-PY");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-SV */
+    ConfirmationUITranslations_select_lang_id("es-SV");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-US */
+    ConfirmationUITranslations_select_lang_id("es-US");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-UY */
+    ConfirmationUITranslations_select_lang_id("es-UY");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language es-VE */
+    ConfirmationUITranslations_select_lang_id("es-VE");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+    /* Tests for language et */
+    ConfirmationUITranslations_select_lang_id("et");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Kinnitamiseks topeltvajutage toitenuppu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Tühista");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "See kinnitus annab veel ühe turvakihi toimingu puhul, mille nüüd teete.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Kinnitamiseks vajutage toitenuppu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Tühistamiseks vajutage mis tahes helitugevuse nuppu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Tühista");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Androidi kaitstud kinnitus");
+
+    /* Tests for language eu */
+    ConfirmationUITranslations_select_lang_id("eu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Berresteko, sakatu birritan pizteko botoia");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Utzi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Berrespen honek segurtasun handiagoa ematen dizu hurrengo ekintza gauzatzeko.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Berresteko, sakatu etengailua");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Bertan behera uzteko, sakatu bolumen-tekla bat");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Utzi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android-en babesa izatearen berrespena");
+
+    /* Tests for language fa */
+    ConfirmationUITranslations_select_lang_id("fa");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "برای تأیید، دکمه روشن/خاموش را دوبار فشار دهید");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "لغو");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "این تأیید یک لایه امنیتی اضافی برای کنشی که می‌خواهید انجام دهید فراهم می‌کند.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "برای تأیید، دکمه روشن/خاموش را فشار دهید");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "برای لغو، یکی از دکمه‌های میزان صدا را فشار دهید");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "لغو");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأیید محافظت‌شده Android");
+
+    /* Tests for language fi */
+    ConfirmationUITranslations_select_lang_id("fi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Vahvista painamalla virtapainiketta kahdesti");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Peruuta");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Tämä vahvistus tarkoittaa, että seuraava toimintosi on entistä paremmin suojattu.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Vahvista painamalla virtapainiketta");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Peruuta painamalla äänenvoimakkuuspainiketta");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Peruuta");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Vahvistus Android-suojauksesta");
+
+    /* Tests for language fil */
+    ConfirmationUITranslations_select_lang_id("fil");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Pindutin nang dalawang beses ang power para kumpirmahin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Kanselahin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ang pagkumpirmang ito ay nagbibigay ng karagdagang layer ng seguridad para sa pagkilos na gagawin mo.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pindutin ang power para kumpirmahin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pindutin ang anumang button ng volume para kanselahin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Kanselahin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Pagkumpirmang Pinoprotektahan ng Android");
+
+    /* Tests for language fr */
+    ConfirmationUITranslations_select_lang_id("fr");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuler");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Appuyez sur l'un des boutons de volume pour annuler l'opération");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuler");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmation de protection Android");
+
+    /* Tests for language fr-CA */
+    ConfirmationUITranslations_select_lang_id("fr-CA");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Appuyez deux fois sur l'interrupteur pour confirmer");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuler");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Cette confirmation fournit une couche supplémentaire de sécurité pour l'action que vous êtes sur le point d'effectuer.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Appuyez sur l'interrupteur pour confirmer");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Appuyez sur un bouton de volume pour annuler l'action");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuler");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmation protégée Android");
+
+    /* Tests for language fr-CH */
+    ConfirmationUITranslations_select_lang_id("fr-CH");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuler");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Appuyez sur l'un des boutons de volume pour annuler l'opération");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuler");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmation de protection Android");
+
+    /* Tests for language gl */
+    ConfirmationUITranslations_select_lang_id("gl");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Preme o botón de acendido dúas veces para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona unha capa adicional de seguranza para a acción que estás a piques de levar a cabo.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Preme o botón de acendido para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Preme calquera botón de volume para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language gsw */
+    ConfirmationUITranslations_select_lang_id("gsw");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Abbrechen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Drücke zum Bestätigen die Ein-/Aus-Taste");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zum Abbrechen eine beliebige Lautstärketaste drücken");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Abbrechen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bestätigung für Android Protected");
+
+    /* Tests for language gu */
+    ConfirmationUITranslations_select_lang_id("gu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "કન્ફર્મ કરવા માટે પાવર પર બે વાર ટૅપ કરો");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "રદ કરો");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "તમે જે ક્રિયા કરવાના છો તેના માટે આ કન્ફર્મેશન એક અતિરિક્ત સુરક્ષાનું સ્તર પ્રદાન કરે છે.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "કન્ફર્મ કરવા માટે પાવર બટન દબાવો");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "રદ કરવા માટે કોઈપણ વૉલ્યૂમનું બટન દબાવો");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "રદ કરો");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android પ્રોટેક્ટેડ કન્ફર્મેશન");
+
+    /* Tests for language he */
+    ConfirmationUITranslations_select_lang_id("he");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "יש ללחוץ פעמיים על לחצן ההפעלה כדי לאשר");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ביטול");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "אישור זה מספק שכבת אבטחה נוספת לפעולה שאתה עומד לבצע.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "יש ללחוץ על לחצן ההפעלה כדי לאשר");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "יש ללחוץ על לחצן כלשהו של עוצמת הקול כדי לבטל");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ביטול");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language hi */
+    ConfirmationUITranslations_select_lang_id("hi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "पुष्टि करने के लिए पावर बटन दो बार दबाएं");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "रद्द करें");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "यह पुष्टि मिलने पर आप जो काम करने वाले हैं, उसके लिए सुरक्षा और बढ़ जाती है.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "पुष्टि करने के लिए पावर बटन दबाएं");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "रद्द करने के लिए कोई भी वॉल्यूम बटन दबाएं");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "रद्द करें");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android की ओर से सुरक्षा की पुष्टि");
+
+    /* Tests for language hr */
+    ConfirmationUITranslations_select_lang_id("hr");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dvaput pritisnite tipku za uključivanje/isključivanje da biste potvrdili");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Otkaži");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ta potvrda pruža dodatan sloj zaštite za radnju koju ćete izvršiti.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pritisnite tipku za uključivanje/isključivanje da biste potvrdili");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pritisnite bilo koju tipku za glasnoću da biste otkazali");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Otkaži");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Potvrda zaštite na Androidu");
+
+    /* Tests for language hu */
+    ConfirmationUITranslations_select_lang_id("hu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "A megerősítéshez nyomja meg duplán a bekapcsológombot");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Mégse");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ez a megerősítés extra réteg biztonságot nyújt a végrehajtani kívánt művelet számára.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Nyomja meg a bekapcsológombot a megerősítéshez");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Nyomja meg valamelyik hangerőgombot az elvetéshez");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Mégse");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android – védett megerősítés");
+
+    /* Tests for language hy */
+    ConfirmationUITranslations_select_lang_id("hy");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Հաստատելու համար կրկնակի սեղմեք սնուցման կոճակը");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Չեղարկել");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Այս հաստատումն ապահովում է պաշտպանության լրացուցիչ մակարդակ՝ նախքան գործողություն կատարելը");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Հաստատելու համար սեղմեք սնուցման կոճակը");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Չեղարկելու համար սեղմեք ձայնի կագավորման որևէ կոճակ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Չեղարկել");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected-ի հաստատում");
+
+    /* Tests for language id */
+    ConfirmationUITranslations_select_lang_id("id");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Tekan dua kali tombol power untuk mengonfirmasi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Batal");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Konfirmasi ini memberikan lapisan keamanan tambahan untuk tindakan yang akan Anda ambil.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Tekan tombol power untuk mengonfirmasi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Tekan tombol volume apa saja untuk membatalkan");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Batal");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Konfirmasi yang Dilindungi Android");
+
+    /* Tests for language in */
+    ConfirmationUITranslations_select_lang_id("in");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Tekan dua kali tombol power untuk mengonfirmasi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Batal");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Konfirmasi ini memberikan lapisan keamanan tambahan untuk tindakan yang akan Anda ambil.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Tekan tombol power untuk mengonfirmasi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Tekan tombol volume apa saja untuk membatalkan");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Batal");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Konfirmasi yang Dilindungi Android");
+
+    /* Tests for language is */
+    ConfirmationUITranslations_select_lang_id("is");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Ýttu tvisvar á aflrofann til að staðfesta");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Hætta við");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Þessi staðfesting veitir aukið öryggi fyrir aðgerðina sem þú ert að fara að framkvæma.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Ýttu á aflrofann til að staðfesta");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Ýttu á hvaða hljóðstyrkshnapp sem er til að hætta við");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Hætta við");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Varin staðfesting Android");
+
+    /* Tests for language it */
+    ConfirmationUITranslations_select_lang_id("it");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Premi due volte il tasto di accensione per confermare");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annulla");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Questa conferma garantisce un ulteriore livello di sicurezza per l'azione che stai per compiere.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Premi il tasto di accensione per confermare");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Premi qualsiasi pulsante del volume per annullare");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annulla");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Conferma Android Protected");
+
+    /* Tests for language iw */
+    ConfirmationUITranslations_select_lang_id("iw");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "יש ללחוץ פעמיים על לחצן ההפעלה כדי לאשר");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ביטול");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "אישור זה מספק שכבת אבטחה נוספת לפעולה שאתה עומד לבצע.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "יש ללחוץ על לחצן ההפעלה כדי לאשר");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "יש ללחוץ על לחצן כלשהו של עוצמת הקול כדי לבטל");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ביטול");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language ja */
+    ConfirmationUITranslations_select_lang_id("ja");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "確認するには、電源を 2 回押します");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "キャンセル");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "この確認により、これから行う操作のセキュリティが強化されます。");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "確認するには、電源を押します");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "キャンセルするには、いずれかの音量ボタンを押します");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "キャンセル");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected の確認");
+
+    /* Tests for language ka */
+    ConfirmationUITranslations_select_lang_id("ka");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "დასადასტურებლად ორმაგად დააჭირეთ ჩართვის ღილაკს");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "გაუქმება");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "დადასტურება უსაფრთხოების დამატებით შრეს უზრუნველყოფს იმ ქმედების განსახორციელებლად, რომელსაც აპირებთ.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "დასადასტურებლად დააჭირეთ ჩართვის ღილაკს");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "გასაუქმებლად დააჭირეთ ხმის რეგულირების ნებისმიერ ღილაკს");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "გაუქმება");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android-ის დაცული დადასტურება");
+
+    /* Tests for language kk */
+    ConfirmationUITranslations_select_lang_id("kk");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Растау үшін қуат түймесін екі рет басыңыз");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Бас тарту");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Бұл растау функциясы орындағалы тұрған әрекеттің қауіпсіздігін қосымша күшейтеді.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Растау үшін қуат түймесін басыңыз");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Бас тарту үшін кез келген дыбыс деңгейі түймесін басыңыз");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Бас тарту");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android қорғалған растау");
+
+    /* Tests for language km */
+    ConfirmationUITranslations_select_lang_id("km");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ចុច​ប៊ូតុង​ថាមពល​ពីរដង​ដើម្បី​បញ្ជាក់");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "បោះបង់");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ការបញ្ជាក់នេះ​ផ្ដល់ស្រទាប់​សុវត្ថិភាព​បន្ថែម​សម្រាប់​សកម្មភាព​ដែលអ្នកហៀប​នឹងធ្វើ។");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ចុច​ប៊ូតុង​ថាមពល​ដើម្បី​បញ្ជាក់");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ចុចប៊ូតុង​កម្រិតសំឡេង​ណាមួយ​ដើម្បីបោះបង់");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "បោះបង់");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "ការ​បញ្ជាក់​ដែលបាន​ការពារ Android");
+
+    /* Tests for language kn */
+    ConfirmationUITranslations_select_lang_id("kn");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ದೃಢೀಕರಿಸಲು ಪವರ್‌ ಬಟನ್‌ ಅನ್ನು ಎರಡು ಬಾರಿ ಒತ್ತಿರಿ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ರದ್ದು");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ಈ ದೃಢೀಕರಣವು ನೀವು ನಿರ್ವಹಿಸಲು ಬಯಸುವ ಕ್ರಿಯೆಗೆ ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯನ್ನು ಒದಗಿಸುತ್ತದೆ.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ದೃಢೀಕರಿಸಲು ಪವರ್ ಬಟನ್ ಒತ್ತಿರಿ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ರದ್ದುಗೊಳಿಸಲು ಯಾವುದೇ ವಾಲ್ಯೂಮ್‌ ಬಟನ್ ಒತ್ತಿರಿ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ರದ್ದು");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android ಸಂರಕ್ಷಿತ ದೃಢೀಕರಣ");
+
+    /* Tests for language ko */
+    ConfirmationUITranslations_select_lang_id("ko");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "확인하려면 전원 버튼을 두 번 누르세요.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "취소");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "이 확인 단계를 사용하면 실행하려는 작업의 보안을 한층 강화할 수 있습니다.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "확인하려면 전원 버튼을 누르세요.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "취소하려면 볼륨 버튼 중 하나를 누르세요.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "취소");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android 보안 확인");
+
+    /* Tests for language ky */
+    ConfirmationUITranslations_select_lang_id("ky");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Ырастоо үчүн \"Кубат\" баскычын эки жолу басыңыз");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Жокко чыгаруу");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Бул ырастоо сиз аткара турган аракеттин коопсуздугун коргоонун дагы бир катмарын камсыздайт.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Ырастоо үчүн \"Кубат\" баскычын басыңыз");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Жокко чыгаруу үчүн үн көлөмүнүн баскычтарынын бирин басыңыз");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Жокко чыгаруу");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected ырастоосу");
+
+    /* Tests for language ln */
+    ConfirmationUITranslations_select_lang_id("ln");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuler");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Appuyez sur l'un des boutons de volume pour annuler l'opération");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuler");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmation de protection Android");
+
+    /* Tests for language lo */
+    ConfirmationUITranslations_select_lang_id("lo");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ກົດປຸ່ມປິດເປີດເຄື່ອງສອງຄັ້ງເພື່ອຢືນຢັນ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ຍົກເລີກ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ການຢືນຢັນນີ້ຈະເພີ່ມຄວາມປອດໄພເພີ່ມເຕີມອີກໜຶ່ງຊັ້ນໃຫ້ກັບຄຳສັ່ງທີ່ທ່ານກຳລັງຈະໃຊ້.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ກົດປຸ່ມເປີດປິດເພື່ອຢືນຢັນ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ກົດປຸ່ມສຽງຂຶ້ນ ຫຼື ລົງເພື່ອຍົກເລີກ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ຍົກເລີກ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "ການຢືນຢັນ Android ທີ່ໄດ້ຮັບການປົກປ້ອງ");
+
+    /* Tests for language lt */
+    ConfirmationUITranslations_select_lang_id("lt");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dukart paspauskite maitinimo mygtuką, kad patvirtintumėte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Atšaukti");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Naudojant šį patvirtinimą, veiksmui, kurį ketinate atlikti, taikomas papildomas saugos lygmuo.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Paspauskite maitinimo mygtuką, kad patvirtintumėte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Paspauskite bet kurį garsumo mygtuką, kad atšauktumėte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Atšaukti");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "„Android Protected“ patvirtinimas");
+
+    /* Tests for language lv */
+    ConfirmationUITranslations_select_lang_id("lv");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Lai apstiprinātu, divreiz nospiediet barošanas pogu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Atcelt");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Šis apstiprinājums sniedz papildu aizsardzību darbībai, kuru veiksiet.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Lai apstiprinātu, nospiediet barošanas pogu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Lai atceltu, nospiediet jebkuru skaļuma pogu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Atcelt");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android aizsargātā informācija");
+
+    /* Tests for language mk */
+    ConfirmationUITranslations_select_lang_id("mk");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Притиснете на копчето за напојување двапати за да потврдите");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Откажи");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Оваа потврда обезбедува дополнителен слој на безбедност за дејството што ќе го преземете.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Притиснете на копчето за напојување за да потврдите");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Притиснете на кое било копче за јачина на звук за да откажете");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Откажи");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Потврда за заштита на Android");
+
+    /* Tests for language ml */
+    ConfirmationUITranslations_select_lang_id("ml");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "സ്ഥിരീകരിക്കാൻ പവർ രണ്ടുതവണ അമർത്തുക");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "റദ്ദാക്കുക");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "നിങ്ങൾ സ്വീകരിക്കാൻ പോകുന്ന നടപടിക്കായി, ഈ സ്ഥിരീകരണം ഒരു അധിക സുരക്ഷാ പാളി നൽകുന്നു.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "സ്ഥിരീകരിക്കാൻ പവർ അമർത്തുക");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "റദ്ദാക്കാൻ എതെങ്കിലും വോളിയം ബട്ടൺ അമർത്തുക");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "റദ്ദാക്കുക");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android സംരക്ഷിത സ്ഥിരീകരണം");
+
+    /* Tests for language mn */
+    ConfirmationUITranslations_select_lang_id("mn");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Баталгаажуулахын тулд унтраах/асаахыг хоёр удаа дарах");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Болих");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Энэ баталгаажуулалт нь таны авах гэж буй арга хэмжээнд хамгаалалтын нэмэлт давхаргыг олгодог.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Баталгаажуулахын тулд унтраах/асаахыг дарах");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Болихын тулд дууны түвшний товчлуурын аль нэгийг нь дарах");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Болих");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Андройдоор хамгаалсан баталгаажуулалт");
+
+    /* Tests for language mo */
+    ConfirmationUITranslations_select_lang_id("mo");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Apăsați de două ori butonul de pornire pentru a confirma");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Anulați");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Această confirmare oferă un nivel suplimentar de securitate pentru acțiunea pe care urmează să o faceți.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Apăsați butonul de pornire pentru a confirma");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Apăsați orice buton de volum pentru a anula");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Anulați");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmare protecție pentru Android");
+
+    /* Tests for language mr */
+    ConfirmationUITranslations_select_lang_id("mr");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "खात्री करण्‍यासाठी पॉवर बटण दोनदा दाबा");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "रद्द करा");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "हे निश्चित झाल्‍यावर, तुम्‍ही जे काम करणार आहात, त्‍यासाठी सुरक्षा आणखी वाढते.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "निश्चित करण्‍यासाठी पॉवर दाबा");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "रद्द करण्‍यासाठी कोणतेही व्‍हॉल्‍यूम बटण दाबा");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "रद्द करा");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android कडून सुरक्षा निश्चित करणे");
+
+    /* Tests for language ms */
+    ConfirmationUITranslations_select_lang_id("ms");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Tekan dua kali butang kuasa untuk mengesahkan");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Batal");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Pengesahan ini memberikan lapisan keselamatan tambahan untuk tindakan yang akan anda ambil.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Tekan kuasa untuk mengesahkan");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Tekan sebarang butang kelantangan untuk membatalkan tindakan");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Batal");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Pengesahan Dilindungi Android");
+
+    /* Tests for language my */
+    ConfirmationUITranslations_select_lang_id("my");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "အတည်ပြုရန် ပါဝါခလုတ်ကို နှစ်ချက်နှိပ်ပါ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "မလုပ်တော့");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ဤအတည်ပြုချက်က သင်ပြုလုပ်တော့မည့် လုပ်ဆောင်ချက်အတွက် အပိုဆောင်းလုံခြုံရေးကို ပေးထားသည်။");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "အတည်ပြုရန် ပါဝါခလုတ်နှိပ်ပါ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ပယ်ဖျက်ရန် အသံအတိုးအကျယ်ခလုတ် တစ်ခုခုကိုနှိပ်ပါ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "မလုပ်တော့");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android ကာကွယ်မှု အတည်ပြုချက်");
+
+    /* Tests for language nb */
+    ConfirmationUITranslations_select_lang_id("nb");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dobbelttrykk på av/på-knappen for å bekrefte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Avbryt");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Denne bekreftelsen gir et ekstra sikkerhetslag for handlingen du er i ferd med å utføre.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Trykk på av/på-knappen for å bekrefte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Trykk på en volumknapp for å avbryte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Avbryt");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android-beskyttet bekreftelse");
+
+    /* Tests for language ne */
+    ConfirmationUITranslations_select_lang_id("ne");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "पुष्टि गर्न पावर बटनमा दुई पटक थिच्नुहोस्");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "रद्द गर्नुहोस्");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "यो पुष्टिले तपाईंले गर्न ऑंट्नुभएको कारबाहीका लागि सुरक्षाको अतिरिक्त तह प्रदान गर्छ।");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "पुष्टि गर्न पावर बटनमा थिच्नुहोस्");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "रद्द गर्नका लागि कुनै भोल्युम बटन थिच्नुहोस्");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "रद्द गर्नुहोस्");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android द्वारा संरक्षण गरिएको पुष्टि");
+
+    /* Tests for language nl */
+    ConfirmationUITranslations_select_lang_id("nl");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Druk twee keer op de aan/uit-knop om te bevestigen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuleren");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Deze bevestiging biedt een extra beveiligingslaag voor de actie die je wilt uitvoeren.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Druk op de aan/uit-knop om te bevestigen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Druk op een volumeknop om te annuleren");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuleren");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bevestiging van Android-beveiliging");
+
+    /* Tests for language no */
+    ConfirmationUITranslations_select_lang_id("no");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dobbelttrykk på av/på-knappen for å bekrefte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Avbryt");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Denne bekreftelsen gir et ekstra sikkerhetslag for handlingen du er i ferd med å utføre.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Trykk på av/på-knappen for å bekrefte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Trykk på en volumknapp for å avbryte");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Avbryt");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android-beskyttet bekreftelse");
+
+    /* Tests for language or */
+    ConfirmationUITranslations_select_lang_id("or");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ସୁନିଶ୍ଚିତ କରିବା ପାଇଁ ପାୱାର୍‍ ବଟନ୍‍କୁ ଦୁଇଥର ଦବାନ୍ତୁ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "କ୍ୟାନ୍ସଲ୍‍ କରନ୍ତୁ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ଏହି ସୁନିଶ୍ଚିତତା, ଆପଣ କରିବାକୁ ଯାଉଥିବା କାର୍ଯ୍ୟ ପାଇଁ ଅତିରିକ୍ତ ସୁରକ୍ଷା ପରତ ପ୍ରଦାନ କରିଥାଏ।");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ସୁନିଶ୍ଚିତ କରିବା ପାଇଁ ପାୱର୍‌ ବଟନ୍‌କୁ ଦାବନ୍ତୁ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "କ୍ୟାନ୍ସଲ୍ କରିବା ପାଇଁ ଯେକୌଣସି ଭଲ୍ୟୁମ୍ ବଟନ୍‌କୁ ଦାବନ୍ତୁ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "କ୍ୟାନ୍ସଲ୍‍ କରନ୍ତୁ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android ଦ୍ୱାରା ସୁରକ୍ଷିତ ହୋଇଥିବାର ସୁନିଶ୍ଚିତତା");
+
+    /* Tests for language pa */
+    ConfirmationUITranslations_select_lang_id("pa");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਪਾਵਰ ਬਟਨ ਨੂੰ ਦੋ ਬਾਰ ਦੱਬੋ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ਰੱਦ ਕਰੋ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ਇਹ ਪੁਸ਼ਟੀਕਰਨ ਤੁਹਾਡੇ ਵੱਲੋਂ ਕਾਰਵਾਈ ਨੂੰ ਕੀਤੇ ਜਾਣ ਲਈ ਸੁਰੱਖਿਆ ਦੇ ਇੱਕ ਵਾਧੂ ਪੱਧਰ ਮੁਹੱਈਆ ਕਰਦੀ ਹੈ।");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਪਾਵਰ ਬਟਨ ਦਬਾਓ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ਰੱਦ ਕਰਨ ਲਈ ਕਿਸੇ ਵੀ ਵੌਲਿਊਮ ਬਟਨ ਨੂੰ ਦਬਾਓ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ਰੱਦ ਕਰੋ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android ਵੱਲੋਂ ਸੁਰੱਖਿਆ ਦੀ ਪੁਸ਼ਟੀ");
+
+    /* Tests for language pl */
+    ConfirmationUITranslations_select_lang_id("pl");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Kliknij dwukrotnie przycisk zasilania, by potwierdzić");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Anuluj");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "To potwierdzenie stanowi dodatkowe zabezpieczenie czynności, którą zamierzasz wykonać.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Naciśnij przycisk zasilania, aby potwierdzić");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Naciśnij dowolny przycisk głośności, aby anulować");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Anuluj");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Zabezpieczone potwierdzenie w Androidzie");
+
+    /* Tests for language pt */
+    ConfirmationUITranslations_select_lang_id("pt");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Pressione o botão liga/desliga duas vezes para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Essa confirmação oferece uma camada adicional de segurança para a ação que você está prestes a realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pressione o botão liga/desliga para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pressione um dos botões de volume para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmação protegida pelo Android");
+
+    /* Tests for language pt-BR */
+    ConfirmationUITranslations_select_lang_id("pt-BR");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Pressione o botão liga/desliga duas vezes para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Essa confirmação oferece uma camada adicional de segurança para a ação que você está prestes a realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pressione o botão liga/desliga para confirmar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pressione um dos botões de volume para cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmação protegida pelo Android");
+
+    /* Tests for language pt-PT */
+    ConfirmationUITranslations_select_lang_id("pt-PT");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Prima duas vezes ligar/desligar para confirmar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmação oferece um nível extra de segurança para a ação que está prestes a realizar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Prima ligar/desligar para confirmar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Prima qualquer botão de volume para cancelar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmação protegida do Android");
+
+    /* Tests for language ro */
+    ConfirmationUITranslations_select_lang_id("ro");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Apăsați de două ori butonul de pornire pentru a confirma");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Anulați");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Această confirmare oferă un nivel suplimentar de securitate pentru acțiunea pe care urmează să o faceți.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Apăsați butonul de pornire pentru a confirma");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Apăsați orice buton de volum pentru a anula");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Anulați");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmare protecție pentru Android");
+
+    /* Tests for language ru */
+    ConfirmationUITranslations_select_lang_id("ru");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Для подтверждения дважды нажмите кнопку питания.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Отмена");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Дополнительный уровень защиты для действия, которое вы собираетесь выполнить.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Для подтверждения нажмите кнопку питания.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Для отмены нажмите на любую кнопку регулировки громкости.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Отмена");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Подтверждение Android Protected");
+
+    /* Tests for language si */
+    ConfirmationUITranslations_select_lang_id("si");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "තහවුරු කිරීමට බල බොත්තම දෙවරක් ඔබන්න");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "අවලංගු කරන්න");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "මෙම තහවුරු කිරිම ඔබ ගැනීමට යන ක්‍රියාමාර්ගය සඳහා ආරක්ෂාව පිළිබඳ අමතර ස්තරයක් සපයයි.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "තහවුරු කිරීමට බල බොත්තම ඔබන්න");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "අවලංගු කිරීමට ඕනෑම හඬ පරිමා බොත්තමක් ඔබන්න");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "අවලංගු කරන්න");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android ආරක්ෂිත තහවුරු කිරීම");
+
+    /* Tests for language sk */
+    ConfirmationUITranslations_select_lang_id("sk");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Potvrďte dvojitým stlačením vypínača");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Zrušiť");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Toto potvrdenie zaistí dodatočnú úroveň zabezpečenia akcie, ktorú sa chystáte vykonať.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Potvrďte stlačením vypínača");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zrušte stlačením ľubovoľného tlačidla hlasitosti");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Zrušiť");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Chránené potvrdenie Androidu");
+
+    /* Tests for language sl */
+    ConfirmationUITranslations_select_lang_id("sl");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dvakrat pritisnite za potrditev");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Prekliči");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ta potrditev zagotavlja dodatno plast zaščite za dejanje, ki ga boste izvedli.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Za potrditev pritisnite gumb za vklop");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Za preklic pritisnite poljuben gumb za glasnost");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Prekliči");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Zaščitena potrditev v Androidu");
+
+    /* Tests for language sq */
+    ConfirmationUITranslations_select_lang_id("sq");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Shtyp dy herë butonin e energjisë për të konfirmuar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Anulo");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Konfirmim ofron një shtresë sigurie shtesë për veprimin që je gati për të ndërmarrë.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Shtyp butonin e energjisë për të konfirmuar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Shtyp çdo buton volumi për ta anuluar");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Anulo");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+    /* Tests for language sr */
+    ConfirmationUITranslations_select_lang_id("sr");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Двапут притисните дугме за напајање да бисте потврдили");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Откажи");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ова потврда пружа додатни слој безбедности за радњу коју се спремате да извршите.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Притисните дугме за напајање да бисте потврдили");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Притисните било које дугме за јачину звука да бисте отказали");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Откажи");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Потврда заштите на Android-у");
+
+    /* Tests for language sr-Latn */
+    ConfirmationUITranslations_select_lang_id("sr-Latn");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dvaput pritisnite dugme za napajanje da biste potvrdili");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Otkaži");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ova potvrda pruža dodatni sloj bezbednosti za radnju koju se spremate da izvršite.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pritisnite dugme za napajanje da biste potvrdili");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pritisnite bilo koje dugme za jačinu zvuka da biste otkazali");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Otkaži");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Potvrda zaštite na Android-u");
+
+    /* Tests for language sv */
+    ConfirmationUITranslations_select_lang_id("sv");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Bekräfta genom att trycka två gånger på avstängningsknappen");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Avbryt");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Bekräftelsen ger extra skydd för åtgärden du ska vidta.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Bekräfta genom att trycka på strömbrytaren");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Avbryt genom att trycka på valfri volymknapp");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Avbryt");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bekräftelseskydd för Android");
+
+    /* Tests for language sw */
+    ConfirmationUITranslations_select_lang_id("sw");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Bonyeza kitufe cha kuwasha mara mbili ili uthibitishe");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Ghairi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Uthibitishaji huu hutoa ulinzi zaidi wa usalama kwa hatua unayotaka kuchukua.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Bonyeza kitufe cha kuwasha ili uthibitishe");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Bonyeza kitufe chochote cha sauti ili ughairi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Ghairi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Uthibitishaji Unaolindwa wa Android");
+
+    /* Tests for language ta */
+    ConfirmationUITranslations_select_lang_id("ta");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "உறுதிப்படுத்த, பவர் பட்டனை இருமுறை அழுத்தவும்");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ரத்துசெய்");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "நீங்கள் மேற்கொள்ளவிருக்கும் செயலுக்கு, கூடுதல் பாதுகாப்பை இந்த உறுதிப்படுத்தல் வழங்கும்.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "உறுதிப்படுத்த, பவரை அழுத்தவும்");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ரத்துசெய்ய, ஏதேனும் ஒலியளவு பட்டனை அழுத்தவும்");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ரத்துசெய்");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android பாதுகாப்பு தொடர்பான உறுதிப்படுத்தல்");
+
+    /* Tests for language te */
+    ConfirmationUITranslations_select_lang_id("te");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "నిర్ధారించడానికి పవర్ బటన్‌ని రెండు సార్లు నొక్కండి");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "రద్దు చేయండి");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ఈ నిర్ధారణ మీరు తీసుకోబోయే చర్య కోసం అదనపు భద్రతా లేయర్‌ను అందిస్తుంది.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "నిర్ధారించడానికి పవర్‌ను నొక్కండి");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "రద్దు చేయడానికి ఏదైనా వాల్యూమ్ బటన్‌ను నొక్కండి");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "రద్దు చేయండి");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android సురక్షిత నిర్ధారణ");
+
+    /* Tests for language th */
+    ConfirmationUITranslations_select_lang_id("th");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "กดปุ่มเปิด/ปิด 2 ครั้งเพื่อยืนยัน");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ยกเลิก");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "การยืนยันนี้จะช่วยเพิ่มความปลอดภัยอีกขั้นสำหรับสิ่งที่คุณกำลังจะดำเนินการ");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "กดปุ่มเปิด/ปิดเพื่อยืนยัน");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "กดปุ่มปรับระดับเสียงเพื่อยกเลิก");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ยกเลิก");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "ยืนยันการป้องกัน Android");
+
+    /* Tests for language tl */
+    ConfirmationUITranslations_select_lang_id("tl");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Pindutin nang dalawang beses ang power para kumpirmahin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Kanselahin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ang pagkumpirmang ito ay nagbibigay ng karagdagang layer ng seguridad para sa pagkilos na gagawin mo.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pindutin ang power para kumpirmahin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pindutin ang anumang button ng volume para kanselahin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Kanselahin");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Pagkumpirmang Pinoprotektahan ng Android");
+
+    /* Tests for language tr */
+    ConfirmationUITranslations_select_lang_id("tr");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Onaylamak için güç düğmesine iki kez basın");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "İptal");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Bu onay, yapmak üzere olduğunuz işlem için ek güvenlik katmanı sağlar.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Onaylamak için güç düğmesine basın");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "İptal etmek için herhangi bir ses düğmesine basın");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "İptal");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Korumalı Onayı");
+
+    /* Tests for language uk */
+    ConfirmationUITranslations_select_lang_id("uk");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Двічі натисніть кнопку живлення, щоб підтвердити");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Скасувати");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Це підтвердження є додатковим рівнем захисту, коли ви збираєтеся виконати дію.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Натисніть кнопку живлення, щоб підтвердити");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Натисніть будь-яку клавішу гучності, щоб скасувати");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Скасувати");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Підтвердження Android Protected");
+
+    /* Tests for language ur */
+    ConfirmationUITranslations_select_lang_id("ur");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "تصدیق کرنے کے لئے پاور بٹن دوبار دبائیں");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "منسوخ کریں");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "آپ جو کارروائی کرنے والے ہیں اس کے لئے یہ تصدیق ایک اضافی پرت فراہم کرتی ہے۔");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "تصدیق کرنے کے لئے پاور بٹن دبائیں");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "منسوخ کرنے کے لئے کوئی بھی والیوم بٹن دبائیں");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "منسوخ کریں");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android کی تحفظ یافتہ تصدیق");
+
+    /* Tests for language uz */
+    ConfirmationUITranslations_select_lang_id("uz");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Tasdiqlash uchun quvvat tugmasini ikki marta bosing");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Bekor qilish");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Tasdiqlangandan keyin bajarilayotgan amal uchun qo‘shimcha xavfsizlik qatlami taqdim etiladi.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Tasdiqlash uchun quvvat tugmasini bosing");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Bekor qilish uchun istalgan tovush tugmasini bosing");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Bekor qilish");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected nomli tasdiq");
+
+    /* Tests for language vi */
+    ConfirmationUITranslations_select_lang_id("vi");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Nhấn hai lần vào nút nguồn để xác nhận");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Hủy");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Xác nhận này cung cấp thêm một lớp bảo mật cho hành động bạn sắp thực hiện.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Nhấn vào nút nguồn để xác nhận");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Nhấn vào nút âm lượng bất kỳ để hủy");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Hủy");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Xác nhận bảo vệ Android");
+
+    /* Tests for language zh */
+    ConfirmationUITranslations_select_lang_id("zh");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "连按两次电源按钮即可确认");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "这项确认可为您即将执行的操作增添一层额外的安全保障。");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "按电源按钮即可确认");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "按任意音量按钮即可取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android 保护确认");
+
+    /* Tests for language zh-CN */
+    ConfirmationUITranslations_select_lang_id("zh-CN");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "连按两次电源按钮即可确认");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "这项确认可为您即将执行的操作增添一层额外的安全保障。");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "按电源按钮即可确认");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "按任意音量按钮即可取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android 保护确认");
+
+    /* Tests for language zh-HK */
+    ConfirmationUITranslations_select_lang_id("zh-HK");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "按兩下電源按鈕即可確認");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "此確認可為你即將執行的操作提供額外安全保障。");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "按下電源按鈕即可確認");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "按下任何音量按鈕即可取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android 保護確認");
+
+    /* Tests for language zh-TW */
+    ConfirmationUITranslations_select_lang_id("zh-TW");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "按兩下電源按鈕即可確認操作");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "這項確認作業可為你即將執行的動作提供多一層安全保障。");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "按下電源按鈕即可確認操作");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "按下任一音量按鈕即可取消操作");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "取消");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected 確認");
+
+    /* Tests for language zu */
+    ConfirmationUITranslations_select_lang_id("zu");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Cindezela kabili ukuze uqinisekise");
+    ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Khansela");
+    ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Lokhu kuqinisekiswa kunikeza isendlalelo esingeziwe sokuvikelwa sesenzo osuzosithatha.");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Cindezela amandla ukuze uqinisekise");
+    ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Cindezela noma iyiphi inkinobho yevolumu ukuze ukhansele");
+    ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Khansela");
+    ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Ukuqinisekiswa okuvikelwe i-Android");
+
+    /* Check language tag fallback mechanism works
+       (chop off components until a match has been found) */
+    const char* lang_ids[] = {
+        "de",
+        "da",
+        "da-GL",
+        "es-419",
+        "es-AR",
+        NULL
+    };
+    ASSERT_STR(test_lang_id_match(lang_ids, "de"), "de");
+    ASSERT_STR(test_lang_id_match(lang_ids, "de-DE"), "de");
+    ASSERT_STR(test_lang_id_match(lang_ids, "de-CH-1901"), "de");
+    ASSERT_STR(test_lang_id_match(lang_ids, "de-AT"), "de");
+    ASSERT_STR(test_lang_id_match(lang_ids, "da-DK"), "da");
+    ASSERT_STR(test_lang_id_match(lang_ids, "da-GL"), "da-GL");
+    ASSERT_STR(test_lang_id_match(lang_ids, "zh"), "");
+    ASSERT_STR(test_lang_id_match(lang_ids, "es-419"), "es-419");
+    ASSERT_STR(test_lang_id_match(lang_ids, "es-AR"), "es-AR");
+    ASSERT_STR(test_lang_id_match(lang_ids, "es"), "");
+
+    printf("All unit tests passed.\n");
+    return 0;
+}
diff --git a/contexthub/1.0/Android.bp b/contexthub/1.0/Android.bp
index 730adcb..71dd978 100644
--- a/contexthub/1.0/Android.bp
+++ b/contexthub/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/contexthub/1.0/default/Android.bp b/contexthub/1.0/default/Android.bp
index d1db6a6..8384037 100644
--- a/contexthub/1.0/default/Android.bp
+++ b/contexthub/1.0/default/Android.bp
@@ -28,7 +28,6 @@
         "libcutils",
         "libutils",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.contexthub@1.0",
     ],
 }
@@ -47,7 +46,6 @@
         "libdl",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.contexthub@1.0",
diff --git a/contexthub/1.0/default/OWNERS b/contexthub/1.0/default/OWNERS
index 5373073..90c2330 100644
--- a/contexthub/1.0/default/OWNERS
+++ b/contexthub/1.0/default/OWNERS
@@ -1,4 +1,3 @@
-aarossig@google.com
 arthuri@google.com
 bduddie@google.com
-bstack@google.com
+stange@google.com
diff --git a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
index a8c9487..b659be8 100644
--- a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
+++ b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.contexthub-hal-1-0 /vendor/bin/hw/android.hardware.contexthub@1.0-service
+    interface android.hardware.contexthub@1.0::IContexthub default
     class hal
     user system
     group system
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
index ee01441..045cc4e 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -1,8 +1,7 @@
 #Context Hub team
-aarossig@google.com
 arthuri@google.com
 bduddie@google.com
-bstack@google.com
+stange@google.com
 
 #VTS team
 yim@google.com
diff --git a/current.txt b/current.txt
index 221ca20..90f646d 100644
--- a/current.txt
+++ b/current.txt
@@ -576,3 +576,45 @@
 09e08b5d12b109562ecdd8882532fd1f2c4639588e07769d5c7396b7c5b9f34f android.hardware.wifi.supplicant@1.2::ISupplicantStaIfaceCallback
 efbb061c969fa9553d243da6ee23b83fe5d4aa663a7b8896adc52e2b015bc2f3 android.hardware.wifi.supplicant@1.2::ISupplicantStaNetwork
 cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardware.wifi.supplicant@1.2::types
+
+# ABI preserving changes to HALs during Android R
+b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
+eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
+f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types
+5f6d3097ba84cb63c430787123f4de1b31c11f90b531b98eae9a8623a5ae962a android.hardware.neuralnetworks@1.1::types
+fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice
+40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel
+2d5483fbf59d5fd2de94665a6df05da5c3d09de67561d0db5e9f09e59e9aea46 android.hardware.neuralnetworks@1.2::types
+a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types
+1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
+fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
+
+# HALs released in Android R
+79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci
+40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks
+07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
+74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
+ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
+26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
+db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types
+c228aaa27f66c48e147159a4f4996c5273191fece1b08de31bd171c61334855e android.hardware.keymaster@4.1::IKeymasterDevice
+adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
+7a04ea5595ed418ca3e91c28b8bd7353dd988be9be7b0c8c9e64fb4b77bd4523 android.hardware.keymaster@4.1::types
+9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice
+4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel
+94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
+cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types
+3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
+a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
+44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
+619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
+c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
+9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types
+eaf870a7439838c66127a74e1896c4a2346979c116eb1931785ebb4d353230ae android.hardware.radio@1.5::types
+ae2fd16a80caff9cb6e3f91875c7f68f7ff76c75334056549d38496673eafe5b android.hardware.radio@1.5::IRadio
+3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication
+e7268d32bedcf7d98324ffc808ec3dc45248d47ff4d04519d09e3c71767a7ad1 android.hardware.radio@1.5::IRadioResponse
+55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types
+b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
+742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
+7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse
diff --git a/drm/1.0/Android.bp b/drm/1.0/Android.bp
index fea851f..9049af2 100644
--- a/drm/1.0/Android.bp
+++ b/drm/1.0/Android.bp
@@ -17,6 +17,5 @@
     interfaces: [
         "android.hidl.base@1.0",
     ],
-    gen_java: false,
+    gen_java: true,
 }
-
diff --git a/drm/1.0/default/Android.mk b/drm/1.0/default/Android.mk
index d66f377..9016dc3 100644
--- a/drm/1.0/default/Android.mk
+++ b/drm/1.0/default/Android.mk
@@ -59,7 +59,6 @@
     libcutils \
     libhidlbase \
     libhidlmemory \
-    libhidltransport \
     liblog \
     libstagefright_foundation \
     libutils \
diff --git a/drm/1.0/default/common_default_service.mk b/drm/1.0/default/common_default_service.mk
index 28db567..1b5a975 100644
--- a/drm/1.0/default/common_default_service.mk
+++ b/drm/1.0/default/common_default_service.mk
@@ -21,7 +21,6 @@
   android.hardware.drm@1.0 \
   android.hidl.memory@1.0 \
   libhidlbase \
-  libhidltransport \
   libhardware \
   liblog \
   libutils \
diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp
index d6ebfdd..61d4d58 100644
--- a/drm/1.0/vts/functional/Android.bp
+++ b/drm/1.0/vts/functional/Android.bp
@@ -30,7 +30,7 @@
         "libhidlmemory",
         "libnativehelper",
         "libssl",
-        "libcrypto",
+        "libcrypto_static",
     ],
     test_suites: ["general-tests"],
 }
diff --git a/drm/1.1/Android.bp b/drm/1.1/Android.bp
index 739b470..16010a6 100644
--- a/drm/1.1/Android.bp
+++ b/drm/1.1/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/drm/1.1/vts/functional/Android.bp b/drm/1.1/vts/functional/Android.bp
index 1090b69..47b02bf 100644
--- a/drm/1.1/vts/functional/Android.bp
+++ b/drm/1.1/vts/functional/Android.bp
@@ -29,7 +29,6 @@
         "libhidlmemory",
         "libnativehelper",
         "libssl",
-        "libcrypto",
     ],
     test_suites: ["general-tests"],
 }
diff --git a/drm/1.2/Android.bp b/drm/1.2/Android.bp
index 2d54302..9104aa9 100644
--- a/drm/1.2/Android.bp
+++ b/drm/1.2/Android.bp
@@ -21,4 +21,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/drm/1.2/vts/functional/Android.bp b/drm/1.2/vts/functional/Android.bp
index 6b4a4c0..95883bf 100644
--- a/drm/1.2/vts/functional/Android.bp
+++ b/drm/1.2/vts/functional/Android.bp
@@ -34,7 +34,7 @@
         "libhidlmemory",
         "libnativehelper",
         "libssl",
-        "libcrypto",
+        "libcrypto_static",
     ],
     test_suites: ["general-tests"],
 }
diff --git a/dumpstate/1.0/Android.bp b/dumpstate/1.0/Android.bp
index 29be116..3d47550 100644
--- a/dumpstate/1.0/Android.bp
+++ b/dumpstate/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/dumpstate/1.0/default/Android.bp b/dumpstate/1.0/default/Android.bp
index 3ca19e8..6b02715 100644
--- a/dumpstate/1.0/default/Android.bp
+++ b/dumpstate/1.0/default/Android.bp
@@ -1,5 +1,5 @@
 cc_binary {
-    name: "android.hardware.dumpstate@1.0-service",
+    name: "android.hardware.dumpstate@1.0-service.example",
     init_rc: ["android.hardware.dumpstate@1.0-service.rc"],
     relative_install_path: "hw",
     vendor: true,
@@ -18,7 +18,6 @@
         "libcutils",
         "libdumpstateutil",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
diff --git a/dumpstate/1.0/default/DumpstateDevice.cpp b/dumpstate/1.0/default/DumpstateDevice.cpp
index 25d92b0..c57bf43 100644
--- a/dumpstate/1.0/default/DumpstateDevice.cpp
+++ b/dumpstate/1.0/default/DumpstateDevice.cpp
@@ -37,11 +37,6 @@
     // NOTE: this is just an example on how to use the DumpstateUtil.h functions to implement
     // this interface.
 
-    // Exit when dump is completed since this is a lazy HAL.
-    addPostCommandTask([]() {
-        exit(0);
-    });
-
     if (handle == nullptr || handle->numFds < 1) {
         ALOGE("no FDs\n");
         return Void();
diff --git a/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc b/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc
index 062a291..03298dc 100644
--- a/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc
+++ b/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc
@@ -1,4 +1,4 @@
-service vendor.dumpstate-1-0 /vendor/bin/hw/android.hardware.dumpstate@1.0-service
+service vendor.dumpstate-1-0 /vendor/bin/hw/android.hardware.dumpstate@1.0-service.example
     class hal
     user system
     group system
diff --git a/dumpstate/1.0/default/service.cpp b/dumpstate/1.0/default/service.cpp
index 4f276b7..76c72b5 100644
--- a/dumpstate/1.0/default/service.cpp
+++ b/dumpstate/1.0/default/service.cpp
@@ -15,22 +15,26 @@
  */
 #define LOG_TAG "android.hardware.dumpstate@1.0-service"
 
+#include <hidl/HidlLazyUtils.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
 
 #include "DumpstateDevice.h"
 
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
-using ::android::hardware::dumpstate::V1_0::implementation::DumpstateDevice;
-using ::android::hardware::joinRpcThreadpool;
 using ::android::OK;
 using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::LazyServiceRegistrar;
+using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using ::android::hardware::dumpstate::V1_0::implementation::DumpstateDevice;
 
 int main(int /* argc */, char* /* argv */ []) {
     sp<IDumpstateDevice> dumpstate = new DumpstateDevice;
     configureRpcThreadpool(1, true /* will join */);
-    if (dumpstate->registerAsService() != OK) {
+
+    auto registrar = LazyServiceRegistrar::getInstance();
+    if (registrar.registerService(dumpstate) != OK) {
         ALOGE("Could not register service.");
         return 1;
     }
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/fastboot/1.0/Android.bp b/fastboot/1.0/Android.bp
index ea3566f..ec447b8 100644
--- a/fastboot/1.0/Android.bp
+++ b/fastboot/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/fastboot/1.0/default/Android.bp b/fastboot/1.0/default/Android.bp
index fde7efa..f7b3635 100644
--- a/fastboot/1.0/default/Android.bp
+++ b/fastboot/1.0/default/Android.bp
@@ -23,7 +23,6 @@
     shared_libs: [
         "libbase",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "libcutils",
         "android.hardware.fastboot@1.0",
diff --git a/gatekeeper/1.0/Android.bp b/gatekeeper/1.0/Android.bp
index 7eff2e8..5d63eaf 100644
--- a/gatekeeper/1.0/Android.bp
+++ b/gatekeeper/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/gatekeeper/1.0/default/Android.bp b/gatekeeper/1.0/default/Android.bp
index ae3b91c..2be4f4d 100644
--- a/gatekeeper/1.0/default/Android.bp
+++ b/gatekeeper/1.0/default/Android.bp
@@ -10,7 +10,6 @@
         "android.hardware.gatekeeper@1.0",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "liblog",
     ],
@@ -30,7 +29,6 @@
         "android.hardware.gatekeeper@1.0",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "liblog",
     ],
diff --git a/gatekeeper/1.0/default/OWNERS b/gatekeeper/1.0/default/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/gatekeeper/1.0/default/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
index da332c7..b13a9ba 100644
--- a/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
+++ b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.gatekeeper-1-0 /vendor/bin/hw/android.hardware.gatekeeper@1.0-service
+    interface android.hardware.gatekeeper@1.0::IGatekeeper default
     class hal
     user system
     group system
diff --git a/gatekeeper/1.0/software/Android.bp b/gatekeeper/1.0/software/Android.bp
new file mode 100644
index 0000000..24c81f6
--- /dev/null
+++ b/gatekeeper/1.0/software/Android.bp
@@ -0,0 +1,27 @@
+cc_binary {
+    name: "android.hardware.gatekeeper@1.0-service.software",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.gatekeeper@1.0-service.software.rc"],
+
+    srcs: [
+        "service.cpp",
+        "SoftGateKeeperDevice.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.gatekeeper@1.0",
+        "libbase",
+        "libhardware",
+        "libhidlbase",
+        "libutils",
+        "liblog",
+        "libcrypto",
+        "libgatekeeper",
+    ],
+
+    static_libs: ["libscrypt_static"],
+
+    vintf_fragments: ["android.hardware.gatekeeper@1.0-service.software.xml"],
+}
diff --git a/gatekeeper/1.0/software/OWNERS b/gatekeeper/1.0/software/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/gatekeeper/1.0/software/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/gatekeeper/1.0/software/SoftGateKeeper.h b/gatekeeper/1.0/software/SoftGateKeeper.h
new file mode 100644
index 0000000..3276d1e
--- /dev/null
+++ b/gatekeeper/1.0/software/SoftGateKeeper.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef SOFT_GATEKEEPER_H_
+#define SOFT_GATEKEEPER_H_
+
+extern "C" {
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include <crypto_scrypt.h>
+}
+
+#include <android-base/memory.h>
+#include <gatekeeper/gatekeeper.h>
+
+#include <iostream>
+#include <memory>
+#include <unordered_map>
+
+namespace gatekeeper {
+
+struct fast_hash_t {
+    uint64_t salt;
+    uint8_t digest[SHA256_DIGEST_LENGTH];
+};
+
+class SoftGateKeeper : public GateKeeper {
+  public:
+    static const uint32_t SIGNATURE_LENGTH_BYTES = 32;
+
+    // scrypt params
+    static const uint64_t N = 16384;
+    static const uint32_t r = 8;
+    static const uint32_t p = 1;
+
+    static const int MAX_UINT_32_CHARS = 11;
+
+    SoftGateKeeper() {
+        key_.reset(new uint8_t[SIGNATURE_LENGTH_BYTES]);
+        memset(key_.get(), 0, SIGNATURE_LENGTH_BYTES);
+    }
+
+    virtual ~SoftGateKeeper() {}
+
+    virtual bool GetAuthTokenKey(const uint8_t** auth_token_key, uint32_t* length) const {
+        if (auth_token_key == NULL || length == NULL) return false;
+        *auth_token_key = key_.get();
+        *length = SIGNATURE_LENGTH_BYTES;
+        return true;
+    }
+
+    virtual void GetPasswordKey(const uint8_t** password_key, uint32_t* length) {
+        if (password_key == NULL || length == NULL) return;
+        *password_key = key_.get();
+        *length = SIGNATURE_LENGTH_BYTES;
+    }
+
+    virtual void ComputePasswordSignature(uint8_t* signature, uint32_t signature_length,
+                                          const uint8_t*, uint32_t, const uint8_t* password,
+                                          uint32_t password_length, salt_t salt) const {
+        if (signature == NULL) return;
+        crypto_scrypt(password, password_length, reinterpret_cast<uint8_t*>(&salt), sizeof(salt), N,
+                      r, p, signature, signature_length);
+    }
+
+    virtual void GetRandom(void* random, uint32_t requested_length) const {
+        if (random == NULL) return;
+        RAND_pseudo_bytes((uint8_t*)random, requested_length);
+    }
+
+    virtual void ComputeSignature(uint8_t* signature, uint32_t signature_length, const uint8_t*,
+                                  uint32_t, const uint8_t*, const uint32_t) const {
+        if (signature == NULL) return;
+        memset(signature, 0, signature_length);
+    }
+
+    virtual uint64_t GetMillisecondsSinceBoot() const {
+        struct timespec time;
+        int res = clock_gettime(CLOCK_BOOTTIME, &time);
+        if (res < 0) return 0;
+        return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
+    }
+
+    virtual bool IsHardwareBacked() const { return false; }
+
+    virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t* record,
+                                  bool /* secure */) {
+        failure_record_t* stored = &failure_map_[uid];
+        if (user_id != stored->secure_user_id) {
+            stored->secure_user_id = user_id;
+            stored->last_checked_timestamp = 0;
+            stored->failure_counter = 0;
+        }
+        memcpy(record, stored, sizeof(*record));
+        return true;
+    }
+
+    virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool /* secure */) {
+        failure_record_t* stored = &failure_map_[uid];
+        stored->secure_user_id = user_id;
+        stored->last_checked_timestamp = 0;
+        stored->failure_counter = 0;
+        return true;
+    }
+
+    virtual bool WriteFailureRecord(uint32_t uid, failure_record_t* record, bool /* secure */) {
+        failure_map_[uid] = *record;
+        return true;
+    }
+
+    fast_hash_t ComputeFastHash(const SizedBuffer& password, uint64_t salt) {
+        fast_hash_t fast_hash;
+        size_t digest_size = password.size() + sizeof(salt);
+        std::unique_ptr<uint8_t[]> digest(new uint8_t[digest_size]);
+        memcpy(digest.get(), &salt, sizeof(salt));
+        memcpy(digest.get() + sizeof(salt), password.Data<uint8_t>(), password.size());
+
+        SHA256(digest.get(), digest_size, (uint8_t*)&fast_hash.digest);
+
+        fast_hash.salt = salt;
+        return fast_hash;
+    }
+
+    bool VerifyFast(const fast_hash_t& fast_hash, const SizedBuffer& password) {
+        fast_hash_t computed = ComputeFastHash(password, fast_hash.salt);
+        return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0;
+    }
+
+    bool DoVerify(const password_handle_t* expected_handle, const SizedBuffer& password) {
+        uint64_t user_id = android::base::get_unaligned<secure_id_t>(&expected_handle->user_id);
+        FastHashMap::const_iterator it = fast_hash_map_.find(user_id);
+        if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) {
+            return true;
+        } else {
+            if (GateKeeper::DoVerify(expected_handle, password)) {
+                uint64_t salt;
+                GetRandom(&salt, sizeof(salt));
+                fast_hash_map_[user_id] = ComputeFastHash(password, salt);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+  private:
+    typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap;
+    typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap;
+
+    std::unique_ptr<uint8_t[]> key_;
+    FailureRecordMap failure_map_;
+    FastHashMap fast_hash_map_;
+};
+}  // namespace gatekeeper
+
+#endif  // SOFT_GATEKEEPER_H_
diff --git a/gatekeeper/1.0/software/SoftGateKeeperDevice.cpp b/gatekeeper/1.0/software/SoftGateKeeperDevice.cpp
new file mode 100644
index 0000000..d7a0b46
--- /dev/null
+++ b/gatekeeper/1.0/software/SoftGateKeeperDevice.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SoftGateKeeperDevice.h"
+#include "SoftGateKeeper.h"
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
+using ::gatekeeper::EnrollRequest;
+using ::gatekeeper::EnrollResponse;
+using ::gatekeeper::ERROR_INVALID;
+using ::gatekeeper::ERROR_MEMORY_ALLOCATION_FAILED;
+using ::gatekeeper::ERROR_NONE;
+using ::gatekeeper::ERROR_RETRY;
+using ::gatekeeper::SizedBuffer;
+using ::gatekeeper::VerifyRequest;
+using ::gatekeeper::VerifyResponse;
+
+#include <limits>
+
+namespace android {
+
+inline SizedBuffer hidl_vec2sized_buffer(const hidl_vec<uint8_t>& vec) {
+    if (vec.size() == 0 || vec.size() > std::numeric_limits<uint32_t>::max()) return {};
+    auto dummy = new uint8_t[vec.size()];
+    std::copy(vec.begin(), vec.end(), dummy);
+    return {dummy, static_cast<uint32_t>(vec.size())};
+}
+
+Return<void> SoftGateKeeperDevice::enroll(uint32_t uid,
+                                          const hidl_vec<uint8_t>& currentPasswordHandle,
+                                          const hidl_vec<uint8_t>& currentPassword,
+                                          const hidl_vec<uint8_t>& desiredPassword,
+                                          enroll_cb _hidl_cb) {
+    if (desiredPassword.size() == 0) {
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+        return {};
+    }
+
+    EnrollRequest request(uid, hidl_vec2sized_buffer(currentPasswordHandle),
+                          hidl_vec2sized_buffer(desiredPassword),
+                          hidl_vec2sized_buffer(currentPassword));
+    EnrollResponse response;
+    impl_->Enroll(request, &response);
+
+    if (response.error == ERROR_RETRY) {
+        _hidl_cb({GatekeeperStatusCode::ERROR_RETRY_TIMEOUT, response.retry_timeout, {}});
+    } else if (response.error != ERROR_NONE) {
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+    } else {
+        hidl_vec<uint8_t> new_handle(response.enrolled_password_handle.Data<uint8_t>(),
+                                     response.enrolled_password_handle.Data<uint8_t>() +
+                                             response.enrolled_password_handle.size());
+        _hidl_cb({GatekeeperStatusCode::STATUS_OK, response.retry_timeout, new_handle});
+    }
+    return {};
+}
+
+Return<void> SoftGateKeeperDevice::verify(
+        uint32_t uid, uint64_t challenge,
+        const ::android::hardware::hidl_vec<uint8_t>& enrolledPasswordHandle,
+        const ::android::hardware::hidl_vec<uint8_t>& providedPassword, verify_cb _hidl_cb) {
+    if (enrolledPasswordHandle.size() == 0) {
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+        return {};
+    }
+
+    VerifyRequest request(uid, challenge, hidl_vec2sized_buffer(enrolledPasswordHandle),
+                          hidl_vec2sized_buffer(providedPassword));
+    VerifyResponse response;
+
+    impl_->Verify(request, &response);
+
+    if (response.error == ERROR_RETRY) {
+        _hidl_cb({GatekeeperStatusCode::ERROR_RETRY_TIMEOUT, response.retry_timeout, {}});
+    } else if (response.error != ERROR_NONE) {
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+    } else {
+        hidl_vec<uint8_t> auth_token(
+                response.auth_token.Data<uint8_t>(),
+                response.auth_token.Data<uint8_t>() + response.auth_token.size());
+
+        _hidl_cb({response.request_reenroll ? GatekeeperStatusCode::STATUS_REENROLL
+                                            : GatekeeperStatusCode::STATUS_OK,
+                  response.retry_timeout, auth_token});
+    }
+    return {};
+}
+
+Return<void> SoftGateKeeperDevice::deleteUser(uint32_t /*uid*/, deleteUser_cb _hidl_cb) {
+    _hidl_cb({GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED, 0, {}});
+    return {};
+}
+
+Return<void> SoftGateKeeperDevice::deleteAllUsers(deleteAllUsers_cb _hidl_cb) {
+    _hidl_cb({GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED, 0, {}});
+    return {};
+}
+
+}  // namespace android
diff --git a/gatekeeper/1.0/software/SoftGateKeeperDevice.h b/gatekeeper/1.0/software/SoftGateKeeperDevice.h
new file mode 100644
index 0000000..17b474e
--- /dev/null
+++ b/gatekeeper/1.0/software/SoftGateKeeperDevice.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_GATEKEEPER_DEVICE_H_
+#define SOFT_GATEKEEPER_DEVICE_H_
+
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+#include <hidl/Status.h>
+
+#include <memory>
+#include "SoftGateKeeper.h"
+
+namespace android {
+
+/**
+ * Software based GateKeeper implementation
+ */
+class SoftGateKeeperDevice : public ::android::hardware::gatekeeper::V1_0::IGatekeeper {
+  public:
+    SoftGateKeeperDevice() { impl_.reset(new ::gatekeeper::SoftGateKeeper()); }
+
+    // Wrappers to translate the gatekeeper HAL API to the Kegyuard Messages API.
+
+    /**
+     * Enrolls password_payload, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password_handle will not be allocated.
+     */
+    ::android::hardware::Return<void> enroll(
+            uint32_t uid, const ::android::hardware::hidl_vec<uint8_t>& currentPasswordHandle,
+            const ::android::hardware::hidl_vec<uint8_t>& currentPassword,
+            const ::android::hardware::hidl_vec<uint8_t>& desiredPassword,
+            enroll_cb _hidl_cb) override;
+
+    /**
+     * Verifies provided_password matches enrolled_password_handle.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to auth_token,
+     * usable to attest password verification to other trusted services. Clients
+     * may pass NULL for this value.
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    ::android::hardware::Return<void> verify(
+            uint32_t uid, uint64_t challenge,
+            const ::android::hardware::hidl_vec<uint8_t>& enrolledPasswordHandle,
+            const ::android::hardware::hidl_vec<uint8_t>& providedPassword,
+            verify_cb _hidl_cb) override;
+
+    ::android::hardware::Return<void> deleteUser(uint32_t uid, deleteUser_cb _hidl_cb) override;
+
+    ::android::hardware::Return<void> deleteAllUsers(deleteAllUsers_cb _hidl_cb) override;
+
+  private:
+    std::unique_ptr<::gatekeeper::SoftGateKeeper> impl_;
+};
+
+}  // namespace android
+
+#endif  // SOFT_GATEKEEPER_DEVICE_H_
diff --git a/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.rc b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.rc
new file mode 100644
index 0000000..60cb96c
--- /dev/null
+++ b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.rc
@@ -0,0 +1,4 @@
+service vendor.gatekeeper-1-0 /vendor/bin/hw/android.hardware.gatekeeper@1.0-service.software
+    class hal
+    user system
+    group system
diff --git a/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.xml b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.xml
new file mode 100644
index 0000000..19714a8
--- /dev/null
+++ b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.gatekeeper</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+        <name>IGatekeeper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/gatekeeper/1.0/software/service.cpp b/gatekeeper/1.0/software/service.cpp
new file mode 100644
index 0000000..a48a964
--- /dev/null
+++ b/gatekeeper/1.0/software/service.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "android.hardware.gatekeeper@1.0-service"
+
+#include <android-base/logging.h>
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+
+#include <hidl/LegacySupport.h>
+
+#include "SoftGateKeeperDevice.h"
+
+// Generated HIDL files
+using android::SoftGateKeeperDevice;
+using android::hardware::gatekeeper::V1_0::IGatekeeper;
+
+int main() {
+    ::android::hardware::configureRpcThreadpool(1, true /* willJoinThreadpool */);
+    android::sp<SoftGateKeeperDevice> gatekeeper(new SoftGateKeeperDevice());
+    auto status = gatekeeper->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Could not register service for Gatekeeper 1.0 (software) (" << status << ")";
+    }
+
+    android::hardware::joinRpcThreadpool();
+    return -1;  // Should never get here.
+}
diff --git a/gatekeeper/1.0/software/tests/Android.bp b/gatekeeper/1.0/software/tests/Android.bp
new file mode 100644
index 0000000..3f0300d
--- /dev/null
+++ b/gatekeeper/1.0/software/tests/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "gatekeeper-software-device-unit-tests",
+
+    cflags: [
+        "-g",
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+    ],
+    shared_libs: [
+        "libgatekeeper",
+        "libcrypto",
+        "libbase",
+    ],
+    static_libs: ["libscrypt_static"],
+
+    srcs: ["gatekeeper_test.cpp"],
+}
diff --git a/gatekeeper/1.0/software/tests/gatekeeper_test.cpp b/gatekeeper/1.0/software/tests/gatekeeper_test.cpp
new file mode 100644
index 0000000..bf4a8bc
--- /dev/null
+++ b/gatekeeper/1.0/software/tests/gatekeeper_test.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arpa/inet.h>
+#include <iostream>
+
+#include <gtest/gtest.h>
+#include <hardware/hw_auth_token.h>
+
+#include "../SoftGateKeeper.h"
+
+using ::gatekeeper::EnrollRequest;
+using ::gatekeeper::EnrollResponse;
+using ::gatekeeper::secure_id_t;
+using ::gatekeeper::SizedBuffer;
+using ::gatekeeper::SoftGateKeeper;
+using ::gatekeeper::VerifyRequest;
+using ::gatekeeper::VerifyResponse;
+using ::testing::Test;
+
+static SizedBuffer makePasswordBuffer(int init = 0) {
+    constexpr const uint32_t pw_buffer_size = 16;
+    auto pw_buffer = new uint8_t[pw_buffer_size];
+    memset(pw_buffer, init, pw_buffer_size);
+
+    return {pw_buffer, pw_buffer_size};
+}
+
+static SizedBuffer makeAndInitializeSizedBuffer(const uint8_t* data, uint32_t size) {
+    auto buffer = new uint8_t[size];
+    memcpy(buffer, data, size);
+    return {buffer, size};
+}
+
+static SizedBuffer copySizedBuffer(const SizedBuffer& rhs) {
+    return makeAndInitializeSizedBuffer(rhs.Data<uint8_t>(), rhs.size());
+}
+
+static void do_enroll(SoftGateKeeper& gatekeeper, EnrollResponse* response) {
+    EnrollRequest request(0, {}, makePasswordBuffer(), {});
+
+    gatekeeper.Enroll(request, response);
+}
+
+TEST(GateKeeperTest, EnrollSuccess) {
+    SoftGateKeeper gatekeeper;
+    EnrollResponse response;
+    do_enroll(gatekeeper, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+}
+
+TEST(GateKeeperTest, EnrollBogusData) {
+    SoftGateKeeper gatekeeper;
+    EnrollResponse response;
+
+    EnrollRequest request(0, {}, {}, {});
+
+    gatekeeper.Enroll(request, &response);
+
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error);
+}
+
+TEST(GateKeeperTest, VerifySuccess) {
+    SoftGateKeeper gatekeeper;
+    EnrollResponse enroll_response;
+
+    do_enroll(gatekeeper, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+    VerifyRequest request(0, 1, std::move(enroll_response.enrolled_password_handle),
+                          makePasswordBuffer());
+    VerifyResponse response;
+
+    gatekeeper.Verify(request, &response);
+
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+
+    auto auth_token = response.auth_token.Data<hw_auth_token_t>();
+
+    ASSERT_NE(nullptr, auth_token);
+    ASSERT_EQ((uint32_t)HW_AUTH_PASSWORD, ntohl(auth_token->authenticator_type));
+    ASSERT_EQ((uint64_t)1, auth_token->challenge);
+    ASSERT_NE(~((uint32_t)0), auth_token->timestamp);
+    ASSERT_NE((uint64_t)0, auth_token->user_id);
+    ASSERT_NE((uint64_t)0, auth_token->authenticator_id);
+}
+
+TEST(GateKeeperTest, TrustedReEnroll) {
+    SoftGateKeeper gatekeeper;
+    EnrollResponse enroll_response;
+
+    // do_enroll enrolls an all 0 password
+    do_enroll(gatekeeper, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // verify first password
+    VerifyRequest request(0, 0, copySizedBuffer(enroll_response.enrolled_password_handle),
+                          makePasswordBuffer());
+    VerifyResponse response;
+    gatekeeper.Verify(request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    auto auth_token = response.auth_token.Data<hw_auth_token_t>();
+    ASSERT_NE(nullptr, auth_token);
+
+    secure_id_t secure_id = auth_token->user_id;
+
+    // enroll new password
+    EnrollRequest enroll_request(0, std::move(enroll_response.enrolled_password_handle),
+                                 makePasswordBuffer(1) /* new password */,
+                                 makePasswordBuffer() /* old password */);
+    gatekeeper.Enroll(enroll_request, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // verify new password
+    VerifyRequest new_request(0, 0, std::move(enroll_response.enrolled_password_handle),
+                              makePasswordBuffer(1));
+    gatekeeper.Verify(new_request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    ASSERT_NE(nullptr, response.auth_token.Data<hw_auth_token_t>());
+    ASSERT_EQ(secure_id, response.auth_token.Data<hw_auth_token_t>()->user_id);
+}
+
+TEST(GateKeeperTest, UntrustedReEnroll) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer provided_password;
+    EnrollResponse enroll_response;
+
+    // do_enroll enrolls an all 0 password
+    provided_password = makePasswordBuffer();
+    do_enroll(gatekeeper, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // verify first password
+    VerifyRequest request(0, 0, std::move(enroll_response.enrolled_password_handle),
+                          std::move(provided_password));
+    VerifyResponse response;
+    gatekeeper.Verify(request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    auto auth_token = response.auth_token.Data<hw_auth_token_t>();
+    ASSERT_NE(nullptr, auth_token);
+
+    secure_id_t secure_id = auth_token->user_id;
+
+    EnrollRequest enroll_request(0, {}, makePasswordBuffer(1), {});
+    gatekeeper.Enroll(enroll_request, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // verify new password
+    VerifyRequest new_request(0, 0, std::move(enroll_response.enrolled_password_handle),
+                              makePasswordBuffer(1));
+    gatekeeper.Verify(new_request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    ASSERT_NE(nullptr, response.auth_token.Data<hw_auth_token_t>());
+    ASSERT_NE(secure_id, response.auth_token.Data<hw_auth_token_t>()->user_id);
+}
+
+TEST(GateKeeperTest, VerifyBogusData) {
+    SoftGateKeeper gatekeeper;
+    VerifyResponse response;
+
+    VerifyRequest request(0, 0, {}, {});
+
+    gatekeeper.Verify(request, &response);
+
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error);
+}
diff --git a/gatekeeper/1.0/vts/OWNERS b/gatekeeper/1.0/vts/OWNERS
new file mode 100644
index 0000000..738c710
--- /dev/null
+++ b/gatekeeper/1.0/vts/OWNERS
@@ -0,0 +1,3 @@
+jdanis@google.com
+swillden@google.com
+guangzhu@google.com
diff --git a/gatekeeper/1.0/vts/functional/Android.bp b/gatekeeper/1.0/vts/functional/Android.bp
index f55e5d2..a115285 100644
--- a/gatekeeper/1.0/vts/functional/Android.bp
+++ b/gatekeeper/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGatekeeperV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.gatekeeper@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
index 715e9fc..afc737c 100644
--- a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
+++ b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
@@ -24,7 +24,10 @@
 #include <inttypes.h>
 #include <unistd.h>
 
+#include <gtest/gtest.h>
 #include <hardware/hw_auth_token.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <android/log.h>
 #include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
@@ -32,9 +35,6 @@
 
 #include <log/log.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::gatekeeper::V1_0::IGatekeeper;
@@ -78,22 +78,8 @@
   return auth_token;
 }
 
-// Test environment for Gatekeeper HIDL HAL.
-class GatekeeperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static GatekeeperHidlEnvironment* Instance() {
-    static GatekeeperHidlEnvironment* instance = new GatekeeperHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<IGatekeeper>(); }
- private:
-  GatekeeperHidlEnvironment() {}
-};
-
 // The main test class for Gatekeeper HIDL HAL.
-class GatekeeperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class GatekeeperHidlTest : public ::testing::TestWithParam<std::string> {
  protected:
   void setUid(uint32_t uid) { uid_ = uid; }
 
@@ -204,8 +190,7 @@
   GatekeeperHidlTest() : uid_(0) {}
   virtual void SetUp() override {
     GatekeeperResponse rsp;
-    gatekeeper_ = ::testing::VtsHalHidlTargetTestBase::getService<IGatekeeper>(
-        GatekeeperHidlEnvironment::Instance()->getServiceName<IGatekeeper>());
+    gatekeeper_ = IGatekeeper::getService(GetParam());
     ASSERT_NE(nullptr, gatekeeper_.get());
     doDeleteAllUsers(rsp);
   }
@@ -219,7 +204,7 @@
 /**
  * Ensure we can enroll new password
  */
-TEST_F(GatekeeperHidlTest, EnrollSuccess) {
+TEST_P(GatekeeperHidlTest, EnrollSuccess) {
   hidl_vec<uint8_t> password;
   GatekeeperResponse rsp;
   ALOGI("Testing Enroll (expected success)");
@@ -231,7 +216,7 @@
 /**
  * Ensure we can not enroll empty password
  */
-TEST_F(GatekeeperHidlTest, EnrollNoPassword) {
+TEST_P(GatekeeperHidlTest, EnrollNoPassword) {
   hidl_vec<uint8_t> password;
   GatekeeperResponse rsp;
   ALOGI("Testing Enroll (expected failure)");
@@ -242,7 +227,7 @@
 /**
  * Ensure we can successfully verify previously enrolled password
  */
-TEST_F(GatekeeperHidlTest, VerifySuccess) {
+TEST_P(GatekeeperHidlTest, VerifySuccess) {
   GatekeeperResponse enrollRsp;
   GatekeeperResponse verifyRsp;
   hidl_vec<uint8_t> password;
@@ -258,7 +243,7 @@
  * Ensure we can securely update password (keep the same
  * secure user_id) if we prove we know old password
  */
-TEST_F(GatekeeperHidlTest, TrustedReenroll) {
+TEST_P(GatekeeperHidlTest, TrustedReenroll) {
   GatekeeperResponse enrollRsp;
   GatekeeperRequest reenrollReq;
   GatekeeperResponse reenrollRsp;
@@ -297,7 +282,7 @@
  * Ensure we can update password (and get new
  * secure user_id) if we don't know old password
  */
-TEST_F(GatekeeperHidlTest, UntrustedReenroll) {
+TEST_P(GatekeeperHidlTest, UntrustedReenroll) {
   GatekeeperResponse enrollRsp;
   GatekeeperResponse reenrollRsp;
   GatekeeperResponse verifyRsp;
@@ -327,7 +312,7 @@
 /**
  * Ensure we dont get successful verify with invalid data
  */
-TEST_F(GatekeeperHidlTest, VerifyNoData) {
+TEST_P(GatekeeperHidlTest, VerifyNoData) {
   hidl_vec<uint8_t> password;
   hidl_vec<uint8_t> passwordHandle;
   GatekeeperResponse verifyRsp;
@@ -341,7 +326,7 @@
 /**
  * Ensure we can not verify password after we enrolled it and then deleted user
  */
-TEST_F(GatekeeperHidlTest, DeleteUserTest) {
+TEST_P(GatekeeperHidlTest, DeleteUserTest) {
   hidl_vec<uint8_t> password;
   GatekeeperResponse enrollRsp;
   GatekeeperResponse verifyRsp;
@@ -368,7 +353,7 @@
 /**
  * Ensure we can not delete a user that does not exist
  */
-TEST_F(GatekeeperHidlTest, DeleteInvalidUserTest) {
+TEST_P(GatekeeperHidlTest, DeleteInvalidUserTest) {
   hidl_vec<uint8_t> password;
   GatekeeperResponse enrollRsp;
   GatekeeperResponse verifyRsp;
@@ -400,7 +385,7 @@
  * Ensure we can not verify passwords after we enrolled them and then deleted
  * all users
  */
-TEST_F(GatekeeperHidlTest, DeleteAllUsersTest) {
+TEST_P(GatekeeperHidlTest, DeleteAllUsersTest) {
   struct UserData {
     uint32_t userId;
     hidl_vec<uint8_t> password;
@@ -448,11 +433,7 @@
   ALOGI("Testing deleteAllUsers done: rsp=%" PRIi32, delAllRsp.code);
 }
 
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(GatekeeperHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  GatekeeperHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GatekeeperHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGatekeeper::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/gnss/1.0/Android.bp b/gnss/1.0/Android.bp
index 2e3e6fd..d97588c 100644
--- a/gnss/1.0/Android.bp
+++ b/gnss/1.0/Android.bp
@@ -35,4 +35,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/gnss/1.0/default/Android.bp b/gnss/1.0/default/Android.bp
index ca495e6..57d8903 100644
--- a/gnss/1.0/default/Android.bp
+++ b/gnss/1.0/default/Android.bp
@@ -22,7 +22,6 @@
     shared_libs: [
         "liblog",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.gnss@1.0",
         "libhardware",
@@ -47,7 +46,6 @@
         "libhardware",
         "libbinder",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.gnss@1.0",
     ],
 
diff --git a/gnss/1.0/default/Gnss.cpp b/gnss/1.0/default/Gnss.cpp
index 32c131c..7d1cacf 100644
--- a/gnss/1.0/default/Gnss.cpp
+++ b/gnss/1.0/default/Gnss.cpp
@@ -128,20 +128,20 @@
     for (size_t i = 0; i < svStatus.numSvs; i++) {
         auto svInfo = status->gnss_sv_list[i];
         IGnssCallback::GnssSvInfo gnssSvInfo = {
-            .svid = svInfo.svid,
-            .constellation = static_cast<
-                android::hardware::gnss::V1_0::GnssConstellationType>(
-                svInfo.constellation),
-            .cN0Dbhz = svInfo.c_n0_dbhz,
-            .elevationDegrees = svInfo.elevation,
-            .azimuthDegrees = svInfo.azimuth,
-            // Older chipsets do not provide carrier frequency, hence
-            // HAS_CARRIER_FREQUENCY flag and the carrierFrequencyHz fields
-            // are not set. So we are resetting both fields here.
-            .svFlag = static_cast<uint8_t>(
-                svInfo.flags &= ~(static_cast<uint8_t>(
-                    IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY))),
-            .carrierFrequencyHz = 0};
+                .svid = svInfo.svid,
+                .constellation = static_cast<android::hardware::gnss::V1_0::GnssConstellationType>(
+                        svInfo.constellation),
+                .cN0Dbhz = svInfo.c_n0_dbhz,
+                .elevationDegrees = svInfo.elevation,
+                .azimuthDegrees = svInfo.azimuth,
+                .carrierFrequencyHz = 0,
+                // Older chipsets do not provide carrier frequency, hence
+                // HAS_CARRIER_FREQUENCY flag and the carrierFrequencyHz fields
+                // are not set. So we are resetting both fields here.
+                .svFlag = static_cast<uint8_t>(
+                        svInfo.flags &=
+                        ~(static_cast<uint8_t>(IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY))),
+        };
         svStatus.gnssSvList[i] = gnssSvInfo;
     }
 
diff --git a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
index 1a44d34..1300d81 100644
--- a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
+++ b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service
+    interface android.hardware.gnss@1.0::IGnss default
     class hal
     user gps
     group system gps radio
diff --git a/gnss/1.0/vts/functional/Android.bp b/gnss/1.0/vts/functional/Android.bp
index 505cb41..d73b32e 100644
--- a/gnss/1.0/vts/functional/Android.bp
+++ b/gnss/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGnssV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.gnss@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index c26f60a..1a80ecf 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -16,11 +16,11 @@
 
 #define LOG_TAG "VtsHalGnssV1_0TargetTest"
 #include <android/hardware/gnss/1.0/IGnss.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -42,23 +42,8 @@
 bool sAgpsIsPresent = false;  // if SUPL or XTRA assistance available
 bool sSignalIsWeak = false;   // if GNSS signals are weak (e.g. light indoor)
 
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static GnssHidlEnvironment* Instance() {
-    static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
- private:
-  GnssHidlEnvironment() {}
-};
-
 // The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
+class GnssHalTest : public testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
     // Clean between tests
@@ -67,8 +52,7 @@
     info_called_count_ = 0;
     notify_count_ = 0;
 
-    gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
-        GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
+    gnss_hal_ = IGnss::getService(GetParam());
     ASSERT_NE(gnss_hal_, nullptr);
 
     gnss_cb_ = new GnssCallback(*this);
@@ -344,14 +328,14 @@
  * Since this is just the basic operation of SetUp() and TearDown(),
  * the function definition is intentionally empty
  */
-TEST_F(GnssHalTest, SetCallbackCapabilitiesCleanup) {}
+TEST_P(GnssHalTest, SetCallbackCapabilitiesCleanup) {}
 
 /*
  * GetLocation:
  * Turns on location, waits 45 second for at least 5 locations,
  * and checks them for reasonable validity.
  */
-TEST_F(GnssHalTest, GetLocation) {
+TEST_P(GnssHalTest, GetLocation) {
 #define MIN_INTERVAL_MSEC 500
 #define PREFERRED_ACCURACY 0   // Ideally perfect (matches GnssLocationProvider)
 #define PREFERRED_TIME_MSEC 0  // Ideally immediate
@@ -391,7 +375,7 @@
  * InjectDelete:
  * Ensures that calls to inject and/or delete information state are handled.
  */
-TEST_F(GnssHalTest, InjectDelete) {
+TEST_P(GnssHalTest, InjectDelete) {
   // confidently, well north of Alaska
   auto result = gnss_hal_->injectLocation(80.0, -170.0, 1000.0);
 
@@ -424,7 +408,7 @@
  *   null or actual extension, no crash.
  * Confirms year-based required extensions (Measurement & Debug) are present
  */
-TEST_F(GnssHalTest, GetAllExtensions) {
+TEST_P(GnssHalTest, GetAllExtensions) {
   // Basic call-is-handled checks
   auto gnssXtra = gnss_hal_->getExtensionXtra();
   ASSERT_TRUE(gnssXtra.isOk());
@@ -470,7 +454,7 @@
  * MeasurementCapabilities:
  * Verifies that modern hardware supports measurement capabilities.
  */
-TEST_F(GnssHalTest, MeasurementCapabilites) {
+TEST_P(GnssHalTest, MeasurementCapabilites) {
   if (info_called_count_ > 0 && last_info_.yearOfHw >= 2016) {
     EXPECT_TRUE(last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS);
   }
@@ -480,16 +464,19 @@
  * SchedulingCapabilities:
  * Verifies that 2018+ hardware supports Scheduling capabilities.
  */
-TEST_F(GnssHalTest, SchedulingCapabilities) {
+TEST_P(GnssHalTest, SchedulingCapabilities) {
     if (info_called_count_ > 0 && last_info_.yearOfHw >= 2018) {
         EXPECT_TRUE(last_capabilities_ & IGnssCallback::Capabilities::SCHEDULING);
     }
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GnssHalTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 int main(int argc, char** argv) {
-  ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
   ::testing::InitGoogleTest(&argc, argv);
-  GnssHidlEnvironment::Instance()->init(&argc, argv);
   /*
    * These arguments not used by automated VTS testing.
    * Only for use in manual testing, when wanting to run
@@ -502,7 +489,6 @@
         sSignalIsWeak = true;
     }
   }
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
-}
+
+  return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/gnss/1.1/Android.bp b/gnss/1.1/Android.bp
index 4ae4439..5294a6b 100644
--- a/gnss/1.1/Android.bp
+++ b/gnss/1.1/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/gnss/1.1/default/Android.bp b/gnss/1.1/default/Android.bp
index 8c3aac4..95bd7f3 100644
--- a/gnss/1.1/default/Android.bp
+++ b/gnss/1.1/default/Android.bp
@@ -12,7 +12,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "liblog",
         "android.hardware.gnss@1.1",
diff --git a/gnss/1.1/default/android.hardware.gnss@1.1-service.rc b/gnss/1.1/default/android.hardware.gnss@1.1-service.rc
index 0cf7c49..73901bf 100644
--- a/gnss/1.1/default/android.hardware.gnss@1.1-service.rc
+++ b/gnss/1.1/default/android.hardware.gnss@1.1-service.rc
@@ -1,4 +1,6 @@
 service gnss-1-1 /vendor/bin/hw/android.hardware.gnss@1.1-service
+    interface android.hardware.gnss@1.0::IGnss default
+    interface android.hardware.gnss@1.1::IGnss default
     class hal
     user system
     group system
diff --git a/gnss/2.0/Android.bp b/gnss/2.0/Android.bp
index 6cfd346..db5075f 100644
--- a/gnss/2.0/Android.bp
+++ b/gnss/2.0/Android.bp
@@ -30,4 +30,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/gnss/2.0/default/Android.bp b/gnss/2.0/default/Android.bp
index 0fcd764..3ba89da 100644
--- a/gnss/2.0/default/Android.bp
+++ b/gnss/2.0/default/Android.bp
@@ -33,7 +33,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "liblog",
         "android.hardware.gnss@2.0",
diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp
index 93de89c..1f95ff9 100644
--- a/gnss/2.0/default/GnssMeasurement.cpp
+++ b/gnss/2.0/default/GnssMeasurement.cpp
@@ -119,12 +119,13 @@
     V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = {
             .v1_1 = measurement_1_1,
             .codeType = "C",
-            .constellation = GnssConstellationType::GLONASS,
             .state = GnssMeasurementState::STATE_CODE_LOCK | GnssMeasurementState::STATE_BIT_SYNC |
                      GnssMeasurementState::STATE_SUBFRAME_SYNC |
                      GnssMeasurementState::STATE_TOW_DECODED |
                      GnssMeasurementState::STATE_GLO_STRING_SYNC |
-                     GnssMeasurementState::STATE_GLO_TOD_DECODED};
+                     GnssMeasurementState::STATE_GLO_TOD_DECODED,
+            .constellation = GnssConstellationType::GLONASS,
+    };
 
     hidl_vec<IGnssMeasurementCallback::GnssMeasurement> measurements(1);
     measurements[0] = measurement_2_0;
diff --git a/gnss/measurement_corrections/1.0/Android.bp b/gnss/measurement_corrections/1.0/Android.bp
index 456b55c..837cc7a 100644
--- a/gnss/measurement_corrections/1.0/Android.bp
+++ b/gnss/measurement_corrections/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/gnss/visibility_control/1.0/Android.bp b/gnss/visibility_control/1.0/Android.bp
index 40a28c9..e58e932 100644
--- a/gnss/visibility_control/1.0/Android.bp
+++ b/gnss/visibility_control/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/graphics/allocator/2.0/Android.bp b/graphics/allocator/2.0/Android.bp
index 50b474e..37d9dfc 100644
--- a/graphics/allocator/2.0/Android.bp
+++ b/graphics/allocator/2.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/allocator/2.0/default/Android.bp b/graphics/allocator/2.0/default/Android.bp
index 9980ae0..59229b0 100644
--- a/graphics/allocator/2.0/default/Android.bp
+++ b/graphics/allocator/2.0/default/Android.bp
@@ -13,7 +13,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
@@ -31,7 +30,6 @@
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
diff --git a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
index a2a881a..038e87c 100644
--- a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
+++ b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.gralloc-2-0 /vendor/bin/hw/android.hardware.graphics.allocator@2.0-service
+    interface android.hardware.graphics.allocator@2.0::IAllocator default
     class hal animation
     interface android.hardware.graphics.allocator@2.0::IAllocator default
     user system
diff --git a/graphics/allocator/3.0/Android.bp b/graphics/allocator/3.0/Android.bp
index fa3e2ce..2cfa1d0 100644
--- a/graphics/allocator/3.0/Android.bp
+++ b/graphics/allocator/3.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/bufferqueue/1.0/Android.bp b/graphics/bufferqueue/1.0/Android.bp
index e23ca59..7fca354 100644
--- a/graphics/bufferqueue/1.0/Android.bp
+++ b/graphics/bufferqueue/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/graphics/bufferqueue/2.0/Android.bp b/graphics/bufferqueue/2.0/Android.bp
index 97c05fa..fd08079 100644
--- a/graphics/bufferqueue/2.0/Android.bp
+++ b/graphics/bufferqueue/2.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/graphics/common/1.0/Android.bp b/graphics/common/1.0/Android.bp
index 175166d..089fe14 100644
--- a/graphics/common/1.0/Android.bp
+++ b/graphics/common/1.0/Android.bp
@@ -13,4 +13,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/graphics/common/1.1/Android.bp b/graphics/common/1.1/Android.bp
index 0647d12d..899fe03 100644
--- a/graphics/common/1.1/Android.bp
+++ b/graphics/common/1.1/Android.bp
@@ -16,4 +16,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/graphics/common/1.2/Android.bp b/graphics/common/1.2/Android.bp
index 088bc37..2c4d93b 100644
--- a/graphics/common/1.2/Android.bp
+++ b/graphics/common/1.2/Android.bp
@@ -17,4 +17,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/graphics/composer/2.1/Android.bp b/graphics/composer/2.1/Android.bp
index 38786fd..4e4b81c 100644
--- a/graphics/composer/2.1/Android.bp
+++ b/graphics/composer/2.1/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/composer/2.1/default/Android.bp b/graphics/composer/2.1/default/Android.bp
index 63accff..6157719 100644
--- a/graphics/composer/2.1/default/Android.bp
+++ b/graphics/composer/2.1/default/Android.bp
@@ -16,7 +16,6 @@
         "libfmq",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libsync",
         "libutils",
@@ -39,7 +38,6 @@
         "android.hardware.graphics.composer@2.1",
         "libbinder",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libsync",
         "libutils",
diff --git a/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
index 5a5b51e..cbd589a 100644
--- a/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
+++ b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
@@ -1,4 +1,5 @@
 service vendor.hwcomposer-2-1 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service
+    interface android.hardware.graphics.composer@2.1::IComposer default
     class hal animation
     user system
     group graphics drmrpc
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
index 420a1f6..ec7a0b9 100644
--- a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
@@ -20,42 +20,14 @@
     cflags: [
         "-Wall",
         "-Werror",
-        "-Wno-user-defined-warnings",
     ],
     cppflags: [
-        "-Weverything",
+        "-Wextra",
         "-Wunused",
         "-Wunreachable-code",
 
-        // The static constructors and destructors in this library have not been noted to
-        // introduce significant overheads
-        "-Wno-exit-time-destructors",
-        "-Wno-global-constructors",
-
-        // We only care about compiling as C++14
-        "-Wno-c++98-compat-pedantic",
-
-        // android/sensors.h uses nested anonymous unions and anonymous structs
-        "-Wno-nested-anon-types",
-        "-Wno-gnu-anonymous-struct",
-
-        // Don't warn about struct padding
-        "-Wno-padded",
-
-        // hwcomposer2.h features switch covering all cases.
-        "-Wno-covered-switch-default",
-
-        // hwcomposer.h features zero size array.
-        "-Wno-zero-length-array",
-
         // Disabling warning specific to hwc2on1adapter code
-        "-Wno-double-promotion",
-        "-Wno-sign-conversion",
-        "-Wno-switch-enum",
-        "-Wno-float-equal",
-        "-Wno-shorten-64-to-32",
         "-Wno-sign-compare",
-        "-Wno-missing-prototypes",
     ],
 
     srcs: [
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
index 3d138f7..5a75ae1 100644
--- a/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -1389,7 +1389,7 @@
 }
 
 static std::string approximateFloatString(float f) {
-    if (static_cast<int32_t>(f) == f) {
+    if (static_cast<float>(static_cast<int32_t>(f)) == f) {
         return std::to_string(static_cast<int32_t>(f));
     }
     int32_t truncated = static_cast<int32_t>(f * 10);
@@ -1680,10 +1680,10 @@
     if (mAttributes.count(HWC2::Attribute::DpiX) != 0 &&
             mAttributes.at(HWC2::Attribute::DpiX) != -1) {
         std::memset(buffer, 0, BUFFER_SIZE);
-        writtenBytes = snprintf(buffer, BUFFER_SIZE,
-                ", DPI: %.1f x %.1f",
-                mAttributes.at(HWC2::Attribute::DpiX) / 1000.0f,
-                mAttributes.at(HWC2::Attribute::DpiY) / 1000.0f);
+        writtenBytes =
+                snprintf(buffer, BUFFER_SIZE, ", DPI: %.1f x %.1f",
+                         static_cast<float>(mAttributes.at(HWC2::Attribute::DpiX)) / 1000.0f,
+                         static_cast<float>(mAttributes.at(HWC2::Attribute::DpiY)) / 1000.0f);
         output.append(buffer, writtenBytes);
     }
 
diff --git a/graphics/composer/2.2/Android.bp b/graphics/composer/2.2/Android.bp
index fe71e9e..930cadc 100644
--- a/graphics/composer/2.2/Android.bp
+++ b/graphics/composer/2.2/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/composer/2.2/default/Android.mk b/graphics/composer/2.2/default/Android.mk
index 7dedf61..4916557 100644
--- a/graphics/composer/2.2/default/Android.mk
+++ b/graphics/composer/2.2/default/Android.mk
@@ -19,7 +19,6 @@
         libfmq \
         libhardware \
         libhidlbase \
-        libhidltransport \
         libhwc2on1adapter \
         libhwc2onfbadapter \
         liblog \
diff --git a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
index efe6dad..0d7e86f 100644
--- a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
+++ b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
@@ -1,4 +1,6 @@
 service vendor.hwcomposer-2-2 /vendor/bin/hw/android.hardware.graphics.composer@2.2-service
+    interface android.hardware.graphics.composer@2.1::IComposer default
+    interface android.hardware.graphics.composer@2.2::IComposer default
     class hal animation
     user system
     group graphics drmrpc
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 9f7e1cd..a8e70ae 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -26,7 +26,6 @@
     shared_libs: [
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
         "libsync",
     ],
     static_libs: [
diff --git a/graphics/composer/2.3/Android.bp b/graphics/composer/2.3/Android.bp
index 6d29348..a777556 100644
--- a/graphics/composer/2.3/Android.bp
+++ b/graphics/composer/2.3/Android.bp
@@ -20,4 +20,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/composer/2.3/default/Android.bp b/graphics/composer/2.3/default/Android.bp
index 07afd6c..59b9436 100644
--- a/graphics/composer/2.3/default/Android.bp
+++ b/graphics/composer/2.3/default/Android.bp
@@ -36,7 +36,6 @@
         "libfmq",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libhwc2on1adapter",
         "libhwc2onfbadapter",
         "liblog",
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
index 11863fa..e1a870e 100644
--- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -79,6 +79,7 @@
 
     void setLayerPerFrameMetadataBlobs(
         const hidl_vec<IComposerClient::PerFrameMetadataBlob>& metadata) {
+        // in units of uint32_t's
         size_t commandLength = 0;
 
         if (metadata.size() > std::numeric_limits<uint32_t>::max()) {
@@ -86,12 +87,12 @@
             return;
         }
 
-        // number of blobs
-        commandLength += metadata.size();
+        // space for numElements
+        commandLength += 1;
 
         for (auto metadataBlob : metadata) {
-            commandLength += sizeof(int32_t);  // key of metadata blob
-            commandLength += 1;                // size information of metadata blob
+            commandLength += 1;  // key of metadata blob
+            commandLength += 1;  // size information of metadata blob
 
             // metadata content size
             size_t metadataSize = metadataBlob.blob.size() / sizeof(uint32_t);
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index 2766638..e421889 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -23,7 +23,6 @@
     shared_libs: [
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
         "libsync",
     ],
     static_libs: [
diff --git a/graphics/mapper/2.0/Android.bp b/graphics/mapper/2.0/Android.bp
index 96e812b..4459bdc 100644
--- a/graphics/mapper/2.0/Android.bp
+++ b/graphics/mapper/2.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/mapper/2.0/default/Android.bp b/graphics/mapper/2.0/default/Android.bp
index 8874799..4f64184 100644
--- a/graphics/mapper/2.0/default/Android.bp
+++ b/graphics/mapper/2.0/default/Android.bp
@@ -28,7 +28,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libsync",
         "libutils",
diff --git a/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h b/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
index 5ad2a65..8134174 100644
--- a/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
+++ b/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
@@ -80,17 +80,21 @@
     }
 
     Return<Error> freeBuffer(void* buffer) override {
-        native_handle_t* bufferHandle = removeImportedBuffer(buffer);
+        native_handle_t* bufferHandle = getImportedBuffer(buffer);
         if (!bufferHandle) {
             return Error::BAD_BUFFER;
         }
 
-        return mHal->freeBuffer(bufferHandle);
+        Error error = mHal->freeBuffer(bufferHandle);
+        if (error == Error::NONE) {
+            removeImportedBuffer(buffer);
+        }
+        return error;
     }
 
     Return<void> lock(void* buffer, uint64_t cpuUsage, const V2_0::IMapper::Rect& accessRegion,
                       const hidl_handle& acquireFence, IMapper::lock_cb hidl_cb) override {
-        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        const native_handle_t* bufferHandle = getConstImportedBuffer(buffer);
         if (!bufferHandle) {
             hidl_cb(Error::BAD_BUFFER, nullptr);
             return Void();
@@ -112,7 +116,7 @@
     Return<void> lockYCbCr(void* buffer, uint64_t cpuUsage, const V2_0::IMapper::Rect& accessRegion,
                            const hidl_handle& acquireFence,
                            IMapper::lockYCbCr_cb hidl_cb) override {
-        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        const native_handle_t* bufferHandle = getConstImportedBuffer(buffer);
         if (!bufferHandle) {
             hidl_cb(Error::BAD_BUFFER, YCbCrLayout{});
             return Void();
@@ -132,7 +136,7 @@
     }
 
     Return<void> unlock(void* buffer, IMapper::unlock_cb hidl_cb) override {
-        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        const native_handle_t* bufferHandle = getConstImportedBuffer(buffer);
         if (!bufferHandle) {
             hidl_cb(Error::BAD_BUFFER, nullptr);
             return Void();
@@ -160,7 +164,11 @@
         return static_cast<native_handle_t*>(buffer);
     }
 
-    virtual const native_handle_t* getImportedBuffer(void* buffer) const {
+    virtual native_handle_t* getImportedBuffer(void* buffer) const {
+        return static_cast<native_handle_t*>(buffer);
+    }
+
+    virtual const native_handle_t* getConstImportedBuffer(void* buffer) const {
         return static_cast<const native_handle_t*>(buffer);
     }
 
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
index d9beb4f..db7e67d 100644
--- a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
@@ -282,14 +282,16 @@
         }
 
         if (flex.planes[0].component != FLEX_COMPONENT_Y ||
-            flex.planes[1].component != FLEX_COMPONENT_Cb ||
-            flex.planes[2].component != FLEX_COMPONENT_Cr) {
+           ((flex.planes[1].component != FLEX_COMPONENT_Cb || flex.planes[2].component != FLEX_COMPONENT_Cr) &&
+           (flex.planes[2].component != FLEX_COMPONENT_Cb || flex.planes[1].component != FLEX_COMPONENT_Cr))) {
             return false;
         }
 
         const auto& y = flex.planes[0];
-        const auto& cb = flex.planes[1];
-        const auto& cr = flex.planes[2];
+        const auto& cb = (flex.planes[1].component == FLEX_COMPONENT_Cb)?
+                          flex.planes[1] : flex.planes[2];
+        const auto& cr = (flex.planes[2].component == FLEX_COMPONENT_Cr)?
+                          flex.planes[2] : flex.planes[1];
 
         if (cb.h_increment != cr.h_increment || cb.v_increment != cr.v_increment) {
             return false;
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
index e8b1b4b..85a91c3 100644
--- a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
@@ -68,7 +68,14 @@
         return mBufferHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr;
     }
 
-    const native_handle_t* get(void* buffer) {
+    native_handle_t* get(void* buffer) {
+        auto bufferHandle = static_cast<native_handle_t*>(buffer);
+
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mBufferHandles.count(bufferHandle) == 1 ? bufferHandle : nullptr;
+    }
+
+    const native_handle_t* getConst(void* buffer) {
         auto bufferHandle = static_cast<const native_handle_t*>(buffer);
 
         std::lock_guard<std::mutex> lock(mMutex);
@@ -92,9 +99,13 @@
         return GrallocImportedBufferPool::getInstance().remove(buffer);
     }
 
-    const native_handle_t* getImportedBuffer(void* buffer) const override {
+    native_handle_t* getImportedBuffer(void* buffer) const override {
         return GrallocImportedBufferPool::getInstance().get(buffer);
     }
+
+    const native_handle_t* getConstImportedBuffer(void* buffer) const override {
+        return GrallocImportedBufferPool::getInstance().getConst(buffer);
+    }
 };
 
 class GrallocLoader {
diff --git a/graphics/mapper/2.0/utils/vts/MapperVts.cpp b/graphics/mapper/2.0/utils/vts/MapperVts.cpp
index d08ac56..d4e4dde 100644
--- a/graphics/mapper/2.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/2.0/utils/vts/MapperVts.cpp
@@ -16,8 +16,6 @@
 
 #include <mapper-vts/2.0/MapperVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -30,10 +28,10 @@
 }
 
 void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
-    mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+    mAllocator = IAllocator::getService(allocatorServiceName);
     ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
 
-    mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+    mMapper = IMapper::getService(mapperServiceName);
     ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
     ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
 }
diff --git a/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h b/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
index 6c2c9a6..fc8a102 100644
--- a/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
+++ b/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
@@ -22,6 +22,7 @@
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <gtest/gtest.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp
index 853c2a3..a055b61 100644
--- a/graphics/mapper/2.0/vts/functional/Android.bp
+++ b/graphics/mapper/2.0/vts/functional/Android.bp
@@ -24,5 +24,5 @@
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.0-vts",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
index 5ec0af2..b079a4b 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
@@ -20,8 +20,10 @@
 #include <thread>
 #include <vector>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <mapper-vts/2.0/MapperVts.h>
 
 namespace android {
@@ -35,28 +37,12 @@
 using android::hardware::graphics::common::V1_0::BufferUsage;
 using android::hardware::graphics::common::V1_0::PixelFormat;
 
-// Test environment for graphics.mapper.
-class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static GraphicsMapperHidlEnvironment* Instance() {
-        static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<IAllocator>();
-        registerTestService<IMapper>();
-    }
-};
-
-class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class GraphicsMapperHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+  protected:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(
-            mGralloc = std::make_unique<Gralloc>(
-                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
-                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+                                                                     std::get<1>(GetParam())));
 
         mDummyDescriptorInfo.width = 64;
         mDummyDescriptorInfo.height = 64;
@@ -75,14 +61,14 @@
 /**
  * Test IAllocator::dumpDebugInfo by calling it.
  */
-TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
+TEST_P(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
     mGralloc->dumpDebugInfo();
 }
 
 /**
  * Test IAllocator::allocate with valid buffer descriptors.
  */
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
     BufferDescriptor descriptor;
     ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
 
@@ -105,7 +91,7 @@
 /**
  * Test IAllocator::allocate with invalid buffer descriptors.
  */
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
     // this assumes any valid descriptor is non-empty
     BufferDescriptor descriptor;
     mGralloc->getAllocator()->allocate(descriptor, 1,
@@ -117,7 +103,7 @@
 /**
  * Test IAllocator::allocate does not leak.
  */
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
     auto info = mDummyDescriptorInfo;
     info.width = 1024;
     info.height = 1024;
@@ -131,7 +117,7 @@
 /**
  * Test that IAllocator::allocate is thread-safe.
  */
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
     BufferDescriptor descriptor;
     ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
 
@@ -161,14 +147,14 @@
 /**
  * Test IMapper::createDescriptor with valid descriptor info.
  */
-TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorBasic) {
     ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
 }
 
 /**
  * Test IMapper::createDescriptor with invalid descriptor info.
  */
-TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorNegative) {
     auto info = mDummyDescriptorInfo;
     info.width = 0;
     mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
@@ -179,7 +165,7 @@
 /**
  * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
  */
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
     const native_handle_t* bufferHandle;
     ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
     ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
@@ -188,7 +174,7 @@
 /**
  * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
  */
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferClone) {
     const native_handle_t* clonedBufferHandle;
     ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
 
@@ -206,7 +192,7 @@
 /**
  * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
  */
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
     const native_handle_t* rawHandle;
     ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
 
@@ -218,10 +204,8 @@
 
     // free the imported handle with another mapper
     std::unique_ptr<Gralloc> anotherGralloc;
-    ASSERT_NO_FATAL_FAILURE(
-        anotherGralloc = std::make_unique<Gralloc>(
-            GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
-            GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+    ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+                                                                       std::get<1>(GetParam())));
     Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
     ASSERT_EQ(Error::NONE, error);
 
@@ -231,7 +215,7 @@
 /**
  * Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
  */
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
     auto info = mDummyDescriptorInfo;
     info.width = 1024;
     info.height = 1024;
@@ -245,7 +229,7 @@
 /**
  * Test IMapper::importBuffer with invalid buffers.
  */
-TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) {
+TEST_P(GraphicsMapperHidlTest, ImportBufferNegative) {
     native_handle_t* invalidHandle = nullptr;
     mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
         EXPECT_EQ(Error::BAD_BUFFER, tmpError)
@@ -263,7 +247,7 @@
 /**
  * Test IMapper::freeBuffer with invalid buffers.
  */
-TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) {
+TEST_P(GraphicsMapperHidlTest, FreeBufferNegative) {
     native_handle_t* invalidHandle = nullptr;
     Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
     EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER";
@@ -286,7 +270,7 @@
 /**
  * Test IMapper::lock and IMapper::unlock.
  */
-TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) {
+TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) {
     const auto& info = mDummyDescriptorInfo;
 
     const native_handle_t* bufferHandle;
@@ -332,7 +316,7 @@
  * Test IMapper::lockYCbCr.  This locks a YV12 buffer, and makes sure we can
  * write to and read from it.
  */
-TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) {
+TEST_P(GraphicsMapperHidlTest, LockYCbCrBasic) {
     auto info = mDummyDescriptorInfo;
     info.format = PixelFormat::YV12;
 
@@ -391,7 +375,7 @@
 /**
  * Test IMapper::unlock with invalid buffers.
  */
-TEST_F(GraphicsMapperHidlTest, UnlockNegative) {
+TEST_P(GraphicsMapperHidlTest, UnlockNegative) {
     native_handle_t* invalidHandle = nullptr;
     mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
         EXPECT_EQ(Error::BAD_BUFFER, tmpError)
@@ -426,6 +410,14 @@
 #endif
 }
 
+INSTANTIATE_TEST_CASE_P(
+        PerInstance, GraphicsMapperHidlTest,
+        testing::Combine(
+                testing::ValuesIn(
+                        android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+                testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
+        android::hardware::PrintInstanceTupleNameToString<>);
+
 }  // namespace
 }  // namespace vts
 }  // namespace V2_0
@@ -433,13 +425,3 @@
 }  // namespace graphics
 }  // namespace hardware
 }  // namespace android
-
-int main(int argc, char** argv) {
-    using android::hardware::graphics::mapper::V2_0::vts::GraphicsMapperHidlEnvironment;
-    ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
diff --git a/graphics/mapper/2.1/Android.bp b/graphics/mapper/2.1/Android.bp
index 8527d3d..e5a5ae4 100644
--- a/graphics/mapper/2.1/Android.bp
+++ b/graphics/mapper/2.1/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/mapper/2.1/default/Android.bp b/graphics/mapper/2.1/default/Android.bp
index aa204a0..2ea7f94 100644
--- a/graphics/mapper/2.1/default/Android.bp
+++ b/graphics/mapper/2.1/default/Android.bp
@@ -29,7 +29,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libsync",
         "libutils",
diff --git a/graphics/mapper/2.1/utils/vts/Android.bp b/graphics/mapper/2.1/utils/vts/Android.bp
index ca02aad..abbe50a 100644
--- a/graphics/mapper/2.1/utils/vts/Android.bp
+++ b/graphics/mapper/2.1/utils/vts/Android.bp
@@ -16,14 +16,13 @@
 
 cc_library_static {
     name: "android.hardware.graphics.mapper@2.1-vts",
-    defaults: ["hidl_defaults"],
+    defaults: ["hidl_defaults", "VtsHalTargetTestDefaults"],
     srcs: ["MapperVts.cpp"],
     cflags: [
         "-O0",
         "-g",
     ],
     static_libs: [
-        "VtsHalHidlTargetTestBase",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.0-vts",
diff --git a/graphics/mapper/2.1/utils/vts/MapperVts.cpp b/graphics/mapper/2.1/utils/vts/MapperVts.cpp
index 36f9cbb..239de74 100644
--- a/graphics/mapper/2.1/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/2.1/utils/vts/MapperVts.cpp
@@ -16,8 +16,6 @@
 
 #include <mapper-vts/2.1/MapperVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace android {
 namespace hardware {
 namespace graphics {
diff --git a/graphics/mapper/2.1/vts/functional/Android.bp b/graphics/mapper/2.1/vts/functional/Android.bp
index afd8e7f..bb76c74 100644
--- a/graphics/mapper/2.1/vts/functional/Android.bp
+++ b/graphics/mapper/2.1/vts/functional/Android.bp
@@ -26,5 +26,5 @@
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@2.1-vts",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
index 5e7cf93..1185945 100644
--- a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
+++ b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
@@ -16,9 +16,11 @@
 
 #define LOG_TAG "VtsHalGraphicsMapperV2_1TargetTest"
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <mapper-vts/2.1/MapperVts.h>
 
 namespace android {
@@ -34,28 +36,12 @@
 using android::hardware::graphics::common::V1_1::PixelFormat;
 using V2_0::Error;
 
-// Test environment for graphics.mapper.
-class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static GraphicsMapperHidlEnvironment* Instance() {
-        static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<IAllocator>();
-        registerTestService<IMapper>();
-    }
-};
-
-class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class GraphicsMapperHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+  protected:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(
-            mGralloc = std::make_unique<Gralloc>(
-                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
-                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+                                                                     std::get<1>(GetParam())));
 
         mDummyDescriptorInfo.width = 64;
         mDummyDescriptorInfo.height = 64;
@@ -74,7 +60,7 @@
 /**
  * Test that IMapper::validateBufferSize works.
  */
-TEST_F(GraphicsMapperHidlTest, ValidateBufferSizeBasic) {
+TEST_P(GraphicsMapperHidlTest, ValidateBufferSizeBasic) {
     const native_handle_t* bufferHandle;
     uint32_t stride;
     ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true, &stride));
@@ -87,7 +73,7 @@
 /**
  * Test IMapper::validateBufferSize with invalid buffers.
  */
-TEST_F(GraphicsMapperHidlTest, ValidateBufferSizeBadBuffer) {
+TEST_P(GraphicsMapperHidlTest, ValidateBufferSizeBadBuffer) {
     native_handle_t* invalidHandle = nullptr;
     Error ret = mGralloc->getMapper()->validateBufferSize(invalidHandle, mDummyDescriptorInfo,
                                                           mDummyDescriptorInfo.width);
@@ -114,7 +100,7 @@
 /**
  * Test IMapper::validateBufferSize with invalid descriptor and/or stride.
  */
-TEST_F(GraphicsMapperHidlTest, ValidateBufferSizeBadValue) {
+TEST_P(GraphicsMapperHidlTest, ValidateBufferSizeBadValue) {
     auto info = mDummyDescriptorInfo;
     info.width = 1024;
     info.height = 1024;
@@ -161,7 +147,7 @@
 /**
  * Test IMapper::getTransportSize.
  */
-TEST_F(GraphicsMapperHidlTest, GetTransportSizeBasic) {
+TEST_P(GraphicsMapperHidlTest, GetTransportSizeBasic) {
     const native_handle_t* bufferHandle;
     uint32_t numFds;
     uint32_t numInts;
@@ -173,7 +159,7 @@
 /**
  * Test IMapper::getTransportSize with invalid buffers.
  */
-TEST_F(GraphicsMapperHidlTest, GetTransportSizeBadBuffer) {
+TEST_P(GraphicsMapperHidlTest, GetTransportSizeBadBuffer) {
     native_handle_t* invalidHandle = nullptr;
     mGralloc->getMapper()->getTransportSize(
         invalidHandle, [&](const auto& tmpError, const auto&, const auto&) {
@@ -203,14 +189,14 @@
 /**
  * Test IMapper::createDescriptor with valid descriptor info.
  */
-TEST_F(GraphicsMapperHidlTest, CreateDescriptor_2_1Basic) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptor_2_1Basic) {
     ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
 }
 
 /**
  * Test IMapper::createDescriptor with invalid descriptor info.
  */
-TEST_F(GraphicsMapperHidlTest, CreateDescriptor_2_1Negative) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptor_2_1Negative) {
     auto info = mDummyDescriptorInfo;
     info.width = 0;
     mGralloc->getMapper()->createDescriptor_2_1(info, [&](const auto& tmpError, const auto&) {
@@ -218,22 +204,18 @@
     });
 }
 
+INSTANTIATE_TEST_CASE_P(
+        PerInstance, GraphicsMapperHidlTest,
+        testing::Combine(
+                testing::ValuesIn(
+                        android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+                testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
+        android::hardware::PrintInstanceTupleNameToString<>);
+
 }  // namespace
 }  // namespace vts
 }  // namespace V2_1
 }  // namespace mapper
 }  // namespace graphics
 }  // namespace hardware
-}  // namespace android
-
-int main(int argc, char** argv) {
-    using android::hardware::graphics::mapper::V2_1::vts::GraphicsMapperHidlEnvironment;
-    ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
-
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-
-    return status;
-}
+}  // namespace android
\ No newline at end of file
diff --git a/graphics/mapper/3.0/Android.bp b/graphics/mapper/3.0/Android.bp
index e348296..a143243 100644
--- a/graphics/mapper/3.0/Android.bp
+++ b/graphics/mapper/3.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/mapper/3.0/utils/vts/MapperVts.cpp b/graphics/mapper/3.0/utils/vts/MapperVts.cpp
index c94e8db..de886a9 100644
--- a/graphics/mapper/3.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/3.0/utils/vts/MapperVts.cpp
@@ -16,8 +16,6 @@
 
 #include <mapper-vts/3.0/MapperVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -35,19 +33,19 @@
 }
 
 void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
-    mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+    mAllocator = IAllocator::getService(allocatorServiceName);
     ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
 
-    mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+    mMapper = IMapper::getService(mapperServiceName);
     ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
     ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
 }
 
 void Gralloc::initNoErr(const std::string& allocatorServiceName,
                         const std::string& mapperServiceName) {
-    mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+    mAllocator = IAllocator::getService(allocatorServiceName);
 
-    mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+    mMapper = IMapper::getService(mapperServiceName);
     if (mMapper.get()) {
         ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
     }
diff --git a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h
index 1141a88..b2fbebb1 100644
--- a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h
+++ b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h
@@ -22,6 +22,7 @@
 
 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <gtest/gtest.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
diff --git a/graphics/mapper/3.0/vts/functional/Android.bp b/graphics/mapper/3.0/vts/functional/Android.bp
index 77075a5..f01670e 100644
--- a/graphics/mapper/3.0/vts/functional/Android.bp
+++ b/graphics/mapper/3.0/vts/functional/Android.bp
@@ -26,5 +26,5 @@
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@3.0-vts",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
index ff73ecf..92b5994 100644
--- a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
+++ b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
@@ -20,8 +20,10 @@
 #include <thread>
 #include <vector>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <mapper-vts/3.0/MapperVts.h>
 
 namespace android {
@@ -35,28 +37,12 @@
 using android::hardware::graphics::common::V1_2::BufferUsage;
 using android::hardware::graphics::common::V1_2::PixelFormat;
 
-// Test environment for graphics.mapper.
-class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static GraphicsMapperHidlEnvironment* Instance() {
-        static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<IAllocator>();
-        registerTestService<IMapper>();
-    }
-};
-
-class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class GraphicsMapperHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+  protected:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(
-            mGralloc = std::make_unique<Gralloc>(
-                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
-                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+                                                                     std::get<1>(GetParam())));
 
         mDummyDescriptorInfo.width = 64;
         mDummyDescriptorInfo.height = 64;
@@ -75,14 +61,14 @@
 /**
  * Test IAllocator::dumpDebugInfo by calling it.
  */
-TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
+TEST_P(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
     mGralloc->dumpDebugInfo();
 }
 
 /**
  * Test IAllocator::allocate with valid buffer descriptors.
  */
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
     BufferDescriptor descriptor;
     ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
 
@@ -105,7 +91,7 @@
 /**
  * Test IAllocator::allocate with invalid buffer descriptors.
  */
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
     // this assumes any valid descriptor is non-empty
     BufferDescriptor descriptor;
     mGralloc->getAllocator()->allocate(descriptor, 1,
@@ -117,7 +103,7 @@
 /**
  * Test IAllocator::allocate does not leak.
  */
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
     auto info = mDummyDescriptorInfo;
     info.width = 1024;
     info.height = 1024;
@@ -131,7 +117,7 @@
 /**
  * Test that IAllocator::allocate is thread-safe.
  */
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
     BufferDescriptor descriptor;
     ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
 
@@ -161,14 +147,14 @@
 /**
  * Test IMapper::createDescriptor with valid descriptor info.
  */
-TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorBasic) {
     ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
 }
 
 /**
  * Test IMapper::createDescriptor with invalid descriptor info.
  */
-TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorNegative) {
     auto info = mDummyDescriptorInfo;
     info.width = 0;
     mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
@@ -179,7 +165,7 @@
 /**
  * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
  */
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
     const native_handle_t* bufferHandle;
     ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
     ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
@@ -188,7 +174,7 @@
 /**
  * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
  */
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferClone) {
     const native_handle_t* clonedBufferHandle;
     ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
 
@@ -206,7 +192,7 @@
 /**
  * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
  */
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
     const native_handle_t* rawHandle;
     ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
 
@@ -218,10 +204,8 @@
 
     // free the imported handle with another mapper
     std::unique_ptr<Gralloc> anotherGralloc;
-    ASSERT_NO_FATAL_FAILURE(
-        anotherGralloc = std::make_unique<Gralloc>(
-            GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
-            GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+    ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+                                                                       std::get<1>(GetParam())));
     Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
     ASSERT_EQ(Error::NONE, error);
 
@@ -231,7 +215,7 @@
 /**
  * Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
  */
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
     auto info = mDummyDescriptorInfo;
     info.width = 1024;
     info.height = 1024;
@@ -245,7 +229,7 @@
 /**
  * Test IMapper::importBuffer with invalid buffers.
  */
-TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) {
+TEST_P(GraphicsMapperHidlTest, ImportBufferNegative) {
     native_handle_t* invalidHandle = nullptr;
     mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
         EXPECT_EQ(Error::BAD_BUFFER, tmpError)
@@ -263,7 +247,7 @@
 /**
  * Test IMapper::freeBuffer with invalid buffers.
  */
-TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) {
+TEST_P(GraphicsMapperHidlTest, FreeBufferNegative) {
     native_handle_t* invalidHandle = nullptr;
     Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
     EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER";
@@ -286,7 +270,7 @@
 /**
  * Test IMapper::lock and IMapper::unlock.
  */
-TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) {
+TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) {
     const auto& info = mDummyDescriptorInfo;
 
     const native_handle_t* bufferHandle;
@@ -346,7 +330,7 @@
  * Test IMapper::lockYCbCr.  This locks a YV12 buffer, and makes sure we can
  * write to and read from it.
  */
-TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) {
+TEST_P(GraphicsMapperHidlTest, LockYCbCrBasic) {
     auto info = mDummyDescriptorInfo;
     info.format = PixelFormat::YV12;
 
@@ -405,7 +389,7 @@
 /**
  * Test IMapper::unlock with invalid buffers.
  */
-TEST_F(GraphicsMapperHidlTest, UnlockNegative) {
+TEST_P(GraphicsMapperHidlTest, UnlockNegative) {
     native_handle_t* invalidHandle = nullptr;
     mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
         EXPECT_EQ(Error::BAD_BUFFER, tmpError)
@@ -443,7 +427,7 @@
 /**
  * Test IMapper::isSupported with required format RGBA_8888
  */
-TEST_F(GraphicsMapperHidlTest, IsSupportedRGBA8888) {
+TEST_P(GraphicsMapperHidlTest, IsSupportedRGBA8888) {
     const auto& info = mDummyDescriptorInfo;
     bool supported = false;
 
@@ -454,7 +438,7 @@
 /**
  * Test IMapper::isSupported with required format YV12
  */
-TEST_F(GraphicsMapperHidlTest, IsSupportedYV12) {
+TEST_P(GraphicsMapperHidlTest, IsSupportedYV12) {
     auto info = mDummyDescriptorInfo;
     info.format = PixelFormat::YV12;
     bool supported = false;
@@ -466,7 +450,7 @@
 /**
  * Test IMapper::isSupported with optional format Y16
  */
-TEST_F(GraphicsMapperHidlTest, IsSupportedY16) {
+TEST_P(GraphicsMapperHidlTest, IsSupportedY16) {
     auto info = mDummyDescriptorInfo;
     info.format = PixelFormat::Y16;
     bool supported = false;
@@ -474,6 +458,14 @@
     ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
 }
 
+INSTANTIATE_TEST_CASE_P(
+        PerInstance, GraphicsMapperHidlTest,
+        testing::Combine(
+                testing::ValuesIn(
+                        android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+                testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
+        android::hardware::PrintInstanceTupleNameToString<>);
+
 }  // namespace
 }  // namespace vts
 }  // namespace V3_0
@@ -481,13 +473,3 @@
 }  // namespace graphics
 }  // namespace hardware
 }  // namespace android
-
-int main(int argc, char** argv) {
-    using android::hardware::graphics::mapper::V3_0::vts::GraphicsMapperHidlEnvironment;
-    ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
diff --git a/health/1.0/Android.bp b/health/1.0/Android.bp
index e03b142..ea6b0c8 100644
--- a/health/1.0/Android.bp
+++ b/health/1.0/Android.bp
@@ -16,4 +16,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/health/1.0/default/Android.bp b/health/1.0/default/Android.bp
index 8fbb8c3..7581335 100644
--- a/health/1.0/default/Android.bp
+++ b/health/1.0/default/Android.bp
@@ -12,10 +12,61 @@
     shared_libs: [
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.health@1.0",
     ],
 
 }
 
+cc_library_static {
+    name: "android.hardware.health@1.0-impl-helper",
+    vendor: true,
+    srcs: ["Health.cpp"],
+
+    header_libs: [
+        "libbase_headers",
+        "libhealthd_headers",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.health@1.0",
+    ],
+
+    static_libs: [
+        "android.hardware.health@1.0-convert",
+    ],
+}
+
+cc_library_shared {
+    name: "android.hardware.health@1.0-impl",
+    vendor: true,
+    relative_install_path: "hw",
+
+    static_libs: [
+        "android.hardware.health@1.0-impl-helper",
+        "android.hardware.health@1.0-convert",
+        "libhealthd.default",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.health@1.0-service",
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.health@1.0-service.rc"],
+    srcs: ["HealthService.cpp"],
+
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libdl",
+        "libbase",
+        "libutils",
+        "libhidlbase",
+        "android.hardware.health@1.0",
+    ],
+}
diff --git a/health/1.0/default/Android.mk b/health/1.0/default/Android.mk
deleted file mode 100644
index 199ab41..0000000
--- a/health/1.0/default/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.health@1.0-impl
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_C_INCLUDES := system/core/base/include
-LOCAL_SRC_FILES := \
-    Health.cpp \
-
-LOCAL_HEADER_LIBRARIES := libhealthd_headers
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libhidlbase \
-    libhidltransport \
-    liblog \
-    libutils \
-    android.hardware.health@1.0 \
-
-LOCAL_STATIC_LIBRARIES := android.hardware.health@1.0-convert
-
-LOCAL_HAL_STATIC_LIBRARIES := libhealthd
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_MODULE := android.hardware.health@1.0-service
-LOCAL_INIT_RC := android.hardware.health@1.0-service.rc
-LOCAL_SRC_FILES := \
-    HealthService.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-    liblog \
-    libcutils \
-    libdl \
-    libbase \
-    libutils \
-    libhidlbase \
-    libhidltransport \
-    android.hardware.health@1.0 \
-
-include $(BUILD_EXECUTABLE)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/health/1.0/default/README.md b/health/1.0/default/README.md
new file mode 100644
index 0000000..1ded7de
--- /dev/null
+++ b/health/1.0/default/README.md
@@ -0,0 +1,66 @@
+# Implement the 2.1 HAL instead!
+
+It is strongly recommended that you implement the 2.1 HAL directly. See
+`hardware/interfaces/health/2.1/README.md` for more details.
+
+# Implement Health 1.0 HAL
+
+1. Install common binderized service. The binderized service `dlopen()`s
+   passthrough implementations on the device, so there is no need to write
+   your own.
+
+    ```mk
+    # Install default binderized implementation to vendor.
+    PRODUCT_PACKAGES += android.hardware.health@1.0-service
+    ```
+
+1. Add proper VINTF manifest entry to your device manifest. Example:
+
+    ```xml
+    <hal format="hidl">
+        <name>android.hardware.health</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IHealth</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    ```
+
+1. Install the proper passthrough implemetation.
+
+    1. If you want to use the default implementation (with default `libhealthd`),
+       add the following to `device.mk`:
+
+        ```mk
+        PRODUCT_PACKAGES += \
+            android.hardware.health@1.0-impl
+        ```
+
+    1. Otherwise, if you have a customized `libhealthd.<board>`:
+
+        1. Define your passthrough implementation. Example (replace `<device>`
+           and `<board>` accordingly):
+
+            ```bp
+            cc_library_shared {
+                name: "android.hardware.health@1.0-impl-<device>",
+                vendor: true,
+                relative_install_path: "hw",
+
+                static_libs: [
+                    "android.hardware.health@1.0-impl-helper",
+                    "android.hardware.health@1.0-convert",
+                    "libhealthd.<board>",
+                ],
+            }
+            ```
+
+        1. Add to `device.mk`.
+
+            ```
+            PRODUCT_PACKAGES += android.hardware.health@1.0-impl-<device>
+            ```
+
+        1. Define appropriate SELinux permissions.
diff --git a/health/1.0/vts/functional/Android.bp b/health/1.0/vts/functional/Android.bp
index c14dcee..be2d206 100644
--- a/health/1.0/vts/functional/Android.bp
+++ b/health/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalHealthV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.health@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp b/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
index 335d15d..b985a9f 100644
--- a/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
+++ b/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
@@ -18,11 +18,11 @@
 
 #include <android/hardware/health/1.0/IHealth.h>
 #include <android/hardware/health/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 using HealthConfig = ::android::hardware::health::V1_0::HealthConfig;
 using HealthInfo = ::android::hardware::health::V1_0::HealthInfo;
 using IHealth = ::android::hardware::health::V1_0::IHealth;
@@ -30,25 +30,10 @@
 
 using ::android::sp;
 
-// Test environment for Health HIDL HAL.
-class HealthHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static HealthHidlEnvironment* Instance() {
-        static HealthHidlEnvironment* instance = new HealthHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IHealth>(); }
-   private:
-    HealthHidlEnvironment() {}
-};
-
-class HealthHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class HealthHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        health = ::testing::VtsHalHidlTargetTestBase::getService<IHealth>(
-            HealthHidlEnvironment::Instance()->getServiceName<IHealth>());
+        health = IHealth::getService(GetParam());
         ASSERT_NE(health, nullptr);
         health->init(config,
                      [&](const auto& halConfigOut) { config = halConfigOut; });
@@ -61,7 +46,7 @@
 /**
  * Ensure EnergyCounter call returns positive energy counter or NOT_SUPPORTED
  */
-TEST_F(HealthHidlTest, TestEnergyCounter) {
+TEST_P(HealthHidlTest, TestEnergyCounter) {
     Result result;
     int64_t energy = 0;
     health->energyCounter([&](Result ret, int64_t energyOut) {
@@ -73,11 +58,7 @@
     ASSERT_TRUE(result != Result::SUCCESS || energy > 0);
 }
 
-int main(int argc, char **argv) {
-    ::testing::AddGlobalTestEnvironment(HealthHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    HealthHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, HealthHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/health/2.0/Android.bp b/health/2.0/Android.bp
index f472b27..b8323b6 100644
--- a/health/2.0/Android.bp
+++ b/health/2.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/health/2.0/README.md b/health/2.0/README.md
index 58ea9e3..8a7c922 100644
--- a/health/2.0/README.md
+++ b/health/2.0/README.md
@@ -1,3 +1,8 @@
+# Implement the 2.1 HAL instead!
+
+It is strongly recommended that you implement the 2.1 HAL directly. See
+`hardware/interfaces/health/2.1/README.md` for more details.
+
 # Upgrading from Health 1.0 HAL
 
 1. Remove `android.hardware.health@1.0*` from `PRODUCT_PACKAGES`
@@ -44,7 +49,6 @@
             "libbase",
             "libcutils",
             "libhidlbase",
-            "libhidltransport",
             "libutils",
             "android.hardware.health@2.0",
         ],
diff --git a/health/2.0/default/Android.bp b/health/2.0/default/Android.bp
index a85a704..3c5877e 100644
--- a/health/2.0/default/Android.bp
+++ b/health/2.0/default/Android.bp
@@ -10,8 +10,6 @@
     shared_libs: [
         "libbase",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
         "libcutils",
@@ -33,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..4225fd8 100644
--- a/health/2.0/default/Health.cpp
+++ b/health/2.0/default/Health.cpp
@@ -17,11 +17,15 @@
 #include <android-base/logging.h>
 
 #include <android-base/file.h>
+#include <android/hardware/health/2.0/types.h>
 #include <health2/Health.h>
 
 #include <hal_conversion.h>
 #include <hidl/HidlTransportSupport.h>
 
+using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
+
 extern void healthd_battery_update_internal(bool);
 
 namespace android {
@@ -148,7 +152,16 @@
 
     // Retrieve all information and call healthd_mode_ops->battery_update, which calls
     // notifyListeners.
-    bool chargerOnline = battery_monitor_->update();
+    battery_monitor_->updateValues();
+    const HealthInfo_1_0& health_info = battery_monitor_->getHealthInfo_1_0();
+    struct BatteryProperties props;
+    convertFromHealthInfo(health_info, &props);
+    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);
@@ -246,10 +259,7 @@
     using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
 
     updateAndNotify(nullptr);
-    struct android::BatteryProperties p = getBatteryProperties(battery_monitor_.get());
-
-    V1_0::HealthInfo batteryInfo;
-    convertToHealthInfo(&p, batteryInfo);
+    HealthInfo healthInfo = battery_monitor_->getHealthInfo_2_0();
 
     std::vector<StorageInfo> info;
     get_storage_info(info);
@@ -265,8 +275,6 @@
         currentAvg = static_cast<int32_t>(prop.valueInt64);
     }
 
-    V2_0::HealthInfo healthInfo = {};
-    healthInfo.legacy = std::move(batteryInfo);
     healthInfo.batteryCurrentAverage = currentAvg;
     healthInfo.diskStats = stats;
     healthInfo.storageInfos = info;
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..0b5d869
--- /dev/null
+++ b/health/2.0/default/healthd_common_adapter.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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) {
+    if (!health_loop) return -1;
+
+    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) {
+    if (!health_loop) return;
+    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.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
index 74fe4fb..6e13a98 100644
--- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
+++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
@@ -257,15 +257,21 @@
     using V1_0::BatteryStatus;
     using V1_0::BatteryHealth;
 
-    if (!((health_info.legacy.batteryChargeCounter > 0) &&
-          (health_info.legacy.batteryCurrent != INT32_MIN) &&
+    if (!((health_info.legacy.batteryCurrent != INT32_MIN) &&
           (0 <= health_info.legacy.batteryLevel && health_info.legacy.batteryLevel <= 100) &&
           verifyEnum<BatteryHealth>(health_info.legacy.batteryHealth) &&
-          (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN) &&
           verifyEnum<BatteryStatus>(health_info.legacy.batteryStatus))) {
         return false;
     }
 
+    if (health_info.legacy.batteryPresent) {
+        // If a battery is present, the battery status must be known.
+        if (!((health_info.legacy.batteryChargeCounter > 0) &&
+              (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN))) {
+            return false;
+        }
+    }
+
     return true;
 }
 
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/README.md b/health/2.1/README.md
new file mode 100644
index 0000000..5a19d7b
--- /dev/null
+++ b/health/2.1/README.md
@@ -0,0 +1,245 @@
+# Implementing Health 2.1 HAL
+
+1. Install common binderized service. The binderized service `dlopen()`s
+   passthrough implementations on the device, so there is no need to write
+   your own.
+
+    ```mk
+    # Install default binderized implementation to vendor.
+    PRODUCT_PACKAGES += android.hardware.health@2.1-service
+    ```
+
+1. Delete existing VINTF manifest entry. Search for `android.hardware.health` in
+   your device manifest, and delete the whole `<hal>` entry for older versions
+   of the HAL. Instead, when `android.hardware.health@2.1-service` is installed,
+   a VINTF manifest fragment is installed to `/vendor/etc/vintf`, so there is
+   no need to manually specify it in your device manifest. See
+   [Manifest fragments](https://source.android.com/devices/architecture/vintf/objects#manifest-fragments)
+   for details.
+
+1. Install the proper passthrough implemetation.
+
+    1. If you want to use default implementation:
+
+        ```mk
+        # Install default passthrough implementation to vendor.
+        PRODUCT_PACKAGES += android.hardware.health@2.1-impl
+        ```
+
+        You are done. Otherwise, go to the next step.
+
+    1. If you want to write your own implementation,
+
+        1. Copy skeleton implementation from the [appendix](#impl).
+
+        1. Modify the implementation to suit your needs.
+
+            * If you have a board or device specific `libhealthd`, see
+              [Upgrading with  a customized libhealthd](#update-from-1-0).
+            * If you are upgrading from 1.0 health HAL, see
+              [Upgrading from Health HAL 1.0](#update-from-1-0).
+            * If you are upgrading from a customized 2.0 health HAL
+              implementation, See
+              [Upgrading from Health HAL 2.0](#update-from-2-0).
+
+        1. [Update necessary SELinux permissions](#selinux).
+
+        1. [Fix `/charger` symlink](#charger-symlink).
+
+# Upgrading with a customized libhealthd or from Health HAL 1.0 {#update-from-1-0}
+
+`libhealthd` contains two functions: `healthd_board_init()` and
+`healthd_board_battery_update()`. Similarly, Health HAL 1.0 contains `init()`
+and `update()`, with an additional `energyCounter()` function.
+
+* `healthd_board_init()` / `@1.0::IHealth.init()` should be called before
+  passing the `healthd_config` struct to your `HealthImpl` class. See
+  `HIDL_FETCH_IHealth` in [`HealthImpl.cpp`](#health_impl_cpp).
+
+* `healthd_board_battery_update()` / `@1.0::IHealth.update()` should be called
+  in `HealthImpl::UpdateHealthInfo()`. Example:
+
+  ```c++
+  void HealthImpl::UpdateHealthInfo(HealthInfo* health_info) {
+      struct BatteryProperties props;
+      convertFromHealthInfo(health_info->legacy.legacy, &props);
+      healthd_board_battery_update(&props);
+      convertToHealthInfo(&props, health_info->legacy.legacy);
+  }
+  ```
+  For efficiency, you should move code in `healthd_board_battery_update` to
+  `HealthImpl::UpdateHealthInfo` and modify `health_info` directly to avoid
+  conversion to `BatteryProperties`.
+
+* Code for `@1.0::IHealth.energyCounter()` should be moved to
+  `HealthImpl::getEnergyCounter()`. Example:
+
+  ```c++
+  Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
+      int64_t energy = /* ... */;
+      _hidl_cb(Result::SUCCESS, energy);
+      return Void();
+  }
+  ```
+
+# Upgrading from Health HAL 2.0 {#update-from-2-0}
+
+* If you have implemented `healthd_board_init()` and/or
+  `healthd_board_battery_update()` (instead of using `libhealthd.default`),
+  see [the section above](#update-from-1-0)
+  for instructions to convert them.
+
+* If you have implemented `get_storage_info()` and/or `get_disk_stats()`
+  (instead of using libhealthstoragedefault), implement `HealthImpl::getDiskStats`
+  and/or `HealthImpl::getStorageInfo` directly. There is no need to override
+  `HealthImpl::getHealthInfo` or `HealthImpl::getHealthInfo_2_1` because they call
+  `getDiskStats` and `getStorageInfo` to retrieve storage information.
+
+# Update necessary SELinux permissions {#selinux}
+
+For example (replace `<device>` with the device name):
+```
+# device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
+# Add device specific permissions to hal_health_default domain, especially
+# if a device-specific libhealthd is used and/or device-specific storage related
+# APIs are implemented.
+```
+
+# Fix `/charger` symlink {#charger-symlink}
+If you are using `/charger` in your `init.rc` scripts, it is recommended
+(required for devices running in Android R) that the path is changed to
+`/system/bin/charger` instead.
+
+Search for `service charger` in your device configuration directory to see if
+this change applies to your device. Below is an example of how the script should
+look like:
+
+```
+service charger /system/bin/charger
+    class charger
+    user system
+    group system wakelock input
+    capabilities SYS_BOOT
+    file /dev/kmsg w
+    file /sys/fs/pstore/console-ramoops-0 r
+    file /sys/fs/pstore/console-ramoops r
+    file /proc/last_kmsg r
+```
+
+# Appendix: sample code for the implementation {#impl}
+
+## `device/<manufacturer>/<device>/health/Android.bp` {#android_bp}
+
+```bp
+cc_library_shared {
+    name: "android.hardware.health@2.1-impl-<device>",
+    stem: "android.hardware.health@2.0-impl-2.1-<device>",
+
+    // Install to vendor and recovery.
+    proprietary: true,
+    recovery_available: true,
+
+    relative_install_path: "hw",
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.health@2.1",
+        "android.hardware.health@2.0",
+    ],
+
+    static_libs: [
+        "android.hardware.health@1.0-convert",
+        "libbatterymonitor",
+        "libhealthloop",
+        "libhealth2impl",
+        // "libhealthd.<device>"
+    ],
+
+    srcs: [
+        "HealthImpl.cpp",
+    ],
+
+    // No vintf_fragments because both -impl and -service should have been
+    // installed.
+}
+```
+
+## `device/<manufacturer>/<device>/health/HealthImpl.cpp` {#health_impl_cpp}
+
+```c++
+#include <memory>
+#include <string_view>
+
+#include <health/utils.h>
+#include <health2impl/Health.h>
+#include <hidl/Status.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::health::InitHealthdConfig;
+using ::android::hardware::health::V2_1::IHealth;
+using ::android::hidl::base::V1_0::IBase;
+
+using namespace std::literals;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// android::hardware::health::V2_1::implementation::Health implements most
+// defaults. Uncomment functions that you need to override.
+class HealthImpl : public Health {
+  public:
+    HealthImpl(std::unique_ptr<healthd_config>&& config)
+        : Health(std::move(config)) {}
+
+    // A subclass can override this if these information should be retrieved
+    // differently.
+    // Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
+    // Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
+    // Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
+    // Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
+    // Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
+    // Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
+    // Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
+    // Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
+    // Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
+
+    // Functions introduced in Health HAL 2.1.
+    // Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override;
+    // Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override;
+    // Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override;
+
+  protected:
+    // A subclass can override this to modify any health info object before
+    // returning to clients. This is similar to healthd_board_battery_update().
+    // By default, it does nothing.
+    // void UpdateHealthInfo(HealthInfo* health_info) override;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
+
+extern "C" IHealth* HIDL_FETCH_IHealth(const char* instance) {
+    using ::android::hardware::health::V2_1::implementation::HealthImpl;
+    if (instance != "default"sv) {
+        return nullptr;
+    }
+    auto config = std::make_unique<healthd_config>();
+    InitHealthdConfig(config.get());
+
+    // healthd_board_init(config.get());
+
+    return new HealthImpl(std::move(config));
+}
+```
diff --git a/health/2.1/default/Android.bp b/health/2.1/default/Android.bp
new file mode 100644
index 0000000..3649853
--- /dev/null
+++ b/health/2.1/default/Android.bp
@@ -0,0 +1,81 @@
+// 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_defaults {
+    name: "android.hardware.health@2.1-impl-defaults",
+    relative_install_path: "hw",
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.health@2.1",
+        "android.hardware.health@2.0",
+    ],
+
+    static_libs: [
+        "android.hardware.health@1.0-convert",
+        "libbatterymonitor",
+        "libhealthloop",
+        "libhealth2impl",
+    ],
+}
+
+// Default passthrough implementation of the health@2.1 HAL.
+// Passhtrough implementations of the health@2.1 HAL must be installed in
+// vendor in order to support charger.
+// Passhtrough implementations of the health@2.1 HAL must be installed in
+// recovery in order to allow recovery to check battery status.
+// See README.md for details.
+cc_library_shared {
+    name: "android.hardware.health@2.1-impl",
+    stem: "android.hardware.health@2.0-impl-2.1",
+
+    // Only vendor and recovery variants are allowed, not core.
+    vendor: true,
+    recovery_available: true,
+
+    defaults: ["android.hardware.health@2.1-impl-defaults"],
+
+    srcs: [
+        "impl.cpp",
+    ],
+
+    // No vintf_fragments because both -impl and -service should have been
+    // installed.
+}
+
+// Default binderized service of the health@2.1 HAL.
+// This binderized implementation dlopen()s the passthrough implementation,
+// so there is no need to implement your own.
+cc_binary {
+    name: "android.hardware.health@2.1-service",
+    vendor: true,
+    defaults: ["android.hardware.health@2.1-impl-defaults"],
+    init_rc: ["android.hardware.health@2.1-service.rc"],
+
+    srcs: [
+        "service.cpp",
+    ],
+
+    vintf_fragments: [
+        "android.hardware.health@2.1.xml"
+    ],
+
+    overrides: [
+        "healthd",
+    ],
+}
diff --git a/health/2.1/default/android.hardware.health@2.1-service.rc b/health/2.1/default/android.hardware.health@2.1-service.rc
new file mode 100644
index 0000000..917f1c2
--- /dev/null
+++ b/health/2.1/default/android.hardware.health@2.1-service.rc
@@ -0,0 +1,6 @@
+service health-hal-2-1 /vendor/bin/hw/android.hardware.health@2.1-service
+    class hal
+    user system
+    group system
+    capabilities WAKE_ALARM
+    file /dev/kmsg w
diff --git a/health/2.1/default/android.hardware.health@2.1.xml b/health/2.1/default/android.hardware.health@2.1.xml
new file mode 100644
index 0000000..34fdca6
--- /dev/null
+++ b/health/2.1/default/android.hardware.health@2.1.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.health</name>
+        <transport>hwbinder</transport>
+        <fqname>@2.1::IHealth/default</fqname>
+    </hal>
+</manifest>
diff --git a/health/2.1/default/impl.cpp b/health/2.1/default/impl.cpp
new file mode 100644
index 0000000..7389a21
--- /dev/null
+++ b/health/2.1/default/impl.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 <memory>
+#include <string_view>
+
+#include <health/utils.h>
+#include <health2impl/Health.h>
+
+using ::android::sp;
+using ::android::hardware::health::InitHealthdConfig;
+using ::android::hardware::health::V2_1::IHealth;
+using ::android::hardware::health::V2_1::implementation::Health;
+
+using namespace std::literals;
+
+// Passthrough implementation of the health service. Use default configuration.
+// It does not invoke callbacks unless update() is called explicitly. No
+// background thread is spawned to handle callbacks.
+//
+// The passthrough implementation is only allowed in recovery mode, charger, and
+// opened by the hwbinder service.
+// If Android is booted normally, the hwbinder service is used instead.
+//
+// This implementation only implements the "default" instance. It rejects
+// other instance names.
+// Note that the Android framework only reads values from the "default"
+// health HAL 2.1 instance.
+extern "C" IHealth* HIDL_FETCH_IHealth(const char* instance) {
+    if (instance != "default"sv) {
+        return nullptr;
+    }
+    auto config = std::make_unique<healthd_config>();
+    InitHealthdConfig(config.get());
+
+    // This implementation uses default config. If you want to customize it
+    // (e.g. with healthd_board_init), do it here.
+
+    return new Health(std::move(config));
+}
diff --git a/health/2.1/default/service.cpp b/health/2.1/default/service.cpp
new file mode 100644
index 0000000..f8334c5
--- /dev/null
+++ b/health/2.1/default/service.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "android.hardware.health@2.1-service"
+
+#include <android-base/logging.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <health2impl/BinderHealth.h>
+
+using ::android::sp;
+using ::android::hardware::health::V2_1::IHealth;
+using ::android::hardware::health::V2_1::implementation::BinderHealth;
+using IHealth_2_0 = ::android::hardware::health::V2_0::IHealth;
+
+static constexpr const char* gInstanceName = "default";
+
+int main(int /* argc */, char* /* argv */[]) {
+    sp<IHealth> passthrough =
+            IHealth::castFrom(IHealth_2_0::getService(gInstanceName, true /* getStub */));
+    CHECK(passthrough != nullptr)
+            << "Cannot find passthrough implementation of health 2.1 HAL for instance "
+            << gInstanceName;
+    sp<BinderHealth> binder = new BinderHealth(gInstanceName, passthrough);
+    return binder->StartLoop();
+}
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..da9f5bb
--- /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(
+        PerInstance, 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/storage/1.0/Android.bp b/health/storage/1.0/Android.bp
index 45fa01f..e4620f8 100644
--- a/health/storage/1.0/Android.bp
+++ b/health/storage/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/health/storage/1.0/default/Android.bp b/health/storage/1.0/default/Android.bp
index 4723443..3156dfe 100644
--- a/health/storage/1.0/default/Android.bp
+++ b/health/storage/1.0/default/Android.bp
@@ -33,7 +33,6 @@
     shared_libs: [
         "libbase",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.health.storage@1.0",
     ],
diff --git a/health/storage/1.0/default/service.cpp b/health/storage/1.0/default/service.cpp
index f4296f1..6f6ebc8 100644
--- a/health/storage/1.0/default/service.cpp
+++ b/health/storage/1.0/default/service.cpp
@@ -32,7 +32,7 @@
     configureRpcThreadpool(1, true);
 
     sp<IStorage> service = new Storage();
-    LazyServiceRegistrar registrar;
+    auto registrar = LazyServiceRegistrar::getInstance();
     status_t result = registrar.registerService(service);
 
     if (result != OK) {
diff --git a/health/storage/1.0/vts/functional/Android.bp b/health/storage/1.0/vts/functional/Android.bp
index b18e36f..a30cdde 100644
--- a/health/storage/1.0/vts/functional/Android.bp
+++ b/health/storage/1.0/vts/functional/Android.bp
@@ -21,8 +21,7 @@
     static_libs: ["android.hardware.health.storage@1.0"],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp b/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp
index 2365124..eaa44ec 100644
--- a/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp
+++ b/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/health/storage/1.0/IStorage.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
 #include <unistd.h>
 #include <thread>
 
@@ -101,25 +102,10 @@
     Result mResult{Result::UNKNOWN_ERROR};
 };
 
-/** Test environment for Health Storage HIDL HAL. */
-class HealthStorageHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    /** get the test environment singleton */
-    static HealthStorageHidlEnvironment* Instance() {
-        static HealthStorageHidlEnvironment* instance = new HealthStorageHidlEnvironment();
-        return instance;
-    }
-    virtual void registerTestServices() override { registerTestService<IStorage>(); }
-
-   private:
-    HealthStorageHidlEnvironment() {}
-};
-
-class HealthStorageHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class HealthStorageHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        fs = ::testing::VtsHalHidlTargetTestBase::getService<IStorage>(
-            HealthStorageHidlEnvironment::Instance()->getServiceName<IStorage>());
+        fs = IStorage::getService(GetParam());
 
         ASSERT_NE(fs, nullptr);
         LOG(INFO) << "Service is remote " << fs->isRemote();
@@ -153,7 +139,7 @@
 /**
  * Ensure garbage collection works on null callback.
  */
-TEST_F(HealthStorageHidlTest, GcNullCallback) {
+TEST_P(HealthStorageHidlTest, GcNullCallback) {
     auto ret = fs->garbageCollect(kDevGcTimeoutSec, nullptr);
 
     ASSERT_OK(ret);
@@ -167,28 +153,20 @@
 /**
  * Ensure garbage collection works on non-null callback.
  */
-TEST_F(HealthStorageHidlTest, GcNonNullCallback) {
+TEST_P(HealthStorageHidlTest, GcNonNullCallback) {
     sp<GcCallback> cb = new GcCallback();
     auto ret = fs->garbageCollect(kDevGcTimeoutSec, cb);
     ASSERT_OK(ret);
     cb->waitForResult(kDevGcTimeout + kDevGcTolerance + kRpcTime, Result::SUCCESS);
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, HealthStorageHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IStorage::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 }  // namespace V1_0
 }  // namespace storage
 }  // namespace health
 }  // namespace hardware
 }  // namespace android
-
-int main(int argc, char** argv) {
-    using ::android::hardware::configureRpcThreadpool;
-    using ::android::hardware::health::storage::V1_0::HealthStorageHidlEnvironment;
-
-    configureRpcThreadpool(1, false /* callerWillJoin*/);
-    ::testing::AddGlobalTestEnvironment(HealthStorageHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    HealthStorageHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
diff --git a/health/utils/libhealth2impl/Android.bp b/health/utils/libhealth2impl/Android.bp
new file mode 100644
index 0000000..14374a2
--- /dev/null
+++ b/health/utils/libhealth2impl/Android.bp
@@ -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.
+
+// A helper library for health@2.x HAL implementation.
+// HAL implementations can link to this library and extend the Health class.
+cc_library_static {
+    name: "libhealth2impl",
+    vendor_available: true,
+    recovery_available: true,
+    srcs: [
+        "BinderHealth.cpp",
+        "HalHealthLoop.cpp",
+        "Health.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.health@2.1",
+        "android.hardware.health@2.0",
+    ],
+    static_libs: [
+        "libbatterymonitor",
+        "libhealthloop",
+        "android.hardware.health@1.0-convert",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    export_static_lib_headers: [
+        "libbatterymonitor",
+        "libhealthloop",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/health/utils/libhealth2impl/BinderHealth.cpp b/health/utils/libhealth2impl/BinderHealth.cpp
new file mode 100644
index 0000000..625d0e0
--- /dev/null
+++ b/health/utils/libhealth2impl/BinderHealth.cpp
@@ -0,0 +1,190 @@
+/*
+ * 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 <health2impl/BinderHealth.h>
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <health2impl/Callback.h>
+#include <health2impl/Health.h>
+
+using android::hardware::handleTransportPoll;
+using android::hardware::IPCThreadState;
+using android::hardware::setupTransportPolling;
+
+using android::hardware::health::V2_0::Result;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+bool IsDeadObjectLogged(const Return<void>& ret) {
+    if (ret.isOk()) return false;
+    if (ret.isDeadObject()) return true;
+    LOG(ERROR) << "Cannot call healthInfoChanged* on callback: " << ret.description();
+    return false;
+}
+
+BinderHealth::BinderHealth(const std::string& name, const sp<IHealth>& impl)
+    : HalHealthLoop(name, impl) {
+    CHECK_NE(this, impl.get());
+    CHECK(!impl->isRemote());
+}
+
+//
+// Methods that handle callbacks.
+//
+
+Return<Result> BinderHealth::registerCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
+    if (callback == nullptr) {
+        return Result::SUCCESS;
+    }
+
+    Callback* wrapped = nullptr;
+    {
+        std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
+        wrapped = callbacks_.emplace_back(Wrap(callback)).get();
+        // unlock
+    }
+
+    auto linkRet = callback->linkToDeath(this, 0u /* cookie */);
+    if (!linkRet.withDefault(false)) {
+        LOG(WARNING) << __func__ << "Cannot link to death: "
+                     << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
+        // ignore the error
+    }
+
+    getHealthInfo_2_1([&](auto res, const auto& health_info) {
+        if (res != Result::SUCCESS) {
+            LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
+            return;
+        }
+        auto ret = wrapped->Notify(health_info);
+        if (IsDeadObjectLogged(ret)) {
+            // Remove callback reference.
+            std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
+            auto it = std::find_if(callbacks_.begin(), callbacks_.end(),
+                                   [wrapped](const auto& cb) { return cb.get() == wrapped; });
+            if (it != callbacks_.end()) {
+                callbacks_.erase(it);
+            }
+            // unlock
+        }
+    });
+
+    return Result::SUCCESS;
+}
+
+bool BinderHealth::unregisterCallbackInternal(const sp<IBase>& callback) {
+    if (callback == nullptr) {
+        return false;
+    }
+
+    bool removed = false;
+    std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
+    for (auto it = callbacks_.begin(); it != callbacks_.end();) {
+        if (interfacesEqual((*it)->Get(), callback)) {
+            it = callbacks_.erase(it);
+            removed = true;
+        } else {
+            ++it;
+        }
+    }
+    (void)callback->unlinkToDeath(this).isOk();  // ignore errors
+    return removed;
+}
+
+Return<Result> BinderHealth::update() {
+    Result result = service()->update();
+    if (result != Result::SUCCESS) return result;
+    getHealthInfo_2_1([&](auto res, const auto& health_info) {
+        if (res != Result::SUCCESS) {
+            result = res;
+            return;
+        }
+        OnHealthInfoChanged(health_info);
+    });
+    return result;
+}
+
+Return<Result> BinderHealth::unregisterCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
+    return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
+}
+
+void BinderHealth::OnHealthInfoChanged(const HealthInfo& health_info) {
+    // Notify all callbacks
+    std::unique_lock<decltype(callbacks_lock_)> lock(callbacks_lock_);
+    for (auto it = callbacks_.begin(); it != callbacks_.end();) {
+        auto ret = (*it)->Notify(health_info);
+        if (IsDeadObjectLogged(ret)) {
+            it = callbacks_.erase(it);
+        } else {
+            ++it;
+        }
+    }
+    lock.unlock();
+
+    // adjusts uevent / wakealarm periods
+    HalHealthLoop::OnHealthInfoChanged(health_info);
+}
+
+void BinderHealth::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
+    (void)unregisterCallbackInternal(who.promote());
+}
+
+void BinderHealth::BinderEvent(uint32_t /*epevents*/) {
+    if (binder_fd_ >= 0) {
+        handleTransportPoll(binder_fd_);
+    }
+}
+
+void BinderHealth::Init(struct healthd_config* config) {
+    // Set up epoll and get uevent / wake alarm periods
+    HalHealthLoop::Init(config);
+
+    LOG(INFO) << instance_name() << " instance initializing with healthd_config...";
+
+    binder_fd_ = setupTransportPolling();
+
+    if (binder_fd_ >= 0) {
+        auto binder_event = [](auto* health_loop, uint32_t epevents) {
+            static_cast<BinderHealth*>(health_loop)->BinderEvent(epevents);
+        };
+        if (RegisterEvent(binder_fd_, binder_event, EVENT_NO_WAKEUP_FD) != 0) {
+            PLOG(ERROR) << instance_name() << " instance: Register for binder events failed";
+        }
+    }
+
+    CHECK_EQ(registerAsService(instance_name()), android::OK)
+            << instance_name() << ": Failed to register HAL";
+
+    LOG(INFO) << instance_name() << ": Hal init done";
+}
+
+int BinderHealth::PrepareToWait(void) {
+    IPCThreadState::self()->flushCommands();
+    return HalHealthLoop::PrepareToWait();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/HalHealthLoop.cpp b/health/utils/libhealth2impl/HalHealthLoop.cpp
new file mode 100644
index 0000000..3901a76
--- /dev/null
+++ b/health/utils/libhealth2impl/HalHealthLoop.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 <health2impl/HalHealthLoop.h>
+
+#include <android-base/logging.h>
+#include <hal_conversion.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <health2impl/Health.h>
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::handleTransportPoll;
+using android::hardware::IPCThreadState;
+using android::hardware::setupTransportPolling;
+
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
+using android::hardware::health::V2_0::Result;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+void HalHealthLoop::Init(struct healthd_config* config) {
+    // Retrieve healthd_config from the HAL.
+    service_->getHealthConfig([config](auto res, const auto& health_config) {
+        CHECK(res == Result::SUCCESS);
+
+        convertFromHealthConfig(health_config.battery, config);
+        config->boot_min_cap = health_config.bootMinCap;
+
+        // Leave screen_on empty because it is handled in GetScreenOn below.
+
+        // Leave ignorePowerSupplyNames empty because it isn't
+        // used by clients of health HAL.
+    });
+}
+
+void HalHealthLoop::Heartbeat(void) {
+    // noop
+}
+
+void HalHealthLoop::ScheduleBatteryUpdate() {
+    // ignore errors. impl may not be able to handle any callbacks, so
+    // update() may return errors.
+    Result res = service_->update();
+    if (res != Result::SUCCESS) {
+        LOG(WARNING) << "update() on the health HAL implementation failed with " << toString(res);
+    }
+
+    service_->getHealthInfo_2_1([this](auto res, const auto& health_info) {
+        CHECK(res == Result::SUCCESS)
+                << "getHealthInfo_2_1() on the health HAL implementation failed with "
+                << toString(res);
+        this->OnHealthInfoChanged(health_info);
+    });
+}
+
+int HalHealthLoop::PrepareToWait() {
+    return -1;
+}
+
+void HalHealthLoop::OnHealthInfoChanged(const HealthInfo& health_info) {
+    set_charger_online(health_info);
+    AdjustWakealarmPeriods(charger_online());
+}
+
+void HalHealthLoop::set_charger_online(const HealthInfo& health_info) {
+    const auto& props = health_info.legacy.legacy;
+    charger_online_ =
+            props.chargerAcOnline || props.chargerUsbOnline || props.chargerWirelessOnline;
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/Health.cpp b/health/utils/libhealth2impl/Health.cpp
new file mode 100644
index 0000000..f4684ae
--- /dev/null
+++ b/health/utils/libhealth2impl/Health.cpp
@@ -0,0 +1,267 @@
+/*
+ * 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 <health2impl/Health.h>
+
+#include <functional>
+#include <string_view>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android/hardware/health/1.0/types.h>
+#include <android/hardware/health/2.0/IHealthInfoCallback.h>
+#include <android/hardware/health/2.0/types.h>
+#include <android/hardware/health/2.1/IHealthInfoCallback.h>
+#include <hal_conversion.h>
+#include <healthd/healthd.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <health2impl/Callback.h>
+#include <health2impl/HalHealthLoop.h>
+
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V1_0::toString;
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
+using android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
+using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+using android::hardware::health::V2_0::Result;
+using android::hardware::health::V2_1::IHealth;
+
+using ScreenOn = decltype(healthd_config::screen_on);
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+/*
+// If you need to call healthd_board_init, construct the Health instance with
+// the healthd_config after calling healthd_board_init:
+struct healthd_config* init_config(struct healthd_config* config) {
+    healthd_board_init(config);
+    return config;
+}
+class MyHealth : public Health {
+    MyHealth(struct healthd_config* config) :
+        Health(init_config(config)) {}
+};
+*/
+
+Health::Health(std::unique_ptr<healthd_config>&& config) : healthd_config_(std::move(config)) {
+    battery_monitor_.init(healthd_config_.get());
+}
+
+//
+// Callbacks are not supported by the passthrough implementation.
+//
+
+Return<Result> Health::registerCallback(const sp<V2_0::IHealthInfoCallback>&) {
+    return Result::NOT_SUPPORTED;
+}
+
+Return<Result> Health::unregisterCallback(const sp<V2_0::IHealthInfoCallback>&) {
+    return Result::NOT_SUPPORTED;
+}
+
+Return<Result> Health::update() {
+    Result result = Result::UNKNOWN;
+    getHealthInfo_2_1([&](auto res, const auto& /* health_info */) {
+        result = res;
+        if (res != Result::SUCCESS) {
+            LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
+            return;
+        }
+
+        battery_monitor_.logValues();
+    });
+    return result;
+}
+
+//
+// Getters.
+//
+
+template <typename T>
+static Return<void> GetProperty(BatteryMonitor* monitor, int id, T defaultValue,
+                                const std::function<void(Result, T)>& callback) {
+    struct BatteryProperty prop;
+    T ret = defaultValue;
+    Result result = Result::SUCCESS;
+    status_t err = monitor->getProperty(static_cast<int>(id), &prop);
+    if (err != OK) {
+        LOG(DEBUG) << "getProperty(" << id << ")"
+                   << " fails: (" << err << ") " << strerror(-err);
+    } else {
+        ret = static_cast<T>(prop.valueInt64);
+    }
+    switch (err) {
+        case OK:
+            result = Result::SUCCESS;
+            break;
+        case NAME_NOT_FOUND:
+            result = Result::NOT_SUPPORTED;
+            break;
+        default:
+            result = Result::UNKNOWN;
+            break;
+    }
+    callback(result, static_cast<T>(ret));
+    return Void();
+}
+
+Return<void> Health::getChargeCounter(getChargeCounter_cb _hidl_cb) {
+    return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, 0, _hidl_cb);
+}
+
+Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
+    return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CURRENT_NOW, 0, _hidl_cb);
+}
+
+Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
+    return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CURRENT_AVG, 0, _hidl_cb);
+}
+
+Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
+    return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
+}
+
+Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
+    return GetProperty<int64_t>(&battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, 0, _hidl_cb);
+}
+
+Return<void> Health::getChargeStatus(getChargeStatus_cb _hidl_cb) {
+    return GetProperty(&battery_monitor_, BATTERY_PROP_BATTERY_STATUS, BatteryStatus::UNKNOWN,
+                       _hidl_cb);
+}
+
+Return<void> Health::getStorageInfo(getStorageInfo_cb _hidl_cb) {
+    // This implementation does not support StorageInfo. An implementation may extend this
+    // class and override this function to support storage info.
+    _hidl_cb(Result::NOT_SUPPORTED, {});
+    return Void();
+}
+
+Return<void> Health::getDiskStats(getDiskStats_cb _hidl_cb) {
+    // This implementation does not support DiskStats. An implementation may extend this
+    // class and override this function to support disk stats.
+    _hidl_cb(Result::NOT_SUPPORTED, {});
+    return Void();
+}
+
+template <typename T, typename Method>
+static inline void GetHealthInfoField(Health* service, Method func, T* out) {
+    *out = T{};
+    std::invoke(func, service, [out](Result result, const T& value) {
+        if (result == Result::SUCCESS) *out = value;
+    });
+}
+
+Return<void> Health::getHealthInfo(getHealthInfo_cb _hidl_cb) {
+    return getHealthInfo_2_1(
+            [&](auto res, const auto& health_info) { _hidl_cb(res, health_info.legacy); });
+}
+
+Return<void> Health::getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) {
+    battery_monitor_.updateValues();
+
+    HealthInfo health_info = battery_monitor_.getHealthInfo_2_1();
+
+    // Fill in storage infos; these aren't retrieved by BatteryMonitor.
+    GetHealthInfoField(this, &Health::getStorageInfo, &health_info.legacy.storageInfos);
+    GetHealthInfoField(this, &Health::getDiskStats, &health_info.legacy.diskStats);
+
+    // A subclass may want to update health info struct before returning it.
+    UpdateHealthInfo(&health_info);
+
+    _hidl_cb(Result::SUCCESS, health_info);
+    return Void();
+}
+
+Return<void> Health::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+    if (handle == nullptr || handle->numFds == 0) {
+        return Void();
+    }
+
+    int fd = handle->data[0];
+    battery_monitor_.dumpState(fd);
+    getHealthInfo_2_1([fd](auto res, const auto& info) {
+        android::base::WriteStringToFd("\ngetHealthInfo -> ", fd);
+        if (res == Result::SUCCESS) {
+            android::base::WriteStringToFd(toString(info), fd);
+        } else {
+            android::base::WriteStringToFd(toString(res), fd);
+        }
+        android::base::WriteStringToFd("\n", fd);
+    });
+
+    fsync(fd);
+    return Void();
+}
+
+Return<void> Health::getHealthConfig(getHealthConfig_cb _hidl_cb) {
+    HealthConfig config = {};
+    convertToHealthConfig(healthd_config_.get(), config.battery);
+    config.bootMinCap = static_cast<int32_t>(healthd_config_->boot_min_cap);
+
+    _hidl_cb(Result::SUCCESS, config);
+    return Void();
+}
+
+Return<void> Health::shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) {
+    if (!healthd_config_->screen_on) {
+        _hidl_cb(Result::NOT_SUPPORTED, true);
+        return Void();
+    }
+
+    Result returned_result = Result::UNKNOWN;
+    bool screen_on = true;
+    getHealthInfo_2_1([&](auto res, const auto& health_info) {
+        returned_result = res;
+        if (returned_result != Result::SUCCESS) return;
+
+        struct BatteryProperties props = {};
+        V1_0::hal_conversion::convertFromHealthInfo(health_info.legacy.legacy, &props);
+        screen_on = healthd_config_->screen_on(&props);
+    });
+    _hidl_cb(returned_result, screen_on);
+    return Void();
+}
+
+//
+// Subclass helpers / overrides
+//
+
+void Health::UpdateHealthInfo(HealthInfo* /* health_info */) {
+    /*
+        // Sample code for a subclass to implement this:
+        // If you need to modify values (e.g. batteryChargeTimeToFullNowSeconds), do it here.
+        health_info->batteryChargeTimeToFullNowSeconds = calculate_charge_time_seconds();
+
+        // If you need to call healthd_board_battery_update:
+        struct BatteryProperties props;
+        convertFromHealthInfo(health_info.legacy.legacy, &props);
+        healthd_board_battery_update(&props);
+        convertToHealthInfo(&props, health_info.legacy.legacy);
+    */
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/BinderHealth.h b/health/utils/libhealth2impl/include/health2impl/BinderHealth.h
new file mode 100644
index 0000000..1da5bd1
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/BinderHealth.h
@@ -0,0 +1,111 @@
+/*
+ * 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 <android-base/unique_fd.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <healthd/healthd.h>
+
+#include <health2impl/Callback.h>
+#include <health2impl/HalHealthLoop.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// binderized health HAL implementation.
+class BinderHealth : public HalHealthLoop, public IHealth, public hidl_death_recipient {
+  public:
+    // |impl| should be the passthrough implementation.
+    BinderHealth(const std::string& name, const sp<IHealth>& impl);
+
+    // Methods from ::android::hardware::health::V2_0::IHealth follow.
+    Return<::android::hardware::health::V2_0::Result> registerCallback(
+            const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+    Return<::android::hardware::health::V2_0::Result> unregisterCallback(
+            const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+    Return<::android::hardware::health::V2_0::Result> update() override;
+    Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override {
+        return service()->getChargeCounter(_hidl_cb);
+    }
+    Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override {
+        return service()->getCurrentNow(_hidl_cb);
+    }
+    Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override {
+        return service()->getCurrentAverage(_hidl_cb);
+    }
+    Return<void> getCapacity(getCapacity_cb _hidl_cb) override {
+        return service()->getCapacity(_hidl_cb);
+    }
+    Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override {
+        return service()->getEnergyCounter(_hidl_cb);
+    }
+    Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override {
+        return service()->getChargeStatus(_hidl_cb);
+    }
+    Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override {
+        return service()->getStorageInfo(_hidl_cb);
+    }
+    Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override {
+        return service()->getDiskStats(_hidl_cb);
+    }
+    Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override {
+        return service()->getHealthInfo(_hidl_cb);
+    }
+
+    // Methods from ::android::hardware::health::V2_1::IHealth follow.
+    Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override {
+        return service()->getHealthConfig(_hidl_cb);
+    }
+    Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override {
+        return service()->getHealthInfo_2_1(_hidl_cb);
+    }
+    Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override {
+        return service()->shouldKeepScreenOn(_hidl_cb);
+    }
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override {
+        return service()->debug(fd, args);
+    }
+
+    // hidl_death_recipient implementation.
+    void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+
+    // Called by BinderHealthCallback.
+    void OnHealthInfoChanged(const HealthInfo& health_info) override;
+
+  protected:
+    void Init(struct healthd_config* config) override;
+    int PrepareToWait() override;
+    // A subclass may override this if it wants to handle binder events differently.
+    virtual void BinderEvent(uint32_t epevents);
+
+  private:
+    bool unregisterCallbackInternal(const sp<IBase>& callback);
+    int binder_fd_ = -1;
+    std::mutex callbacks_lock_;
+    std::vector<std::unique_ptr<Callback>> callbacks_;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/Callback.h b/health/utils/libhealth2impl/include/health2impl/Callback.h
new file mode 100644
index 0000000..a30480b
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/Callback.h
@@ -0,0 +1,73 @@
+/*
+ * 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 <android/hardware/health/2.1/IHealth.h>
+#include <android/hardware/health/2.1/IHealthInfoCallback.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hidl::base::V1_0::IBase;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// Wraps an IHealthInfoCallback.
+class Callback {
+  public:
+    virtual ~Callback() {}
+    virtual Return<void> Notify(const HealthInfo&) = 0;
+    virtual sp<IBase> Get() = 0;
+};
+
+class Callback_2_0 : public Callback {
+  public:
+    Callback_2_0(const sp<V2_0::IHealthInfoCallback>& callback) : callback_(callback) {}
+    Return<void> Notify(const HealthInfo& info) override {
+        return callback_->healthInfoChanged(info.legacy);
+    }
+    sp<IBase> Get() override { return callback_; }
+
+  private:
+    sp<V2_0::IHealthInfoCallback> callback_;
+};
+
+class Callback_2_1 : public Callback {
+  public:
+    Callback_2_1(const sp<IHealthInfoCallback>& callback) : callback_(callback) {}
+    Return<void> Notify(const HealthInfo& info) override {
+        return callback_->healthInfoChanged_2_1(info);
+    }
+    sp<IBase> Get() override { return callback_; }
+
+  private:
+    sp<IHealthInfoCallback> callback_;
+};
+
+inline std::unique_ptr<Callback> Wrap(const sp<V2_0::IHealthInfoCallback>& callback_2_0) {
+    auto callback_2_1 = IHealthInfoCallback::castFrom(callback_2_0).withDefault(nullptr);
+    if (callback_2_1) return std::make_unique<Callback_2_1>(callback_2_1);
+    return std::make_unique<Callback_2_0>(callback_2_0);
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h b/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h
new file mode 100644
index 0000000..d9b5580
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h
@@ -0,0 +1,67 @@
+/*
+ * 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 <optional>
+
+#include <android/hardware/health/2.1/IHealth.h>
+#include <health/HealthLoop.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// An implementation of HealthLoop for using a given health HAL. This is useful
+// for services that opens the passthrough implementation and starts the HealthLoop
+// to periodically poll data from the implementation.
+class HalHealthLoop : public HealthLoop {
+  public:
+    HalHealthLoop(const std::string& name, const sp<IHealth>& service)
+        : instance_name_(name), service_(service) {}
+
+  protected:
+    virtual void Init(struct healthd_config* config) override;
+    virtual void Heartbeat() override;
+    virtual int PrepareToWait() override;
+    virtual void ScheduleBatteryUpdate() override;
+
+    // HealthLoop periodically calls ScheduleBatteryUpdate, which calls
+    // OnHealthInfoChanged callback. A client can override this function to
+    // broadcast the health_info to interested listeners. By default, this
+    // adjust uevents / wakealarm periods.
+    virtual void OnHealthInfoChanged(const HealthInfo& health_info);
+
+    const std::string& instance_name() const { return instance_name_; }
+    const sp<IHealth>& service() const { return service_; }
+    bool charger_online() const { return charger_online_; }
+
+    // Helpers for subclasses to implement OnHealthInfoChanged.
+    void set_charger_online(const HealthInfo& health_info);
+
+  private:
+    const std::string& instance_name_;
+    sp<IHealth> service_;
+    bool charger_online_ = false;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/Health.h b/health/utils/libhealth2impl/include/health2impl/Health.h
new file mode 100644
index 0000000..853b0cd
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/Health.h
@@ -0,0 +1,90 @@
+/*
+ * 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 <android/hardware/health/2.1/IHealth.h>
+#include <healthd/BatteryMonitor.h>
+#include <hidl/Status.h>
+
+#include <health2impl/Callback.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::base::V1_0::IBase;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+class Health : public IHealth {
+  public:
+    Health(std::unique_ptr<healthd_config>&& config);
+
+    // Methods from ::android::hardware::health::V2_0::IHealth follow.
+    Return<::android::hardware::health::V2_0::Result> registerCallback(
+            const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+    Return<::android::hardware::health::V2_0::Result> unregisterCallback(
+            const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+    Return<::android::hardware::health::V2_0::Result> update() override;
+    Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
+    Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
+    Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
+    Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
+    Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
+    Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
+    Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
+    Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
+    Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
+
+    // Methods from ::android::hardware::health::V2_1::IHealth follow.
+    Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override;
+    Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override;
+    Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+  protected:
+    // A subclass can override this to modify any health info object before
+    // returning to clients. This is similar to healthd_board_battery_update().
+    // By default, it does nothing.
+    virtual void UpdateHealthInfo(HealthInfo* health_info);
+
+  private:
+    bool unregisterCallbackInternal(const sp<IBase>& callback);
+
+    BatteryMonitor battery_monitor_;
+    std::unique_ptr<healthd_config> healthd_config_;
+
+    std::mutex callbacks_lock_;
+    std::vector<std::unique_ptr<Callback>> callbacks_;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
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/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/health/utils/libhealthloop/include/health/utils.h
similarity index 66%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to health/utils/libhealthloop/include/health/utils.h
index 8bb72a1..e46771c 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/health/utils/libhealthloop/include/health/utils.h
@@ -13,14 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
+#include <healthd/healthd.h>
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
+namespace android {
+namespace hardware {
+namespace health {
 
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
+void InitHealthdConfig(struct healthd_config* healthd_config);
 
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+}  // 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/input/classifier/1.0/Android.bp b/input/classifier/1.0/Android.bp
index 6815a51..11e0f52 100644
--- a/input/classifier/1.0/Android.bp
+++ b/input/classifier/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/input/classifier/1.0/default/Android.bp b/input/classifier/1.0/default/Android.bp
index ceb2aca..3379a76 100644
--- a/input/classifier/1.0/default/Android.bp
+++ b/input/classifier/1.0/default/Android.bp
@@ -11,7 +11,6 @@
     shared_libs: [
         "android.hardware.input.classifier@1.0",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
diff --git a/input/common/1.0/Android.bp b/input/common/1.0/Android.bp
index 07b38cf..2c7c517 100644
--- a/input/common/1.0/Android.bp
+++ b/input/common/1.0/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/ir/1.0/Android.bp b/ir/1.0/Android.bp
index 5f25172..5fca96d 100644
--- a/ir/1.0/Android.bp
+++ b/ir/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/ir/1.0/default/Android.bp b/ir/1.0/default/Android.bp
index 2b15387..80e0f3c 100644
--- a/ir/1.0/default/Android.bp
+++ b/ir/1.0/default/Android.bp
@@ -20,7 +20,6 @@
     srcs: ["ConsumerIr.cpp"],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libhardware",
         "liblog",
         "libutils",
@@ -40,7 +39,6 @@
         "liblog",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.ir@1.0",
     ],
diff --git a/ir/1.0/default/android.hardware.ir@1.0-service.rc b/ir/1.0/default/android.hardware.ir@1.0-service.rc
index 0d06967..b2f1f7d 100644
--- a/ir/1.0/default/android.hardware.ir@1.0-service.rc
+++ b/ir/1.0/default/android.hardware.ir@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.ir-hal-1-0 /vendor/bin/hw/android.hardware.ir@1.0-service
+    interface android.hardware.ir@1.0::IConsumerIr default
     class hal
     user system
     group system
diff --git a/ir/1.0/vts/functional/Android.bp b/ir/1.0/vts/functional/Android.bp
index f5c9d61..f9edebd 100644
--- a/ir/1.0/vts/functional/Android.bp
+++ b/ir/1.0/vts/functional/Android.bp
@@ -21,5 +21,5 @@
     static_libs: [
         "android.hardware.ir@1.0",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp b/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
index 5fd2dd4..a5dbdcc 100644
--- a/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
+++ b/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
@@ -21,8 +21,9 @@
 #include <android/hardware/ir/1.0/IConsumerIr.h>
 #include <android/hardware/ir/1.0/types.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <algorithm>
 
 using ::android::hardware::ir::V1_0::IConsumerIr;
@@ -31,26 +32,10 @@
 using ::android::hardware::Return;
 using ::android::sp;
 
-// Test environment for Ir
-class ConsumerIrHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static ConsumerIrHidlEnvironment* Instance() {
-    static ConsumerIrHidlEnvironment* instance = new ConsumerIrHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<IConsumerIr>(); }
- private:
-  ConsumerIrHidlEnvironment() {}
-};
-
-// The main test class for IR HIDL HAL.
-class ConsumerIrHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ConsumerIrHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-    ir = ::testing::VtsHalHidlTargetTestBase::getService<IConsumerIr>(
-      ConsumerIrHidlEnvironment::Instance()->getServiceName<IConsumerIr>());
+    ir = IConsumerIr::getService(GetParam());
     ASSERT_NE(ir, nullptr);
   }
 
@@ -60,7 +45,7 @@
 };
 
 // Test transmit() for the min and max frequency of every available range
-TEST_F(ConsumerIrHidlTest, TransmitTest) {
+TEST_P(ConsumerIrHidlTest, TransmitTest) {
   bool success;
   hidl_vec<ConsumerIrFreqRange> ranges;
   auto cb = [&](bool s, hidl_vec<ConsumerIrFreqRange> v) {
@@ -84,7 +69,7 @@
 }
 
 // Test transmit() when called with invalid frequencies
-TEST_F(ConsumerIrHidlTest, BadFreqTest) {
+TEST_P(ConsumerIrHidlTest, BadFreqTest) {
   uint32_t len = 16;
   hidl_vec<int32_t> vec;
   vec.resize(len);
@@ -92,11 +77,7 @@
   EXPECT_FALSE(ir->transmit(-1, vec));
 }
 
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(ConsumerIrHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  ConsumerIrHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, ConsumerIrHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IConsumerIr::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/keymaster/3.0/Android.bp b/keymaster/3.0/Android.bp
index ca17a9b..0fdc32c 100644
--- a/keymaster/3.0/Android.bp
+++ b/keymaster/3.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/keymaster/3.0/default/Android.mk b/keymaster/3.0/default/Android.mk
index 9e7d04a..208cb66 100644
--- a/keymaster/3.0/default/Android.mk
+++ b/keymaster/3.0/default/Android.mk
@@ -15,7 +15,6 @@
     libpuresoftkeymasterdevice \
     libkeymaster3device \
     libhidlbase \
-    libhidltransport \
     libutils \
     libhardware \
     android.hardware.keymaster@3.0
@@ -38,7 +37,6 @@
     libutils \
     libhardware \
     libhidlbase \
-    libhidltransport \
     android.hardware.keymaster@3.0
 
 include $(BUILD_EXECUTABLE)
diff --git a/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc b/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
index ea8d490..dffaca5 100644
--- a/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
+++ b/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.keymaster-3-0 /vendor/bin/hw/android.hardware.keymaster@3.0-service
+    interface android.hardware.keymaster@3.0::IKeymasterDevice default
     class early_hal
     user nobody
     group drmrpc
diff --git a/keymaster/3.0/vts/functional/Android.bp b/keymaster/3.0/vts/functional/Android.bp
index b0371c7..36a6861 100644
--- a/keymaster/3.0/vts/functional/Android.bp
+++ b/keymaster/3.0/vts/functional/Android.bp
@@ -26,8 +26,8 @@
     ],
     static_libs: [
         "android.hardware.keymaster@3.0",
-        "libcrypto",
+        "libcrypto_static",
         "libsoftkeymasterdevice",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/keymaster/3.0/vts/functional/AndroidTest.xml b/keymaster/3.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..71e41fc
--- /dev/null
+++ b/keymaster/3.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 VtsHalKeymasterV3_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="VtsHalKeymasterV3_0TargetTest->/data/local/tmp/VtsHalKeymasterV3_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="VtsHalKeymasterV3_0TargetTest" />
+        <option name="native-test-timeout" value="900000"/>
+    </test>
+</configuration>
diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
index ccb5622..ae32764 100644
--- a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -25,17 +25,15 @@
 
 #include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
 #include <android/hardware/keymaster/3.0/types.h>
-
 #include <cutils/properties.h>
-
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <keymaster/keymaster_configuration.h>
 
 #include "authorization_set.h"
 #include "key_param_output.h"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 #include "attestation_record.h"
 #include "openssl_utils.h"
 
@@ -413,33 +411,19 @@
 
 }  // namespace
 
-// Test environment for Keymaster HIDL HAL.
-class KeymasterHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static KeymasterHidlEnvironment* Instance() {
-        static KeymasterHidlEnvironment* instance = new KeymasterHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IKeymasterDevice>(); }
-   private:
-    KeymasterHidlEnvironment() {}
-};
-
-class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
   public:
     void TearDown() override {
         if (key_blob_.size()) {
             CheckedDeleteKey();
         }
         AbortIfNeeded();
+
+        keymaster_.clear();
     }
 
-    // SetUpTestCase runs only once per test case, not once per test.
-    static void SetUpTestCase() {
-        keymaster_ = ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(
-            KeymasterHidlEnvironment::Instance()->getServiceName<IKeymasterDevice>());
+    void SetUp() override {
+        keymaster_ = IKeymasterDevice::getService(GetParam());
         ASSERT_NE(keymaster_, nullptr);
 
         ASSERT_TRUE(
@@ -461,11 +445,9 @@
         os_patch_level_ = ::keymaster::GetOsPatchlevel();
     }
 
-    static void TearDownTestCase() { keymaster_.clear(); }
-
-    static IKeymasterDevice& keymaster() { return *keymaster_; }
-    static uint32_t os_version() { return os_version_; }
-    static uint32_t os_patch_level() { return os_patch_level_; }
+    IKeymasterDevice& keymaster() { return *keymaster_; }
+    uint32_t os_version() { return os_version_; }
+    uint32_t os_patch_level() { return os_patch_level_; }
 
     AuthorizationSet UserAuths() { return AuthorizationSetBuilder().Authorization(TAG_USER_ID, 7); }
 
@@ -929,134 +911,121 @@
         }
     }
 
-    static bool IsSecure() { return is_secure_; }
-    static bool SupportsEc() { return supports_ec_; }
-    static bool SupportsSymmetric() { return supports_symmetric_; }
-    static bool SupportsAllDigests() { return supports_all_digests_; }
-    static bool SupportsAttestation() { return supports_attestation_; }
+    bool IsSecure() { return is_secure_; }
+    bool SupportsEc() { return supports_ec_; }
+    bool SupportsSymmetric() { return supports_symmetric_; }
+    bool SupportsAllDigests() { return supports_all_digests_; }
+    bool SupportsAttestation() { return supports_attestation_; }
 
-    static bool Km2Profile() {
+    bool Km2Profile() {
         return SupportsAttestation() && SupportsAllDigests() && SupportsSymmetric() &&
                SupportsEc() && IsSecure();
     }
 
-    static bool Km1Profile() {
+    bool Km1Profile() {
         return !SupportsAttestation() && SupportsSymmetric() && SupportsEc() && IsSecure();
     }
 
-    static bool Km0Profile() {
+    bool Km0Profile() {
         return !SupportsAttestation() && !SupportsAllDigests() && !SupportsSymmetric() &&
                IsSecure();
     }
 
-    static bool SwOnlyProfile() {
+    bool SwOnlyProfile() {
         return !SupportsAttestation() && !SupportsAllDigests() && !SupportsSymmetric() &&
                !SupportsEc() && !IsSecure();
     }
 
+    bool verify_attestation_record(const string& challenge, const string& app_id,
+                                   AuthorizationSet expected_sw_enforced,
+                                   AuthorizationSet expected_tee_enforced,
+                                   const hidl_vec<uint8_t>& attestation_cert) {
+        X509_Ptr cert(parse_cert_blob(attestation_cert));
+        EXPECT_TRUE(!!cert.get());
+        if (!cert.get()) return false;
+
+        ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+        EXPECT_TRUE(!!attest_rec);
+        if (!attest_rec) return false;
+
+        AuthorizationSet att_sw_enforced;
+        AuthorizationSet att_tee_enforced;
+        uint32_t att_attestation_version;
+        uint32_t att_keymaster_version;
+        SecurityLevel att_attestation_security_level;
+        SecurityLevel att_keymaster_security_level;
+        HidlBuf att_challenge;
+        HidlBuf att_unique_id;
+        HidlBuf att_app_id;
+        EXPECT_EQ(ErrorCode::OK,
+                  parse_attestation_record(attest_rec->data,                 //
+                                           attest_rec->length,               //
+                                           &att_attestation_version,         //
+                                           &att_attestation_security_level,  //
+                                           &att_keymaster_version,           //
+                                           &att_keymaster_security_level,    //
+                                           &att_challenge,                   //
+                                           &att_sw_enforced,                 //
+                                           &att_tee_enforced,                //
+                                           &att_unique_id));
+
+        EXPECT_TRUE(att_attestation_version == 1 || att_attestation_version == 2);
+
+        expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id));
+
+        if (!IsSecure()) {
+            // SW is KM3
+            EXPECT_EQ(att_keymaster_version, 3U);
+        }
+
+        if (SupportsSymmetric()) {
+            EXPECT_GE(att_keymaster_version, 1U);
+        }
+
+        if (SupportsAttestation()) {
+            EXPECT_GE(att_keymaster_version, 2U);
+        }
+
+        EXPECT_EQ(IsSecure() ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
+                  att_keymaster_security_level);
+        EXPECT_EQ(SupportsAttestation() ? SecurityLevel::TRUSTED_ENVIRONMENT
+                                        : SecurityLevel::SOFTWARE,
+                  att_attestation_security_level);
+
+        EXPECT_EQ(challenge.length(), att_challenge.size());
+        EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
+
+        att_sw_enforced.Sort();
+        expected_sw_enforced.Sort();
+        EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(att_sw_enforced))
+                << "(Possibly b/38394619)";
+
+        att_tee_enforced.Sort();
+        expected_tee_enforced.Sort();
+        EXPECT_EQ(filter_tags(expected_tee_enforced), filter_tags(att_tee_enforced))
+                << "(Possibly b/38394619)";
+
+        return true;
+    }
+
     HidlBuf key_blob_;
     KeyCharacteristics key_characteristics_;
     OperationHandle op_handle_ = kOpHandleSentinel;
 
   private:
-    static sp<IKeymasterDevice> keymaster_;
-    static uint32_t os_version_;
-    static uint32_t os_patch_level_;
+    sp<IKeymasterDevice> keymaster_;
+    uint32_t os_version_;
+    uint32_t os_patch_level_;
 
-    static bool is_secure_;
-    static bool supports_ec_;
-    static bool supports_symmetric_;
-    static bool supports_attestation_;
-    static bool supports_all_digests_;
-    static hidl_string name_;
-    static hidl_string author_;
+    bool is_secure_;
+    bool supports_ec_;
+    bool supports_symmetric_;
+    bool supports_attestation_;
+    bool supports_all_digests_;
+    hidl_string name_;
+    hidl_string author_;
 };
 
-bool verify_attestation_record(const string& challenge, const string& app_id,
-                               AuthorizationSet expected_sw_enforced,
-                               AuthorizationSet expected_tee_enforced,
-                               const hidl_vec<uint8_t>& attestation_cert) {
-    X509_Ptr cert(parse_cert_blob(attestation_cert));
-    EXPECT_TRUE(!!cert.get());
-    if (!cert.get()) return false;
-
-    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
-    EXPECT_TRUE(!!attest_rec);
-    if (!attest_rec) return false;
-
-    AuthorizationSet att_sw_enforced;
-    AuthorizationSet att_tee_enforced;
-    uint32_t att_attestation_version;
-    uint32_t att_keymaster_version;
-    SecurityLevel att_attestation_security_level;
-    SecurityLevel att_keymaster_security_level;
-    HidlBuf att_challenge;
-    HidlBuf att_unique_id;
-    HidlBuf att_app_id;
-    EXPECT_EQ(ErrorCode::OK,
-              parse_attestation_record(attest_rec->data,                 //
-                                       attest_rec->length,               //
-                                       &att_attestation_version,         //
-                                       &att_attestation_security_level,  //
-                                       &att_keymaster_version,           //
-                                       &att_keymaster_security_level,    //
-                                       &att_challenge,                   //
-                                       &att_sw_enforced,                 //
-                                       &att_tee_enforced,                //
-                                       &att_unique_id));
-
-    EXPECT_TRUE(att_attestation_version == 1 || att_attestation_version == 2);
-
-    expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
-                                   HidlBuf(app_id));
-
-    if (!KeymasterHidlTest::IsSecure()) {
-        // SW is KM3
-        EXPECT_EQ(att_keymaster_version, 3U);
-    }
-
-    if (KeymasterHidlTest::SupportsSymmetric()) {
-        EXPECT_GE(att_keymaster_version, 1U);
-    }
-
-    if (KeymasterHidlTest::SupportsAttestation()) {
-        EXPECT_GE(att_keymaster_version, 2U);
-    }
-
-    EXPECT_EQ(KeymasterHidlTest::IsSecure() ? SecurityLevel::TRUSTED_ENVIRONMENT
-                                            : SecurityLevel::SOFTWARE,
-              att_keymaster_security_level);
-    EXPECT_EQ(KeymasterHidlTest::SupportsAttestation() ? SecurityLevel::TRUSTED_ENVIRONMENT
-                                                       : SecurityLevel::SOFTWARE,
-              att_attestation_security_level);
-
-    EXPECT_EQ(challenge.length(), att_challenge.size());
-    EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
-
-    att_sw_enforced.Sort();
-    expected_sw_enforced.Sort();
-    EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(att_sw_enforced))
-        << "(Possibly b/38394619)";
-
-    att_tee_enforced.Sort();
-    expected_tee_enforced.Sort();
-    EXPECT_EQ(filter_tags(expected_tee_enforced), filter_tags(att_tee_enforced))
-        << "(Possibly b/38394619)";
-
-    return true;
-}
-
-sp<IKeymasterDevice> KeymasterHidlTest::keymaster_;
-uint32_t KeymasterHidlTest::os_version_;
-uint32_t KeymasterHidlTest::os_patch_level_;
-bool KeymasterHidlTest::is_secure_;
-bool KeymasterHidlTest::supports_ec_;
-bool KeymasterHidlTest::supports_symmetric_;
-bool KeymasterHidlTest::supports_all_digests_;
-bool KeymasterHidlTest::supports_attestation_;
-hidl_string KeymasterHidlTest::name_;
-hidl_string KeymasterHidlTest::author_;
-
 typedef KeymasterHidlTest KeymasterVersionTest;
 
 /*
@@ -1065,7 +1034,7 @@
  * Queries keymaster to find the set of features it supports. Fails if the combination doesn't
  * correspond to any well-defined keymaster version.
  */
-TEST_F(KeymasterVersionTest, SensibleFeatures) {
+TEST_P(KeymasterVersionTest, SensibleFeatures) {
     EXPECT_TRUE(Km2Profile() || Km1Profile() || Km0Profile() || SwOnlyProfile())
         << "Keymaster feature set doesn't fit any reasonable profile.  Reported features:"
         << "SupportsAttestation [" << SupportsAttestation() << "], "
@@ -1124,7 +1093,7 @@
  * Verifies that keymaster can generate all required RSA key sizes, and that the resulting keys have
  * correct characteristics.
  */
-TEST_F(NewKeyGenerationTest, Rsa) {
+TEST_P(NewKeyGenerationTest, Rsa) {
     for (auto key_size : {1024, 2048, 3072, 4096}) {
         HidlBuf key_blob;
         KeyCharacteristics key_characteristics;
@@ -1158,7 +1127,7 @@
  *
  * Verifies that failing to specify a key size for RSA key generation returns UNSUPPORTED_KEY_SIZE.
  */
-TEST_F(NewKeyGenerationTest, RsaNoDefaultSize) {
+TEST_P(NewKeyGenerationTest, RsaNoDefaultSize) {
     ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
               GenerateKey(AuthorizationSetBuilder()
                               .Authorization(TAG_ALGORITHM, Algorithm::RSA)
@@ -1172,7 +1141,7 @@
  * Verifies that keymaster can generate all required EC key sizes, and that the resulting keys have
  * correct characteristics.
  */
-TEST_F(NewKeyGenerationTest, Ecdsa) {
+TEST_P(NewKeyGenerationTest, Ecdsa) {
     for (auto key_size : {224, 256, 384, 521}) {
         HidlBuf key_blob;
         KeyCharacteristics key_characteristics;
@@ -1203,7 +1172,7 @@
  *
  * Verifies that failing to specify a key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
  */
-TEST_F(NewKeyGenerationTest, EcdsaDefaultSize) {
+TEST_P(NewKeyGenerationTest, EcdsaDefaultSize) {
     ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
               GenerateKey(AuthorizationSetBuilder()
                               .Authorization(TAG_ALGORITHM, Algorithm::EC)
@@ -1217,7 +1186,7 @@
  * Verifies that failing to specify an invalid key size for EC key generation returns
  * UNSUPPORTED_KEY_SIZE.
  */
-TEST_F(NewKeyGenerationTest, EcdsaInvalidSize) {
+TEST_P(NewKeyGenerationTest, EcdsaInvalidSize) {
     ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
               GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(Digest::NONE)));
 }
@@ -1228,7 +1197,7 @@
  * Verifies that specifying mismatched key size and curve for EC key generation returns
  * INVALID_ARGUMENT.
  */
-TEST_F(NewKeyGenerationTest, EcdsaMismatchKeySize) {
+TEST_P(NewKeyGenerationTest, EcdsaMismatchKeySize) {
     ASSERT_EQ(ErrorCode::INVALID_ARGUMENT,
               GenerateKey(AuthorizationSetBuilder()
                               .EcdsaSigningKey(224)
@@ -1237,7 +1206,7 @@
         << "(Possibly b/36233343)";
 }
 
-TEST_F(NewKeyGenerationTest, EcdsaAllValidSizes) {
+TEST_P(NewKeyGenerationTest, EcdsaAllValidSizes) {
     size_t valid_sizes[] = {224, 256, 384, 521};
     for (size_t size : valid_sizes) {
         EXPECT_EQ(ErrorCode::OK,
@@ -1252,7 +1221,7 @@
  *
  * Verifies that keymaster supports all required EC curves.
  */
-TEST_F(NewKeyGenerationTest, EcdsaAllValidCurves) {
+TEST_P(NewKeyGenerationTest, EcdsaAllValidCurves) {
     EcCurve curves[] = {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521};
     for (auto curve : curves) {
         EXPECT_EQ(
@@ -1269,7 +1238,7 @@
  * Verifies that keymaster supports all required digests, and that the resulting keys have correct
  * characteristics.
  */
-TEST_F(NewKeyGenerationTest, Hmac) {
+TEST_P(NewKeyGenerationTest, Hmac) {
     for (auto digest : {Digest::MD5, Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256,
                         Digest::SHA_2_384, Digest::SHA_2_512}) {
         HidlBuf key_blob;
@@ -1318,7 +1287,7 @@
  *
  * Verifies that keymaster supports all key sizes, and rejects all invalid key sizes.
  */
-TEST_F(NewKeyGenerationTest, HmacCheckKeySizes) {
+TEST_P(NewKeyGenerationTest, HmacCheckKeySizes) {
     for (size_t key_size = 0; key_size <= 512; ++key_size) {
         if (key_size < 64 || key_size % 8 != 0) {
             // To keep this test from being very slow, we only test a random fraction of non-byte
@@ -1349,7 +1318,7 @@
  * test is probabilistic in order to keep the runtime down, but any failure prints out the specific
  * MAC length that failed, so reproducing a failed run will be easy.
  */
-TEST_F(NewKeyGenerationTest, HmacCheckMinMacLengths) {
+TEST_P(NewKeyGenerationTest, HmacCheckMinMacLengths) {
     for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) {
         if (min_mac_length < 64 || min_mac_length % 8 != 0) {
             // To keep this test from being very long, we only test a random fraction of non-byte
@@ -1379,7 +1348,7 @@
  *
  * Verifies that keymaster rejects HMAC key generation with multiple specified digest algorithms.
  */
-TEST_F(NewKeyGenerationTest, HmacMultipleDigests) {
+TEST_P(NewKeyGenerationTest, HmacMultipleDigests) {
     ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
               GenerateKey(AuthorizationSetBuilder()
                               .HmacKey(128)
@@ -1393,7 +1362,7 @@
  *
  * Verifies that keymaster rejects HMAC key generation with no digest or Digest::NONE
  */
-TEST_F(NewKeyGenerationTest, HmacDigestNone) {
+TEST_P(NewKeyGenerationTest, HmacDigestNone) {
     ASSERT_EQ(
         ErrorCode::UNSUPPORTED_DIGEST,
         GenerateKey(AuthorizationSetBuilder().HmacKey(128).Authorization(TAG_MIN_MAC_LENGTH, 128)));
@@ -1413,7 +1382,7 @@
  * Verifies that getKeyCharacteristics functions, and that generated and retrieved key
  * characteristics match.
  */
-TEST_F(GetKeyCharacteristicsTest, SimpleRsa) {
+TEST_P(GetKeyCharacteristicsTest, SimpleRsa) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::NONE)
@@ -1438,7 +1407,7 @@
  *
  * Verifies that raw RSA signature operations succeed.
  */
-TEST_F(SigningOperationsTest, RsaSuccess) {
+TEST_P(SigningOperationsTest, RsaSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::NONE)
@@ -1454,7 +1423,7 @@
  *
  * Verifies that RSA-PSS signature operations succeed.
  */
-TEST_F(SigningOperationsTest, RsaPssSha256Success) {
+TEST_P(SigningOperationsTest, RsaPssSha256Success) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::SHA_2_256)
@@ -1472,7 +1441,7 @@
  * Verifies that keymaster rejects signature operations that specify a padding mode when the key
  * supports only unpadded operations.
  */
-TEST_F(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
+TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::NONE)
@@ -1492,7 +1461,7 @@
  *
  * Verifies that digested RSA-PKCS1 signature operations succeed.
  */
-TEST_F(SigningOperationsTest, RsaPkcs1Sha256Success) {
+TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::SHA_2_256)
@@ -1509,7 +1478,7 @@
  *
  * Verifies that undigested RSA-PKCS1 signature operations succeed.
  */
-TEST_F(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::NONE)
@@ -1527,7 +1496,7 @@
  * Verifies that undigested RSA-PKCS1 signature operations fail with the correct error code when
  * given a too-long message.
  */
-TEST_F(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::NONE)
@@ -1555,7 +1524,7 @@
  * uses SHA512, which has a digest_size == 512, so the message size is 1040 bits, too large for a
  * 1024-bit key.
  */
-TEST_F(SigningOperationsTest, RsaPssSha512TooSmallKey) {
+TEST_P(SigningOperationsTest, RsaPssSha512TooSmallKey) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::SHA_2_512)
@@ -1574,7 +1543,7 @@
  * Verifies that raw RSA signature operations fail with the correct error code when
  * given a too-long message.
  */
-TEST_F(SigningOperationsTest, RsaNoPaddingTooLong) {
+TEST_P(SigningOperationsTest, RsaNoPaddingTooLong) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::NONE)
@@ -1608,7 +1577,7 @@
  * Verifies that operations can be aborted correctly.  Uses an RSA signing operation for the test,
  * but the behavior should be algorithm and purpose-independent.
  */
-TEST_F(SigningOperationsTest, RsaAbort) {
+TEST_P(SigningOperationsTest, RsaAbort) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::NONE)
@@ -1633,7 +1602,7 @@
  * Verifies that RSA operations fail with the correct error (but key gen succeeds) when used with a
  * padding mode inappropriate for RSA.
  */
-TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
+TEST_P(SigningOperationsTest, RsaUnsupportedPadding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1650,7 +1619,7 @@
  *
  * Verifies that RSA PSS operations fail when no digest is used.  PSS requires a digest.
  */
-TEST_F(SigningOperationsTest, RsaNoDigest) {
+TEST_P(SigningOperationsTest, RsaNoDigest) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1670,7 +1639,7 @@
  * Verifies that RSA operations fail when no padding mode is specified.  PaddingMode::NONE is
  * supported in some cases (as validated in other tests), but a mode must be specified.
  */
-TEST_F(SigningOperationsTest, RsaNoPadding) {
+TEST_P(SigningOperationsTest, RsaNoPadding) {
     // Padding must be specified
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaKey(1024, 3)
@@ -1686,7 +1655,7 @@
  *
  * Verifies that raw RSA signatures succeed with a message shorter than the key size.
  */
-TEST_F(SigningOperationsTest, RsaTooShortMessage) {
+TEST_P(SigningOperationsTest, RsaTooShortMessage) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(1024, 3)
@@ -1707,7 +1676,7 @@
  *
  * Verifies that RSA encryption keys cannot be used to sign.
  */
-TEST_F(SigningOperationsTest, RsaSignWithEncryptionKey) {
+TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(1024, 3)
@@ -1724,7 +1693,7 @@
  * Verifies that attempting a raw signature of a message which is the same length as the key, but
  * numerically larger than the public modulus, fails with the correct error.
  */
-TEST_F(SigningOperationsTest, RsaSignTooLargeMessage) {
+TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(1024, 3)
@@ -1746,7 +1715,7 @@
  *
  * Verifies that ECDSA operations succeed with all possible key sizes and hashes.
  */
-TEST_F(SigningOperationsTest, EcdsaAllSizesAndHashes) {
+TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) {
     for (auto key_size : {224, 256, 384, 521}) {
         for (auto digest : {
                  Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
@@ -1773,7 +1742,7 @@
  *
  * Verifies that ECDSA operations succeed with all possible curves.
  */
-TEST_F(SigningOperationsTest, EcdsaAllCurves) {
+TEST_P(SigningOperationsTest, EcdsaAllCurves) {
     for (auto curve : {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521}) {
         ErrorCode error = GenerateKey(AuthorizationSetBuilder()
                                           .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1795,7 +1764,7 @@
  * work because ECDSA actually only signs the leftmost L_n bits of the message, however large it may
  * be.  Not using digesting is a bad idea, but in some cases digesting is done by the framework.
  */
-TEST_F(SigningOperationsTest, EcdsaNoDigestHugeData) {
+TEST_P(SigningOperationsTest, EcdsaNoDigestHugeData) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .EcdsaSigningKey(224)
@@ -1809,7 +1778,7 @@
  *
  * Verifies that attempts to use AES keys to sign fail in the correct way.
  */
-TEST_F(SigningOperationsTest, AesEcbSign) {
+TEST_P(SigningOperationsTest, AesEcbSign) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .SigningKey()
@@ -1832,7 +1801,7 @@
  *
  * Verifies that HMAC works with all digests.
  */
-TEST_F(SigningOperationsTest, HmacAllDigests) {
+TEST_P(SigningOperationsTest, HmacAllDigests) {
     for (auto digest : {Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
                         Digest::SHA_2_512}) {
         ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -1855,7 +1824,7 @@
  * Verifies that HMAC fails in the correct way when asked to generate a MAC larger than the digest
  * size.
  */
-TEST_F(SigningOperationsTest, HmacSha256TooLargeMacLength) {
+TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .HmacKey(128)
@@ -1876,7 +1845,7 @@
  * Verifies that HMAC fails in the correct way when asked to generate a MAC smaller than the
  * specified minimum MAC length.
  */
-TEST_F(SigningOperationsTest, HmacSha256TooSmallMacLength) {
+TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .HmacKey(128)
@@ -1896,7 +1865,7 @@
  *
  * Validates against the test vectors from RFC 4231 test case 3.
  */
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase3) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) {
     string key(20, 0xaa);
     string message(50, 0xdd);
     uint8_t sha_224_expected[] = {
@@ -1933,7 +1902,7 @@
  *
  * Validates against the test vectors from RFC 4231 test case 5.
  */
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase5) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) {
     string key(20, 0x0c);
     string message = "Test With Truncation";
 
@@ -1965,7 +1934,7 @@
  *
  * Validates against the test vectors from RFC 4231 test case 6.
  */
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase6) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase6) {
     string key(131, 0xaa);
     string message = "Test Using Larger Than Block-Size Key - Hash Key First";
 
@@ -2003,7 +1972,7 @@
  *
  * Validates against the test vectors from RFC 4231 test case 7.
  */
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase7) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase7) {
     string key(131, 0xaa);
     string message = "This is a test using a larger than block-size key and a larger than "
                      "block-size data. The key needs to be hashed before being used by the HMAC "
@@ -2045,7 +2014,7 @@
  *
  * Verifies that a simple RSA signature/verification sequence succeeds.
  */
-TEST_F(VerificationOperationsTest, RsaSuccess) {
+TEST_P(VerificationOperationsTest, RsaSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(1024, 3)
@@ -2063,7 +2032,7 @@
  *
  * Verifies RSA signature/verification for all padding modes and digests.
  */
-TEST_F(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
+TEST_P(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
     ASSERT_EQ(ErrorCode::OK,
               GenerateKey(AuthorizationSetBuilder()
                               .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2159,7 +2128,7 @@
  *
  * Verifies ECDSA signature/verification for all digests and curves.
  */
-TEST_F(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
+TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
     auto digests = {
         Digest::NONE,      Digest::SHA1,      Digest::SHA_2_224,
         Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512,
@@ -2242,7 +2211,7 @@
  *
  * Verifies HMAC signing and verification, but that a signing key cannot be used to verify.
  */
-TEST_F(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
+TEST_P(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
     string key_material = "HelloThisIsAKey";
 
     HidlBuf signing_key, verification_key;
@@ -2290,7 +2259,7 @@
  *
  * Verifies that attempting to export RSA keys in PKCS#8 format fails with the correct error.
  */
-TEST_F(ExportKeyTest, RsaUnsupportedKeyFormat) {
+TEST_P(ExportKeyTest, RsaUnsupportedKeyFormat) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::NONE)
@@ -2305,7 +2274,7 @@
  * Verifies that attempting to export RSA keys from corrupted key blobs fails.  This is essentially
  * a poor-man's key blob fuzzer.
  */
-TEST_F(ExportKeyTest, RsaCorruptedKeyBlob) {
+TEST_P(ExportKeyTest, RsaCorruptedKeyBlob) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(1024, 3)
@@ -2328,7 +2297,7 @@
  * Verifies that attempting to export ECDSA keys from corrupted key blobs fails.  This is
  * essentially a poor-man's key blob fuzzer.
  */
-TEST_F(ExportKeyTest, EcCorruptedKeyBlob) {
+TEST_P(ExportKeyTest, EcCorruptedKeyBlob) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .EcdsaSigningKey(EcCurve::P_256)
@@ -2349,7 +2318,7 @@
  *
  * Verifies that attempting to export AES keys fails in the expected way.
  */
-TEST_F(ExportKeyTest, AesKeyUnexportable) {
+TEST_P(ExportKeyTest, AesKeyUnexportable) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2368,7 +2337,7 @@
  *
  * Verifies that importing and using an RSA key pair works correctly.
  */
-TEST_F(ImportKeyTest, RsaSuccess) {
+TEST_P(ImportKeyTest, RsaSuccess) {
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                            .Authorization(TAG_NO_AUTH_REQUIRED)
                                            .RsaSigningKey(1024, 65537)
@@ -2395,7 +2364,7 @@
  * Verifies that importing an RSA key pair with a size that doesn't match the key fails in the
  * correct way.
  */
-TEST_F(ImportKeyTest, RsaKeySizeMismatch) {
+TEST_P(ImportKeyTest, RsaKeySizeMismatch) {
     ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
               ImportKey(AuthorizationSetBuilder()
                             .RsaSigningKey(2048 /* Doesn't match key */, 65537)
@@ -2410,7 +2379,7 @@
  * Verifies that importing an RSA key pair with a public exponent that doesn't match the key fails
  * in the correct way.
  */
-TEST_F(ImportKeyTest, RsaPublicExponentMismatch) {
+TEST_P(ImportKeyTest, RsaPublicExponentMismatch) {
     ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
               ImportKey(AuthorizationSetBuilder()
                             .RsaSigningKey(1024, 3 /* Doesn't match key */)
@@ -2424,7 +2393,7 @@
  *
  * Verifies that importing and using an ECDSA P-256 key pair works correctly.
  */
-TEST_F(ImportKeyTest, EcdsaSuccess) {
+TEST_P(ImportKeyTest, EcdsaSuccess) {
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                            .Authorization(TAG_NO_AUTH_REQUIRED)
                                            .EcdsaSigningKey(256)
@@ -2450,7 +2419,7 @@
  *
  * Verifies that importing and using an ECDSA P-521 key pair works correctly.
  */
-TEST_F(ImportKeyTest, Ecdsa521Success) {
+TEST_P(ImportKeyTest, Ecdsa521Success) {
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                            .Authorization(TAG_NO_AUTH_REQUIRED)
                                            .EcdsaSigningKey(521)
@@ -2477,7 +2446,7 @@
  * Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the
  * correct way.
  */
-TEST_F(ImportKeyTest, EcdsaSizeMismatch) {
+TEST_P(ImportKeyTest, EcdsaSizeMismatch) {
     ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
               ImportKey(AuthorizationSetBuilder()
                             .EcdsaSigningKey(224 /* Doesn't match key */)
@@ -2491,7 +2460,7 @@
  * Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in the
  * correct way.
  */
-TEST_F(ImportKeyTest, EcdsaCurveMismatch) {
+TEST_P(ImportKeyTest, EcdsaCurveMismatch) {
     if (SupportsSymmetric() && !SupportsAttestation()) {
         // KM1 hardware doesn't know about curves
         return;
@@ -2510,7 +2479,7 @@
  *
  * Verifies that importing and using an AES key works.
  */
-TEST_F(ImportKeyTest, AesSuccess) {
+TEST_P(ImportKeyTest, AesSuccess) {
     string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                            .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2537,7 +2506,7 @@
  *
  * Verifies that importing and using an HMAC key works.
  */
-TEST_F(ImportKeyTest, HmacKeySuccess) {
+TEST_P(ImportKeyTest, HmacKeySuccess) {
     string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                            .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2563,7 +2532,7 @@
  *
  * Verifies that raw RSA encryption works.
  */
-TEST_F(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(1024, 3)
@@ -2586,7 +2555,7 @@
  *
  * Verifies that raw RSA encryption of short messages works.
  */
-TEST_F(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(1024, 3)
@@ -2615,7 +2584,7 @@
  *
  * Verifies that raw RSA encryption of too-long messages fails in the expected way.
  */
-TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLong) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(1024, 3)
@@ -2635,7 +2604,7 @@
  *
  * Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected way.
  */
-TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(1024, 3)
@@ -2677,7 +2646,7 @@
  *
  * Verifies that RSA-OAEP encryption operations work, with all digests.
  */
-TEST_F(EncryptionOperationsTest, RsaOaepSuccess) {
+TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
     auto digests = {Digest::MD5,       Digest::SHA1,      Digest::SHA_2_224,
                     Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512};
 
@@ -2729,7 +2698,7 @@
  * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
  * without a digest.
  */
-TEST_F(EncryptionOperationsTest, RsaOaepInvalidDigest) {
+TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(1024, 3)
@@ -2747,7 +2716,7 @@
  * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt with a
  * different digest than was used to encrypt.
  */
-TEST_F(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
+TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(1024, 3)
@@ -2773,7 +2742,7 @@
  * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a
  * too-large message.
  */
-TEST_F(EncryptionOperationsTest, RsaOaepTooLarge) {
+TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(1024, 3)
@@ -2796,7 +2765,7 @@
  *
  * Verifies that RSA PKCS encryption/decrypts works.
  */
-TEST_F(EncryptionOperationsTest, RsaPkcs1Success) {
+TEST_P(EncryptionOperationsTest, RsaPkcs1Success) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(1024, 3)
@@ -2835,7 +2804,7 @@
  *
  * Verifies that RSA PKCS encryption fails in the correct way when the mssage is too large.
  */
-TEST_F(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(1024, 3)
@@ -2855,7 +2824,7 @@
  *
  * Verifies that attempting to use ECDSA keys to encrypt fails in the correct way.
  */
-TEST_F(EncryptionOperationsTest, EcdsaEncrypt) {
+TEST_P(EncryptionOperationsTest, EcdsaEncrypt) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .EcdsaSigningKey(224)
@@ -2872,7 +2841,7 @@
  *
  * Verifies that attempting to use HMAC keys to encrypt fails in the correct way.
  */
-TEST_F(EncryptionOperationsTest, HmacEncrypt) {
+TEST_P(EncryptionOperationsTest, HmacEncrypt) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .HmacKey(128)
@@ -2894,7 +2863,7 @@
  *
  * Verifies that AES ECB mode works.
  */
-TEST_F(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2923,7 +2892,7 @@
  *
  * Verifies that AES encryption fails in the correct way when an unauthorized mode is specified.
  */
-TEST_F(EncryptionOperationsTest, AesWrongMode) {
+TEST_P(EncryptionOperationsTest, AesWrongMode) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2943,7 +2912,7 @@
  * Verifies that AES encryption fails in the correct way when provided an input that is not a
  * multiple of the block size and no padding is specified.
  */
-TEST_F(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
+TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2964,7 +2933,7 @@
  *
  * Verifies that AES PKCS7 padding works for any message length.
  */
-TEST_F(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2989,7 +2958,7 @@
  * Verifies that AES enryption fails in the correct way when an unauthorized padding mode is
  * specified.
  */
-TEST_F(EncryptionOperationsTest, AesEcbWrongPadding) {
+TEST_P(EncryptionOperationsTest, AesEcbWrongPadding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3010,7 +2979,7 @@
  *
  * Verifies that AES decryption fails in the correct way when the padding is corrupted.
  */
-TEST_F(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3041,7 +3010,7 @@
  *
  * Verifies that AES CTR mode works.
  */
-TEST_F(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3088,7 +3057,7 @@
  *
  * Verifies that AES works, all modes, when provided data in various size increments.
  */
-TEST_F(EncryptionOperationsTest, AesIncremental) {
+TEST_P(EncryptionOperationsTest, AesIncremental) {
     auto block_modes = {
         BlockMode::ECB, BlockMode::CBC, BlockMode::CTR, BlockMode::GCM,
     };
@@ -3226,7 +3195,7 @@
  *
  * Verifies AES CTR implementation against SP800-38A test vectors.
  */
-TEST_F(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
     for (size_t i = 0; i < 3; i++) {
         const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
         const string key = hex2str(test.key);
@@ -3242,7 +3211,7 @@
  *
  * Verifies that keymaster rejects use of CTR mode with PKCS7 padding in the correct way.
  */
-TEST_F(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
+TEST_P(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3257,7 +3226,7 @@
  *
  * Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
  */
-TEST_F(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
+TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3289,7 +3258,7 @@
  *
  * Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
  */
-TEST_F(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3322,7 +3291,7 @@
  *
  * Verifies that AES caller-provided nonces work correctly.
  */
-TEST_F(EncryptionOperationsTest, AesCallerNonce) {
+TEST_P(EncryptionOperationsTest, AesCallerNonce) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3371,7 +3340,7 @@
  * Verifies that caller-provided nonces are not permitted when not specified in the key
  * authorizations.
  */
-TEST_F(EncryptionOperationsTest, AesCallerNonceProhibited) {
+TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3406,7 +3375,7 @@
  *
  * Verifies that AES GCM mode works.
  */
-TEST_F(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3454,7 +3423,7 @@
  *
  * Verifies that AES GCM mode fails correctly when a too-short tag length is specified.
  */
-TEST_F(EncryptionOperationsTest, AesGcmTooShortTag) {
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3475,7 +3444,7 @@
  *
  * Verifies that AES GCM mode fails correctly when a too-short tag is provided to decryption.
  */
-TEST_F(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3518,7 +3487,7 @@
  *
  * Verifies that AES GCM mode fails correctly when the decryption key is incorrect.
  */
-TEST_F(EncryptionOperationsTest, AesGcmCorruptKey) {
+TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) {
     const uint8_t nonce_bytes[] = {
         0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
     };
@@ -3570,7 +3539,7 @@
  * Verifies that AES GCM mode works when provided additional authenticated data, but no data to
  * encrypt.
  */
-TEST_F(EncryptionOperationsTest, AesGcmAadNoData) {
+TEST_P(EncryptionOperationsTest, AesGcmAadNoData) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3616,7 +3585,7 @@
  *
  * Verifies that AES GCM mode works when provided additional authenticated data in multiple chunks.
  */
-TEST_F(EncryptionOperationsTest, AesGcmMultiPartAad) {
+TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3675,7 +3644,7 @@
  *
  * Verifies that AES GCM mode fails correctly when given AAD after data to encipher.
  */
-TEST_F(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
+TEST_P(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3724,7 +3693,7 @@
  *
  * Verifies that AES GCM decryption fails correctly when additional authenticated date is wrong.
  */
-TEST_F(EncryptionOperationsTest, AesGcmBadAad) {
+TEST_P(EncryptionOperationsTest, AesGcmBadAad) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3768,7 +3737,7 @@
  *
  * Verifies that AES GCM decryption fails correctly when the nonce is incorrect.
  */
-TEST_F(EncryptionOperationsTest, AesGcmWrongNonce) {
+TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3812,7 +3781,7 @@
  *
  * Verifies that AES GCM decryption fails correctly when the tag is wrong.
  */
-TEST_F(EncryptionOperationsTest, AesGcmCorruptTag) {
+TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3862,7 +3831,7 @@
  *
  * Verifies that the max uses per boot tag works correctly with AES keys.
  */
-TEST_F(MaxOperationsTest, TestLimitAes) {
+TEST_P(MaxOperationsTest, TestLimitAes) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3887,7 +3856,7 @@
  *
  * Verifies that the max uses per boot tag works correctly with RSA keys.
  */
-TEST_F(MaxOperationsTest, TestLimitRsa) {
+TEST_P(MaxOperationsTest, TestLimitRsa) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(1024, 3)
@@ -3914,7 +3883,7 @@
  * Verifies that the addRngEntropy method doesn't blow up.  There's no way to test that entropy is
  * actually added.
  */
-TEST_F(AddEntropyTest, AddEntropy) {
+TEST_P(AddEntropyTest, AddEntropy) {
     EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf("foo")));
 }
 
@@ -3923,7 +3892,7 @@
  *
  * Verifies that the addRngEntropy method doesn't blow up when given an empty buffer.
  */
-TEST_F(AddEntropyTest, AddEmptyEntropy) {
+TEST_P(AddEntropyTest, AddEmptyEntropy) {
     EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf()));
 }
 
@@ -3932,7 +3901,7 @@
  *
  * Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data.
  */
-TEST_F(AddEntropyTest, AddLargeEntropy) {
+TEST_P(AddEntropyTest, AddLargeEntropy) {
     EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a'))));
 }
 
@@ -3943,7 +3912,7 @@
  *
  * Verifies that attesting to RSA keys works and generates the expected output.
  */
-TEST_F(AttestationTest, RsaAttestation) {
+TEST_P(AttestationTest, RsaAttestation) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(1024, 3)
@@ -3971,7 +3940,7 @@
  *
  * Verifies that attesting to RSA requires app ID.
  */
-TEST_F(AttestationTest, RsaAttestationRequiresAppId) {
+TEST_P(AttestationTest, RsaAttestationRequiresAppId) {
     ASSERT_EQ(ErrorCode::OK,
               GenerateKey(AuthorizationSetBuilder()
                               .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -3992,7 +3961,7 @@
  *
  * Verifies that attesting to EC keys works and generates the expected output.
  */
-TEST_F(AttestationTest, EcAttestation) {
+TEST_P(AttestationTest, EcAttestation) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .EcdsaSigningKey(EcCurve::P_256)
@@ -4020,7 +3989,7 @@
  *
  * Verifies that attesting to EC keys requires app ID
  */
-TEST_F(AttestationTest, EcAttestationRequiresAttestationAppId) {
+TEST_P(AttestationTest, EcAttestationRequiresAttestationAppId) {
     ASSERT_EQ(ErrorCode::OK,
               GenerateKey(AuthorizationSetBuilder()
                               .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -4040,7 +4009,7 @@
  *
  * Verifies that attesting to AES keys fails in the expected way.
  */
-TEST_F(AttestationTest, AesAttestation) {
+TEST_P(AttestationTest, AesAttestation) {
     ASSERT_EQ(ErrorCode::OK,
               GenerateKey(AuthorizationSetBuilder()
                               .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -4063,7 +4032,7 @@
  *
  * Verifies that attesting to HMAC keys fails in the expected way.
  */
-TEST_F(AttestationTest, HmacAttestation) {
+TEST_P(AttestationTest, HmacAttestation) {
     ASSERT_EQ(ErrorCode::OK,
               GenerateKey(AuthorizationSetBuilder()
                               .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -4090,7 +4059,7 @@
  * This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly
  * valid key blob.
  */
-TEST_F(KeyDeletionTest, DeleteKey) {
+TEST_P(KeyDeletionTest, DeleteKey) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
                                              .Digest(Digest::NONE)
@@ -4135,7 +4104,7 @@
  *
  * This test checks that the HAL excepts invalid key blobs.
  */
-TEST_F(KeyDeletionTest, DeleteInvalidKey) {
+TEST_P(KeyDeletionTest, DeleteInvalidKey) {
     // Generate key just to check if rollback protection is implemented
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
@@ -4172,7 +4141,7 @@
  * been provisioned. Use this test only on dedicated testing devices that have no valuable
  * credentials stored in Keystore/Keymaster.
  */
-TEST_F(KeyDeletionTest, DeleteAllKeys) {
+TEST_P(KeyDeletionTest, DeleteAllKeys) {
     if (!arm_deleteAllKeys) return;
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 3)
@@ -4207,6 +4176,45 @@
     key_blob_ = HidlBuf();
 }
 
+static const auto kKeymasterDeviceChoices =
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor));
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, NewKeyGenerationTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, KeymasterVersionTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, GetKeyCharacteristicsTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, SigningOperationsTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, VerificationOperationsTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, ExportKeyTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, ImportKeyTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, EncryptionOperationsTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, MaxOperationsTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, AddEntropyTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, AttestationTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, KeyDeletionTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
 }  // namespace test
 }  // namespace V3_0
 }  // namespace keymaster
@@ -4214,10 +4222,7 @@
 }  // namespace android
 
 int main(int argc, char** argv) {
-    using android::hardware::keymaster::V3_0::test::KeymasterHidlEnvironment;
-    ::testing::AddGlobalTestEnvironment(KeymasterHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
-    KeymasterHidlEnvironment::Instance()->init(&argc, argv);
     for (int i = 1; i < argc; ++i) {
         if (argv[i][0] == '-') {
             if (std::string(argv[i]) == "--arm_deleteAllKeys") {
diff --git a/keymaster/4.0/Android.bp b/keymaster/4.0/Android.bp
index cd46fd9..ea328f4 100644
--- a/keymaster/4.0/Android.bp
+++ b/keymaster/4.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/keymaster/4.0/IKeymasterDevice.hal b/keymaster/4.0/IKeymasterDevice.hal
index c867ab0..3475f79 100644
--- a/keymaster/4.0/IKeymasterDevice.hal
+++ b/keymaster/4.0/IKeymasterDevice.hal
@@ -624,7 +624,7 @@
     /**
      * Exports a public key, returning the key in the specified format.
      *
-     * @parm keyFormat The format used for export.  See KeyFormat in types.hal.
+     * @parm keyFormat The format used for export.  Must be KeyFormat::X509.
      *
      * @param keyBlob The opaque descriptor returned by generateKey() or importKey().  The
      *        referenced key must be asymmetric.
@@ -639,7 +639,7 @@
      *        value, it must be computationally infeasible for the secure hardware to obtain the key
      *        material.
      *
-     * @return keyMaterial The public key material in PKCS#8 format.
+     * @return keyMaterial The public key material in X.509 format.
      */
     exportKey(KeyFormat keyFormat, vec<uint8_t> keyBlob, vec<uint8_t> clientId,
               vec<uint8_t> appData) generates (ErrorCode error, vec<uint8_t> keyMaterial);
@@ -1005,13 +1005,11 @@
      *
      * -- EC Keys --
      *
-     * EC key operations must specify exactly one padding mode in inParams.  If unspecified or
-     * specified more than once, begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE.
-     *
-     * Private key operations (KeyPurpose::SIGN) need authorization of digest and padding, which
-     * means that the key authorizations must contain the specified values.  If not, begin() must
-     * return ErrorCode::INCOMPATIBLE_DIGEST.  Public key operations (KeyPurpose::VERIFY) are
-     * permitted with unauthorized digest or padding.
+     * EC private key operations must specify exactly one digest in inParams.  If unspecified or
+     * specified more than once, begin() must return ErrorCode::UNSUPPORTED_DIGEST.  For private key
+     * operations, (KeyPurpose::SIGN), if the specified digest is not in the key's authorization
+     * list, begin() must return ErrorCode::INCOMPATIBLE_DIGEST.  Public key operations
+     * (KeyPurpose::VERIFY) are permitted with unauthorized digest.
      *
      * -- AES Keys --
      *
diff --git a/keymaster/4.0/default/Android.bp b/keymaster/4.0/default/Android.bp
index 0cede50..f9e3986 100644
--- a/keymaster/4.0/default/Android.bp
+++ b/keymaster/4.0/default/Android.bp
@@ -28,7 +28,6 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libkeymaster4",
         "liblog",
         "libutils",
diff --git a/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc b/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc
index 2ce439e..2adfd88 100644
--- a/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc
+++ b/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.keymaster-4-0 /vendor/bin/hw/android.hardware.keymaster@4.0-service
+    interface android.hardware.keymaster@4.0::IKeymasterDevice default
     class early_hal
     user system
     group system drmrpc
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
index ccd1b56..2f40282 100644
--- a/keymaster/4.0/support/Android.bp
+++ b/keymaster/4.0/support/Android.bp
@@ -39,7 +39,6 @@
         "libcrypto",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
     ]
 }
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp
index e8db074..1eb9a68 100644
--- a/keymaster/4.0/support/Keymaster.cpp
+++ b/keymaster/4.0/support/Keymaster.cpp
@@ -19,7 +19,7 @@
 #include <iomanip>
 
 #include <android-base/logging.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <keymasterV4_0/Keymaster3.h>
 #include <keymasterV4_0/Keymaster4.h>
 #include <keymasterV4_0/key_param_output.h>
@@ -69,7 +69,7 @@
 namespace support {
 
 using ::android::sp;
-using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hidl::manager::V1_2::IServiceManager;
 
 std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster) {
     auto& version = keymaster.halVersion();
@@ -86,7 +86,7 @@
 
     bool foundDefault = false;
     auto& descriptor = Wrapper::WrappedIKeymasterDevice::descriptor;
-    serviceManager->listByInterface(descriptor, [&](const hidl_vec<hidl_string>& names) {
+    serviceManager->listManifestByInterface(descriptor, [&](const hidl_vec<hidl_string>& names) {
         for (auto& name : names) {
             if (name == "default") foundDefault = true;
             auto device = Wrapper::WrappedIKeymasterDevice::getService(name);
@@ -97,7 +97,7 @@
     });
 
     if (!foundDefault) {
-        // "default" wasn't provided by listByInterface.  Maybe there's a passthrough
+        // "default" wasn't provided by listManifestByInterface.  Maybe there's a passthrough
         // implementation.
         auto device = Wrapper::WrappedIKeymasterDevice::getService("default");
         if (device) result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, "default")));
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index 97dab68..cb29c64 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -280,39 +280,50 @@
  */
 template <typename ValueT>
 class NullOr {
-    template <typename T>
-    struct reference_initializer {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wnull-dereference"
-        static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
-#pragma GCC diagnostic pop
-    };
-    template <typename T>
-    struct pointer_initializer {
-        static T init() { return nullptr; }
-    };
-    template <typename T>
-    struct value_initializer {
-        static T init() { return T(); }
-    };
-    template <typename T>
-    using initializer_t =
-        std::conditional_t<std::is_lvalue_reference<T>::value, reference_initializer<T>,
-                           std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>,
-                                              value_initializer<T>>>;
+    using internal_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value,
+                                          std::remove_reference_t<ValueT>*, ValueT>;
 
-   public:
-    NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
-    NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}
+    struct pointer_initializer {
+        static std::nullptr_t init() { return nullptr; }
+    };
+    struct value_initializer {
+        static ValueT init() { return ValueT(); }
+    };
+    struct value_pointer_deref_t {
+        static ValueT& deref(ValueT& v) { return v; }
+    };
+    struct reference_deref_t {
+        static auto& deref(internal_t v) { return *v; }
+    };
+    using initializer_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value ||
+                                                     std::is_pointer<ValueT>::value,
+                                             pointer_initializer, value_initializer>;
+    using deref_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value, reference_deref_t,
+                                       value_pointer_deref_t>;
+
+  public:
+    NullOr() : value_(initializer_t::init()), null_(true) {}
+    template <typename T>
+    NullOr(T&& value, typename std::enable_if<
+                              !std::is_lvalue_reference<ValueT>::value &&
+                                      std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value,
+                              int>::type = 0)
+        : value_(std::forward<ValueT>(value)), null_(false) {}
+    template <typename T>
+    NullOr(T& value, typename std::enable_if<
+                             std::is_lvalue_reference<ValueT>::value &&
+                                     std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value,
+                             int>::type = 0)
+        : value_(&value), null_(false) {}
 
     bool isOk() const { return !null_; }
 
-    const ValueT& value() const & { return value_; }
-    ValueT& value() & { return value_; }
-    ValueT&& value() && { return std::move(value_); }
+    const ValueT& value() const& { return deref_t::deref(value_); }
+    ValueT& value() & { return deref_t::deref(value_); }
+    ValueT&& value() && { return std::move(deref_t::deref(value_)); }
 
-   private:
-    ValueT value_;
+  private:
+    internal_t value_;
     bool null_;
 };
 
diff --git a/keymaster/4.0/vts/OWNERS b/keymaster/4.0/vts/OWNERS
index 376c12b..abfb2e0 100644
--- a/keymaster/4.0/vts/OWNERS
+++ b/keymaster/4.0/vts/OWNERS
@@ -1,3 +1,4 @@
+jbires@google.com
 jdanis@google.com
 swillden@google.com
 yim@google.com
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index 333e408..5649f20 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -25,9 +25,9 @@
     ],
     static_libs: [
         "android.hardware.keymaster@4.0",
-        "libcrypto",
+        "libcrypto_static",
         "libkeymaster4support",
         "libsoftkeymasterdevice",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/keymaster/4.0/vts/functional/AndroidTest.xml b/keymaster/4.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..dcf7129
--- /dev/null
+++ b/keymaster/4.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 VtsHalKeymasterV4_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="VtsHalKeymasterV4_0TargetTest->/data/local/tmp/VtsHalKeymasterV4_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="VtsHalKeymasterV4_0TargetTest" />
+        <option name="native-test-timeout" value="900000"/>
+    </test>
+</configuration>
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
index f159796..c228ef7 100644
--- a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -101,7 +101,7 @@
     }
 };
 
-TEST_F(HmacKeySharingTest, GetParameters) {
+TEST_P(HmacKeySharingTest, GetParameters) {
     auto result1 = getHmacSharingParameters(keymaster());
     EXPECT_EQ(ErrorCode::OK, result1.error);
 
@@ -114,7 +114,7 @@
         << "A given keymaster should always return the same nonce until restart.";
 }
 
-TEST_F(HmacKeySharingTest, ComputeSharedHmac) {
+TEST_P(HmacKeySharingTest, ComputeSharedHmac) {
     auto params = getHmacSharingParameters(all_keymasters());
     ASSERT_EQ(all_keymasters().size(), params.size())
         << "One or more keymasters failed to provide parameters.";
@@ -143,8 +143,8 @@
 template <class F>
 class final_action {
    public:
-    explicit final_action(F f) : f_(move(f)) {}
-    ~final_action() { f_(); }
+     explicit final_action(F f) : f_(std::move(f)) {}
+     ~final_action() { f_(); }
 
    private:
     F f_;
@@ -155,7 +155,7 @@
     return final_action<F>(f);
 }
 
-TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) {
+TEST_P(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) {
     // Important: The execution of this test gets the keymaster implementations on the device out of
     // sync with respect to the HMAC key.  Granted that VTS tests aren't run on in-use production
     // devices, this still has the potential to cause confusion.  To mitigate that, we always
@@ -194,7 +194,7 @@
     }
 }
 
-TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) {
+TEST_P(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) {
     // Important: The execution of this test gets the keymaster implementations on the device out of
     // sync with respect to the HMAC key.  Granted that VTS tests aren't run on in-use production
     // devices, this still has the potential to cause confusion.  To mitigate that, we always
@@ -236,6 +236,11 @@
     }
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, HmacKeySharingTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 }  // namespace test
 }  // namespace V4_0
 }  // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 3af1df3..07409f6 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -41,17 +41,9 @@
 
 namespace test {
 
-sp<IKeymasterDevice> KeymasterHidlTest::keymaster_;
-std::vector<sp<IKeymasterDevice>> KeymasterHidlTest::all_keymasters_;
-uint32_t KeymasterHidlTest::os_version_;
-uint32_t KeymasterHidlTest::os_patch_level_;
-SecurityLevel KeymasterHidlTest::securityLevel_;
-hidl_string KeymasterHidlTest::name_;
-hidl_string KeymasterHidlTest::author_;
-
-void KeymasterHidlTest::SetUpTestCase() {
-    string service_name = KeymasterHidlEnvironment::Instance()->getServiceName<IKeymasterDevice>();
-    keymaster_ = ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(service_name);
+void KeymasterHidlTest::InitializeKeymaster() {
+    service_name_ = GetParam();
+    keymaster_ = IKeymasterDevice::getService(service_name_);
     ASSERT_NE(keymaster_, nullptr);
 
     ASSERT_TRUE(keymaster_
@@ -62,20 +54,22 @@
                         author_ = author;
                     })
                     .isOk());
+}
+
+void KeymasterHidlTest::SetUp() {
+    InitializeKeymaster();
 
     os_version_ = ::keymaster::GetOsVersion();
     os_patch_level_ = ::keymaster::GetOsPatchlevel();
 
     auto service_manager = android::hidl::manager::V1_0::IServiceManager::getService();
     ASSERT_NE(nullptr, service_manager.get());
-
     all_keymasters_.push_back(keymaster_);
     service_manager->listByInterface(
         IKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) {
             for (auto& name : names) {
-                if (name == service_name) continue;
-                auto keymaster =
-                    ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(name);
+                if (name == service_name_) continue;
+                auto keymaster = IKeymasterDevice::getService(name);
                 ASSERT_NE(keymaster, nullptr);
                 all_keymasters_.push_back(keymaster);
             }
@@ -217,8 +211,8 @@
             std::chrono::time_point<std::chrono::system_clock> reported_time{
                     std::chrono::milliseconds(sw_enforced[i].f.dateTime)};
             // The test is flaky for EC keys, so a buffer time of 120 seconds will be added.
-            EXPECT_LE(creation - 120s, reported_time);
-            EXPECT_LE(reported_time, now + 1s);
+            EXPECT_LE(creation - std::chrono::seconds(120), reported_time);
+            EXPECT_LE(reported_time, now + std::chrono::seconds(1));
         }
     }
 }
@@ -269,6 +263,13 @@
     return GetCharacteristics(key_blob, client_id, app_data, key_characteristics);
 }
 
+ErrorCode KeymasterHidlTest::GetDebugInfo(DebugInfo* debug_info) {
+    EXPECT_TRUE(keymaster_->getDebugInfo([&](const DebugInfo& hidl_debug_info) {
+      *debug_info = hidl_debug_info;
+    }).isOk());
+    return ErrorCode::OK;
+}
+
 ErrorCode KeymasterHidlTest::Begin(KeyPurpose purpose, const HidlBuf& key_blob,
                                    const AuthorizationSet& in_params, AuthorizationSet* out_params,
                                    OperationHandle* op_handle) {
@@ -611,6 +612,20 @@
     return ciphertext;
 }
 
+string KeymasterHidlTest::EncryptMessage(const string& message, BlockMode block_mode,
+                                         PaddingMode padding, uint8_t mac_length_bits,
+                                         const HidlBuf& iv_in) {
+    SCOPED_TRACE("EncryptMessage");
+    auto params = AuthorizationSetBuilder()
+                          .BlockMode(block_mode)
+                          .Padding(padding)
+                          .Authorization(TAG_MAC_LENGTH, mac_length_bits)
+                          .Authorization(TAG_NONCE, iv_in);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    return ciphertext;
+}
+
 string KeymasterHidlTest::DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
                                          const AuthorizationSet& params) {
     SCOPED_TRACE("DecryptMessage");
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index 015fc43..adceead 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
+#pragma once
 
 #include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
 #include <android/hardware/keymaster/4.0/types.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <keymaster/keymaster_configuration.h>
 
 #include <keymasterV4_0/authorization_set.h>
@@ -37,6 +36,7 @@
 
 using ::android::sp;
 using ::std::string;
+using hidl::base::V1_0::DebugInfo;
 
 class HidlBuf : public hidl_vec<uint8_t> {
     typedef hidl_vec<uint8_t> super;
@@ -68,42 +68,24 @@
 
 constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;
 
-class KeymasterHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static KeymasterHidlEnvironment* Instance() {
-        static KeymasterHidlEnvironment* instance = new KeymasterHidlEnvironment;
-        return instance;
-    }
-
-    void registerTestServices() override { registerTestService<IKeymasterDevice>(); }
-
-   private:
-    KeymasterHidlEnvironment(){};
-
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(KeymasterHidlEnvironment);
-};
-
-class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
+class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp();
     void TearDown() override {
         if (key_blob_.size()) {
             CheckedDeleteKey();
         }
         AbortIfNeeded();
-    }
-
-    // SetUpTestCase runs only once per test case, not once per test.
-    static void SetUpTestCase();
-    static void TearDownTestCase() {
         keymaster_.clear();
         all_keymasters_.clear();
     }
 
-    static IKeymasterDevice& keymaster() { return *keymaster_; }
-    static const std::vector<sp<IKeymasterDevice>>& all_keymasters() { return all_keymasters_; }
-    static uint32_t os_version() { return os_version_; }
-    static uint32_t os_patch_level() { return os_patch_level_; }
+    void InitializeKeymaster();
+
+    IKeymasterDevice& keymaster() { return *keymaster_; }
+    const std::vector<sp<IKeymasterDevice>>& all_keymasters() { return all_keymasters_; }
+    uint32_t os_version() { return os_version_; }
+    uint32_t os_patch_level() { return os_patch_level_; }
 
     ErrorCode GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
                           KeyCharacteristics* key_characteristics);
@@ -140,6 +122,8 @@
                                  const HidlBuf& app_data, KeyCharacteristics* key_characteristics);
     ErrorCode GetCharacteristics(const HidlBuf& key_blob, KeyCharacteristics* key_characteristics);
 
+    ErrorCode GetDebugInfo(DebugInfo* debug_info);
+
     ErrorCode Begin(KeyPurpose purpose, const HidlBuf& key_blob, const AuthorizationSet& in_params,
                     AuthorizationSet* out_params, OperationHandle* op_handle);
     ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
@@ -201,6 +185,8 @@
                           HidlBuf* iv_out);
     string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
                           const HidlBuf& iv_in);
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+                          uint8_t mac_length_bits, const HidlBuf& iv_in);
 
     string DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
                           const AuthorizationSet& params);
@@ -210,8 +196,8 @@
 
     std::pair<ErrorCode, HidlBuf> UpgradeKey(const HidlBuf& key_blob);
 
-    static bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }
-    static SecurityLevel SecLevel() { return securityLevel_; }
+    bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }
+    SecurityLevel SecLevel() { return securityLevel_; }
 
     std::vector<uint32_t> ValidKeySizes(Algorithm algorithm);
     std::vector<uint32_t> InvalidKeySizes(Algorithm algorithm);
@@ -227,14 +213,15 @@
     OperationHandle op_handle_ = kOpHandleSentinel;
 
    private:
-    static sp<IKeymasterDevice> keymaster_;
-    static std::vector<sp<IKeymasterDevice>> all_keymasters_;
-    static uint32_t os_version_;
-    static uint32_t os_patch_level_;
+     sp<IKeymasterDevice> keymaster_;
+     std::vector<sp<IKeymasterDevice>> all_keymasters_;
+     uint32_t os_version_;
+     uint32_t os_patch_level_;
 
-    static SecurityLevel securityLevel_;
-    static hidl_string name_;
-    static hidl_string author_;
+     SecurityLevel securityLevel_;
+     hidl_string name_;
+     hidl_string author_;
+     string service_name_;
 };
 
 }  // namespace test
@@ -242,5 +229,3 @@
 }  // namespace keymaster
 }  // namespace hardware
 }  // namespace android
-
-#endif  // HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
diff --git a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
index 3876b16..693f4ae 100644
--- a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
+++ b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
@@ -75,7 +75,7 @@
  * thing we really can test is that tokens can be created by TEE keymasters, and that the
  * timestamps increase as expected.
  */
-TEST_F(VerificationTokenTest, TestCreation) {
+TEST_P(VerificationTokenTest, TestCreation) {
     auto result1 = verifyAuthorization(
         1 /* operation handle */, AuthorizationSet() /* paramtersToVerify */, HardwareAuthToken());
     ASSERT_TRUE(result1.callSuccessful);
@@ -124,8 +124,72 @@
     // report if times aren't nearly always <1ms apart.
     EXPECT_LE(host_time_delta, km_time_delta + 2);
     EXPECT_LE(km_time_delta, host_time_delta + 2);
+    ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
+    ASSERT_NE(0,
+              memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
 }
 
+/*
+ * Test that the mac changes when the time stamp changes. This is does not guarantee that the time
+ * stamp is included in the mac but on failure we know that it is not. Other than in the test
+ * case above we call verifyAuthorization with the exact same set of parameters.
+ */
+TEST_P(VerificationTokenTest, MacChangesOnChangingTimestamp) {
+    auto result1 =
+            verifyAuthorization(0 /* operation handle */,
+                                AuthorizationSet() /* paramtersToVerify */, HardwareAuthToken());
+    ASSERT_TRUE(result1.callSuccessful);
+    auto result1_time = getTime();
+
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        // StrongBox should not implement verifyAuthorization.
+        EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error);
+        return;
+    }
+
+    EXPECT_EQ(ErrorCode::OK, result1.error);
+    EXPECT_EQ(0U, result1.token.challenge);
+    EXPECT_EQ(SecLevel(), result1.token.securityLevel);
+    EXPECT_EQ(0U, result1.token.parametersVerified.size())
+            << "We didn't supply any parameters to verify";
+    EXPECT_GT(result1.token.timestamp, 0U);
+
+    constexpr uint32_t time_to_sleep = 200;
+    sleep_ms(time_to_sleep);
+
+    auto result2 =
+            verifyAuthorization(0 /* operation handle */,
+                                AuthorizationSet() /* paramtersToVerify */, HardwareAuthToken());
+    ASSERT_TRUE(result2.callSuccessful);
+    auto result2_time = getTime();
+    EXPECT_EQ(ErrorCode::OK, result2.error);
+    EXPECT_EQ(0U, result2.token.challenge);
+    EXPECT_EQ(SecLevel(), result2.token.securityLevel);
+    EXPECT_EQ(0U, result2.token.parametersVerified.size())
+            << "We didn't supply any parameters to verify";
+
+    auto host_time_delta = result2_time - result1_time;
+
+    EXPECT_GE(host_time_delta, time_to_sleep)
+            << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
+    EXPECT_LE(host_time_delta, time_to_sleep + 20)
+            << "The verifyAuthorization call took " << (host_time_delta - time_to_sleep)
+            << " ms?  That's awful!";
+
+    auto km_time_delta = result2.token.timestamp - result1.token.timestamp;
+
+    EXPECT_LE(host_time_delta, km_time_delta + 2);
+    EXPECT_LE(km_time_delta, host_time_delta + 2);
+    ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
+    ASSERT_NE(0,
+              memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, VerificationTokenTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 }  // namespace test
 }  // namespace V4_0
 }  // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 728bf69..35a2fb1 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -18,6 +18,7 @@
 #include <cutils/log.h>
 
 #include <iostream>
+#include <signal.h>
 
 #include <openssl/evp.h>
 #include <openssl/mem.h>
@@ -521,14 +522,14 @@
  * Verifies that keymaster can generate all required RSA key sizes, and that the resulting keys have
  * correct characteristics.
  */
-TEST_F(NewKeyGenerationTest, Rsa) {
+TEST_P(NewKeyGenerationTest, Rsa) {
     for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
         HidlBuf key_blob;
         KeyCharacteristics key_characteristics;
         ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .RsaSigningKey(key_size, 3)
-                                                 .Digest(Digest::NONE)
-                                                 .Padding(PaddingMode::NONE),
+                                                     .RsaSigningKey(key_size, 65537)
+                                                     .Digest(Digest::NONE)
+                                                     .Padding(PaddingMode::NONE),
                                              &key_blob, &key_characteristics));
 
         ASSERT_GT(key_blob.size(), 0U);
@@ -556,7 +557,7 @@
  *
  * Verifies that creation date time is correct.
  */
-TEST_F(NewKeyGenerationTest, RsaCheckCreationDateTime) {
+TEST_P(NewKeyGenerationTest, RsaCheckCreationDateTime) {
     KeyCharacteristics key_characteristics;
     auto creation_time = std::chrono::system_clock::now();
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -574,15 +575,16 @@
  *
  * Verifies that keymaster cannot generate any RSA key sizes that are designated as invalid.
  */
-TEST_F(NewKeyGenerationTest, NoInvalidRsaSizes) {
+TEST_P(NewKeyGenerationTest, NoInvalidRsaSizes) {
     for (auto key_size : InvalidKeySizes(Algorithm::RSA)) {
         HidlBuf key_blob;
         KeyCharacteristics key_characteristics;
-        ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, GenerateKey(AuthorizationSetBuilder()
-                                                                   .RsaSigningKey(key_size, 3)
-                                                                   .Digest(Digest::NONE)
-                                                                   .Padding(PaddingMode::NONE),
-                                                               &key_blob, &key_characteristics));
+        ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+                  GenerateKey(AuthorizationSetBuilder()
+                                      .RsaSigningKey(key_size, 65537)
+                                      .Digest(Digest::NONE)
+                                      .Padding(PaddingMode::NONE),
+                              &key_blob, &key_characteristics));
     }
 }
 
@@ -591,7 +593,7 @@
  *
  * Verifies that failing to specify a key size for RSA key generation returns UNSUPPORTED_KEY_SIZE.
  */
-TEST_F(NewKeyGenerationTest, RsaNoDefaultSize) {
+TEST_P(NewKeyGenerationTest, RsaNoDefaultSize) {
     ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
               GenerateKey(AuthorizationSetBuilder()
                               .Authorization(TAG_ALGORITHM, Algorithm::RSA)
@@ -605,7 +607,7 @@
  * Verifies that keymaster can generate all required EC key sizes, and that the resulting keys have
  * correct characteristics.
  */
-TEST_F(NewKeyGenerationTest, Ecdsa) {
+TEST_P(NewKeyGenerationTest, Ecdsa) {
     for (auto key_size : ValidKeySizes(Algorithm::EC)) {
         HidlBuf key_blob;
         KeyCharacteristics key_characteristics;
@@ -637,7 +639,7 @@
  *
  * Verifies that creation date time is correct.
  */
-TEST_F(NewKeyGenerationTest, EcCheckCreationDateTime) {
+TEST_P(NewKeyGenerationTest, EcCheckCreationDateTime) {
     KeyCharacteristics key_characteristics;
     auto creation_time = std::chrono::system_clock::now();
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -654,7 +656,7 @@
  *
  * Verifies that failing to specify a key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
  */
-TEST_F(NewKeyGenerationTest, EcdsaDefaultSize) {
+TEST_P(NewKeyGenerationTest, EcdsaDefaultSize) {
     ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
               GenerateKey(AuthorizationSetBuilder()
                               .Authorization(TAG_ALGORITHM, Algorithm::EC)
@@ -667,7 +669,7 @@
  *
  * Verifies that specifying an invalid key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
  */
-TEST_F(NewKeyGenerationTest, EcdsaInvalidSize) {
+TEST_P(NewKeyGenerationTest, EcdsaInvalidSize) {
     for (auto key_size : InvalidKeySizes(Algorithm::EC)) {
         HidlBuf key_blob;
         KeyCharacteristics key_characteristics;
@@ -687,7 +689,7 @@
  * Verifies that specifying mismatched key size and curve for EC key generation returns
  * INVALID_ARGUMENT.
  */
-TEST_F(NewKeyGenerationTest, EcdsaMismatchKeySize) {
+TEST_P(NewKeyGenerationTest, EcdsaMismatchKeySize) {
     if (SecLevel() == SecurityLevel::STRONGBOX) return;
 
     ASSERT_EQ(ErrorCode::INVALID_ARGUMENT,
@@ -702,7 +704,7 @@
  *
  * Verifies that keymaster supports all required EC key sizes.
  */
-TEST_F(NewKeyGenerationTest, EcdsaAllValidSizes) {
+TEST_P(NewKeyGenerationTest, EcdsaAllValidSizes) {
     auto valid_sizes = ValidKeySizes(Algorithm::EC);
     for (size_t size : valid_sizes) {
         EXPECT_EQ(ErrorCode::OK,
@@ -718,7 +720,7 @@
  *
  * Verifies that keymaster does not support any curve designated as unsupported.
  */
-TEST_F(NewKeyGenerationTest, EcdsaAllValidCurves) {
+TEST_P(NewKeyGenerationTest, EcdsaAllValidCurves) {
     Digest digest;
     if (SecLevel() == SecurityLevel::STRONGBOX) {
         digest = Digest::SHA_2_256;
@@ -741,7 +743,7 @@
  * Verifies that keymaster supports all required digests, and that the resulting keys have correct
  * characteristics.
  */
-TEST_F(NewKeyGenerationTest, Hmac) {
+TEST_P(NewKeyGenerationTest, Hmac) {
     for (auto digest : ValidDigests(false /* withNone */, true /* withMD5 */)) {
         HidlBuf key_blob;
         KeyCharacteristics key_characteristics;
@@ -777,7 +779,7 @@
  *
  * Verifies that keymaster supports all key sizes, and rejects all invalid key sizes.
  */
-TEST_F(NewKeyGenerationTest, HmacCheckKeySizes) {
+TEST_P(NewKeyGenerationTest, HmacCheckKeySizes) {
     for (size_t key_size = 0; key_size <= 512; ++key_size) {
         if (key_size < 64 || key_size % 8 != 0) {
             // To keep this test from being very slow, we only test a random fraction of non-byte
@@ -810,7 +812,7 @@
  * test is probabilistic in order to keep the runtime down, but any failure prints out the specific
  * MAC length that failed, so reproducing a failed run will be easy.
  */
-TEST_F(NewKeyGenerationTest, HmacCheckMinMacLengths) {
+TEST_P(NewKeyGenerationTest, HmacCheckMinMacLengths) {
     for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) {
         if (min_mac_length < 64 || min_mac_length % 8 != 0) {
             // To keep this test from being very long, we only test a random fraction of non-byte
@@ -842,7 +844,7 @@
  *
  * Verifies that keymaster rejects HMAC key generation with multiple specified digest algorithms.
  */
-TEST_F(NewKeyGenerationTest, HmacMultipleDigests) {
+TEST_P(NewKeyGenerationTest, HmacMultipleDigests) {
     if (SecLevel() == SecurityLevel::STRONGBOX) return;
 
     ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
@@ -858,7 +860,7 @@
  *
  * Verifies that keymaster rejects HMAC key generation with no digest or Digest::NONE
  */
-TEST_F(NewKeyGenerationTest, HmacDigestNone) {
+TEST_P(NewKeyGenerationTest, HmacDigestNone) {
     ASSERT_EQ(
         ErrorCode::UNSUPPORTED_DIGEST,
         GenerateKey(AuthorizationSetBuilder().HmacKey(128).Authorization(TAG_MIN_MAC_LENGTH, 128)));
@@ -877,7 +879,7 @@
  *
  * Verifies that raw RSA signature operations succeed.
  */
-TEST_F(SigningOperationsTest, RsaSuccess) {
+TEST_P(SigningOperationsTest, RsaSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Digest(Digest::NONE)
@@ -893,7 +895,7 @@
  *
  * Verifies that getting RSA key characteristics requires the correct app ID/data.
  */
-TEST_F(SigningOperationsTest, RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData) {
+TEST_P(SigningOperationsTest, RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData) {
     HidlBuf key_blob;
     KeyCharacteristics key_characteristics;
     ASSERT_EQ(ErrorCode::OK,
@@ -914,7 +916,7 @@
  *
  * Verifies that using an RSA key requires the correct app ID/data.
  */
-TEST_F(SigningOperationsTest, RsaUseRequiresCorrectAppIdAppData) {
+TEST_P(SigningOperationsTest, RsaUseRequiresCorrectAppIdAppData) {
     ASSERT_EQ(ErrorCode::OK,
               GenerateKey(AuthorizationSetBuilder()
                                   .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -956,7 +958,7 @@
  *
  * Verifies that RSA-PSS signature operations succeed.
  */
-TEST_F(SigningOperationsTest, RsaPssSha256Success) {
+TEST_P(SigningOperationsTest, RsaPssSha256Success) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Digest(Digest::SHA_2_256)
@@ -974,7 +976,7 @@
  * Verifies that keymaster rejects signature operations that specify a padding mode when the key
  * supports only unpadded operations.
  */
-TEST_F(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
+TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Digest(Digest::NONE)
@@ -996,7 +998,7 @@
  * TRUSTED_CONFIRMATION_REQUIRED and no valid confirmation token
  * presented.
  */
-TEST_F(SigningOperationsTest, NoUserConfirmation) {
+TEST_P(SigningOperationsTest, NoUserConfirmation) {
     if (SecLevel() == SecurityLevel::STRONGBOX) return;
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 65537)
@@ -1018,7 +1020,7 @@
  *
  * Verifies that digested RSA-PKCS1 signature operations succeed.
  */
-TEST_F(SigningOperationsTest, RsaPkcs1Sha256Success) {
+TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Digest(Digest::SHA_2_256)
@@ -1035,7 +1037,7 @@
  *
  * Verifies that undigested RSA-PKCS1 signature operations succeed.
  */
-TEST_F(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Digest(Digest::NONE)
@@ -1053,7 +1055,7 @@
  * Verifies that undigested RSA-PKCS1 signature operations fail with the correct error code when
  * given a too-long message.
  */
-TEST_F(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Digest(Digest::NONE)
@@ -1081,7 +1083,7 @@
  * uses SHA512, which has a digest_size == 512, so the message size is 1040 bits, too large for a
  * 1024-bit key.
  */
-TEST_F(SigningOperationsTest, RsaPssSha512TooSmallKey) {
+TEST_P(SigningOperationsTest, RsaPssSha512TooSmallKey) {
     if (SecLevel() == SecurityLevel::STRONGBOX) return;
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(1024, 65537)
@@ -1100,7 +1102,7 @@
  * Verifies that raw RSA signature operations fail with the correct error code when
  * given a too-long message.
  */
-TEST_F(SigningOperationsTest, RsaNoPaddingTooLong) {
+TEST_P(SigningOperationsTest, RsaNoPaddingTooLong) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Digest(Digest::NONE)
@@ -1134,7 +1136,7 @@
  * Verifies that operations can be aborted correctly.  Uses an RSA signing operation for the test,
  * but the behavior should be algorithm and purpose-independent.
  */
-TEST_F(SigningOperationsTest, RsaAbort) {
+TEST_P(SigningOperationsTest, RsaAbort) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Digest(Digest::NONE)
@@ -1159,7 +1161,7 @@
  * Verifies that RSA operations fail with the correct error (but key gen succeeds) when used with a
  * padding mode inappropriate for RSA.
  */
-TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
+TEST_P(SigningOperationsTest, RsaUnsupportedPadding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1176,7 +1178,7 @@
  *
  * Verifies that RSA PSS operations fail when no digest is used.  PSS requires a digest.
  */
-TEST_F(SigningOperationsTest, RsaNoDigest) {
+TEST_P(SigningOperationsTest, RsaNoDigest) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1196,7 +1198,7 @@
  * Verifies that RSA operations fail when no padding mode is specified.  PaddingMode::NONE is
  * supported in some cases (as validated in other tests), but a mode must be specified.
  */
-TEST_F(SigningOperationsTest, RsaNoPadding) {
+TEST_P(SigningOperationsTest, RsaNoPadding) {
     // Padding must be specified
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaKey(2048, 65537)
@@ -1212,7 +1214,7 @@
  *
  * Verifies that raw RSA signatures succeed with a message shorter than the key size.
  */
-TEST_F(SigningOperationsTest, RsaTooShortMessage) {
+TEST_P(SigningOperationsTest, RsaTooShortMessage) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(2048, 65537)
@@ -1233,7 +1235,7 @@
  *
  * Verifies that RSA encryption keys cannot be used to sign.
  */
-TEST_F(SigningOperationsTest, RsaSignWithEncryptionKey) {
+TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(2048, 65537)
@@ -1250,7 +1252,7 @@
  * Verifies that attempting a raw signature of a message which is the same length as the key, but
  * numerically larger than the public modulus, fails with the correct error.
  */
-TEST_F(SigningOperationsTest, RsaSignTooLargeMessage) {
+TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(2048, 65537)
@@ -1272,7 +1274,7 @@
  *
  * Verifies that ECDSA operations succeed with all possible key sizes and hashes.
  */
-TEST_F(SigningOperationsTest, EcdsaAllSizesAndHashes) {
+TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) {
     for (auto key_size : ValidKeySizes(Algorithm::EC)) {
         for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) {
             ErrorCode error = GenerateKey(AuthorizationSetBuilder()
@@ -1296,7 +1298,7 @@
  *
  * Verifies that ECDSA operations succeed with all possible curves.
  */
-TEST_F(SigningOperationsTest, EcdsaAllCurves) {
+TEST_P(SigningOperationsTest, EcdsaAllCurves) {
     for (auto curve : ValidCurves()) {
         ErrorCode error = GenerateKey(AuthorizationSetBuilder()
                                           .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1318,7 +1320,7 @@
  * work because ECDSA actually only signs the leftmost L_n bits of the message, however large it may
  * be.  Not using digesting is a bad idea, but in some cases digesting is done by the framework.
  */
-TEST_F(SigningOperationsTest, EcdsaNoDigestHugeData) {
+TEST_P(SigningOperationsTest, EcdsaNoDigestHugeData) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .EcdsaSigningKey(256)
@@ -1332,7 +1334,7 @@
  *
  * Verifies that getting EC key characteristics requires the correct app ID/data.
  */
-TEST_F(SigningOperationsTest, EcGetKeyCharacteristicsRequiresCorrectAppIdAppData) {
+TEST_P(SigningOperationsTest, EcGetKeyCharacteristicsRequiresCorrectAppIdAppData) {
     HidlBuf key_blob;
     KeyCharacteristics key_characteristics;
     ASSERT_EQ(ErrorCode::OK,
@@ -1352,7 +1354,7 @@
  *
  * Verifies that using an EC key requires the correct app ID/data.
  */
-TEST_F(SigningOperationsTest, EcUseRequiresCorrectAppIdAppData) {
+TEST_P(SigningOperationsTest, EcUseRequiresCorrectAppIdAppData) {
     ASSERT_EQ(ErrorCode::OK,
               GenerateKey(AuthorizationSetBuilder()
                                   .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1389,7 +1391,7 @@
  *
  * Verifies that attempts to use AES keys to sign fail in the correct way.
  */
-TEST_F(SigningOperationsTest, AesEcbSign) {
+TEST_P(SigningOperationsTest, AesEcbSign) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .SigningKey()
@@ -1408,7 +1410,7 @@
  *
  * Verifies that HMAC works with all digests.
  */
-TEST_F(SigningOperationsTest, HmacAllDigests) {
+TEST_P(SigningOperationsTest, HmacAllDigests) {
     for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) {
         ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1430,7 +1432,7 @@
  * Verifies that HMAC fails in the correct way when asked to generate a MAC larger than the digest
  * size.
  */
-TEST_F(SigningOperationsTest, HmacSha256TooLargeMacLength) {
+TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .HmacKey(128)
@@ -1451,7 +1453,7 @@
  * Verifies that HMAC fails in the correct way when asked to generate a MAC smaller than the
  * specified minimum MAC length.
  */
-TEST_F(SigningOperationsTest, HmacSha256TooSmallMacLength) {
+TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .HmacKey(128)
@@ -1471,7 +1473,7 @@
  *
  * Validates against the test vectors from RFC 4231 test case 3.
  */
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase3) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) {
     string key(20, 0xaa);
     string message(50, 0xdd);
     uint8_t sha_224_expected[] = {
@@ -1510,7 +1512,7 @@
  *
  * Validates against the test vectors from RFC 4231 test case 5.
  */
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase5) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) {
     string key(20, 0x0c);
     string message = "Test With Truncation";
 
@@ -1539,89 +1541,6 @@
     }
 }
 
-/*
- * SigningOperationsTest.HmacRfc4231TestCase6
- *
- * Validates against the test vectors from RFC 4231 test case 6.
- */
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase6) {
-    string key(131, 0xaa);
-    string message = "Test Using Larger Than Block-Size Key - Hash Key First";
-
-    uint8_t sha_224_expected[] = {
-        0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad, 0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d,
-        0xbc, 0xe2, 0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27, 0x3f, 0xa6, 0x87, 0x0e,
-    };
-    uint8_t sha_256_expected[] = {
-        0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26,
-        0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28,
-        0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54,
-    };
-    uint8_t sha_384_expected[] = {
-        0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, 0x88, 0xd2, 0xc6, 0x3a,
-        0x04, 0x1b, 0xc5, 0xb4, 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
-        0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, 0x0c, 0x2e, 0xf6, 0xab,
-        0x40, 0x30, 0xfe, 0x82, 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52,
-    };
-    uint8_t sha_512_expected[] = {
-        0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1, 0xdd,
-        0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, 0x12, 0x1b,
-        0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25,
-        0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, 0x95, 0xe6, 0x4f, 0x73,
-        0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98,
-    };
-
-    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
-    if (SecLevel() != SecurityLevel::STRONGBOX) {
-        CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
-        CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
-        CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
-    }
-}
-
-/*
- * SigningOperationsTest.HmacRfc4231TestCase7
- *
- * Validates against the test vectors from RFC 4231 test case 7.
- */
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase7) {
-    string key(131, 0xaa);
-    string message =
-        "This is a test using a larger than block-size key and a larger than "
-        "block-size data. The key needs to be hashed before being used by the HMAC "
-        "algorithm.";
-
-    uint8_t sha_224_expected[] = {
-        0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02, 0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3,
-        0x9d, 0xbd, 0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9, 0xf6, 0xf5, 0x65, 0xd1,
-    };
-    uint8_t sha_256_expected[] = {
-        0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f,
-        0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07,
-        0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2,
-    };
-    uint8_t sha_384_expected[] = {
-        0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25,
-        0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
-        0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31,
-        0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e,
-    };
-    uint8_t sha_512_expected[] = {
-        0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9, 0x6e,
-        0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, 0x5d, 0xf5,
-        0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82,
-        0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, 0x13, 0x46, 0x76, 0xfb,
-        0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58,
-    };
-
-    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
-    if (SecLevel() != SecurityLevel::STRONGBOX) {
-        CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
-        CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
-        CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
-    }
-}
-
 typedef KeymasterHidlTest VerificationOperationsTest;
 
 /*
@@ -1629,7 +1548,7 @@
  *
  * Verifies that a simple RSA signature/verification sequence succeeds.
  */
-TEST_F(VerificationOperationsTest, RsaSuccess) {
+TEST_P(VerificationOperationsTest, RsaSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(2048, 65537)
@@ -1647,7 +1566,7 @@
  *
  * Verifies RSA signature/verification for all padding modes and digests.
  */
-TEST_F(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
+TEST_P(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
     auto authorizations = AuthorizationSetBuilder()
                               .Authorization(TAG_NO_AUTH_REQUIRED)
                               .RsaSigningKey(2048, 65537)
@@ -1741,7 +1660,7 @@
  *
  * Verifies ECDSA signature/verification for all digests and curves.
  */
-TEST_F(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
+TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
     auto digests = ValidDigests(true /* withNone */, false /* withMD5 */);
 
     string message = "1234567890";
@@ -1821,7 +1740,7 @@
  *
  * Verifies HMAC signing and verification, but that a signing key cannot be used to verify.
  */
-TEST_F(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
+TEST_P(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
     string key_material = "HelloThisIsAKey";
 
     HidlBuf signing_key, verification_key;
@@ -1869,7 +1788,7 @@
  *
  * Verifies that attempting to export RSA keys in PKCS#8 format fails with the correct error.
  */
-TEST_F(ExportKeyTest, RsaUnsupportedKeyFormat) {
+TEST_P(ExportKeyTest, RsaUnsupportedKeyFormat) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .RsaSigningKey(2048, 65537)
                                              .Digest(Digest::NONE)
@@ -1884,7 +1803,7 @@
  * Verifies that attempting to export RSA keys from corrupted key blobs fails.  This is essentially
  * a poor-man's key blob fuzzer.
  */
-TEST_F(ExportKeyTest, RsaCorruptedKeyBlob) {
+TEST_P(ExportKeyTest, RsaCorruptedKeyBlob) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(2048, 65537)
@@ -1907,7 +1826,7 @@
  * Verifies that attempting to export ECDSA keys from corrupted key blobs fails.  This is
  * essentially a poor-man's key blob fuzzer.
  */
-TEST_F(ExportKeyTest, EcCorruptedKeyBlob) {
+TEST_P(ExportKeyTest, EcCorruptedKeyBlob) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .EcdsaSigningKey(EcCurve::P_256)
@@ -1928,7 +1847,7 @@
  *
  * Verifies that attempting to export AES keys fails in the expected way.
  */
-TEST_F(ExportKeyTest, AesKeyUnexportable) {
+TEST_P(ExportKeyTest, AesKeyUnexportable) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -1976,7 +1895,7 @@
  *
  * Verifies that importing and using an RSA key pair works correctly.
  */
-TEST_F(ImportKeyTest, RsaSuccess) {
+TEST_P(ImportKeyTest, RsaSuccess) {
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                            .Authorization(TAG_NO_AUTH_REQUIRED)
                                            .RsaSigningKey(1024, 65537)
@@ -2003,7 +1922,7 @@
  * Verifies that importing an RSA key pair with a size that doesn't match the key fails in the
  * correct way.
  */
-TEST_F(ImportKeyTest, RsaKeySizeMismatch) {
+TEST_P(ImportKeyTest, RsaKeySizeMismatch) {
     ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
               ImportKey(AuthorizationSetBuilder()
                             .RsaSigningKey(2048 /* Doesn't match key */, 65537)
@@ -2018,7 +1937,7 @@
  * Verifies that importing an RSA key pair with a public exponent that doesn't match the key fails
  * in the correct way.
  */
-TEST_F(ImportKeyTest, RsaPublicExponentMismatch) {
+TEST_P(ImportKeyTest, RsaPublicExponentMismatch) {
     ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
               ImportKey(AuthorizationSetBuilder()
                             .RsaSigningKey(1024, 3 /* Doesn't match key */)
@@ -2032,7 +1951,7 @@
  *
  * Verifies that importing and using an ECDSA P-256 key pair works correctly.
  */
-TEST_F(ImportKeyTest, EcdsaSuccess) {
+TEST_P(ImportKeyTest, EcdsaSuccess) {
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                            .Authorization(TAG_NO_AUTH_REQUIRED)
                                            .EcdsaSigningKey(256)
@@ -2057,7 +1976,7 @@
  *
  * Verifies that importing and using an ECDSA P-256 key pair encoded using RFC5915 works correctly.
  */
-TEST_F(ImportKeyTest, EcdsaP256RFC5915Success) {
+TEST_P(ImportKeyTest, EcdsaP256RFC5915Success) {
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                                .Authorization(TAG_NO_AUTH_REQUIRED)
                                                .EcdsaSigningKey(256)
@@ -2082,7 +2001,7 @@
  *
  * Verifies that importing and using an ECDSA P-256 key pair encoded using SEC1 works correctly.
  */
-TEST_F(ImportKeyTest, EcdsaP256SEC1Success) {
+TEST_P(ImportKeyTest, EcdsaP256SEC1Success) {
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                                .Authorization(TAG_NO_AUTH_REQUIRED)
                                                .EcdsaSigningKey(256)
@@ -2107,7 +2026,7 @@
  *
  * Verifies that importing and using an ECDSA P-521 key pair works correctly.
  */
-TEST_F(ImportKeyTest, Ecdsa521Success) {
+TEST_P(ImportKeyTest, Ecdsa521Success) {
     if (SecLevel() == SecurityLevel::STRONGBOX) return;
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                            .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2133,7 +2052,7 @@
  * Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the
  * correct way.
  */
-TEST_F(ImportKeyTest, EcdsaSizeMismatch) {
+TEST_P(ImportKeyTest, EcdsaSizeMismatch) {
     ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
               ImportKey(AuthorizationSetBuilder()
                             .EcdsaSigningKey(224 /* Doesn't match key */)
@@ -2147,7 +2066,7 @@
  * Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in the
  * correct way.
  */
-TEST_F(ImportKeyTest, EcdsaCurveMismatch) {
+TEST_P(ImportKeyTest, EcdsaCurveMismatch) {
     ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
               ImportKey(AuthorizationSetBuilder()
                             .EcdsaSigningKey(EcCurve::P_224 /* Doesn't match key */)
@@ -2160,7 +2079,7 @@
  *
  * Verifies that importing and using an AES key works.
  */
-TEST_F(ImportKeyTest, AesSuccess) {
+TEST_P(ImportKeyTest, AesSuccess) {
     string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                            .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2187,7 +2106,7 @@
  *
  * Verifies that importing and using an HMAC key works.
  */
-TEST_F(ImportKeyTest, HmacKeySuccess) {
+TEST_P(ImportKeyTest, HmacKeySuccess) {
     string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                            .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2207,26 +2126,26 @@
 }
 
 auto wrapped_key = hex2str(
-    "3082017902010004820100A0E69B1395D382354FC0E7F74AC068C5818279D76D46745C7274997D045BAA8B9763B3F3"
-    "09E5E59ECA99273AAAE0A37449DA9B1E67B66EC4E42BB62C25346683A43A9F2ACBCA6D350B25551CC53CE0721D29BE"
-    "90F60686877478F82B3BB111C5EAC0BAE9310D7AD11F5A82948B31C322820F24E20DDB0FBD07D1566DAEAA058D4645"
-    "2607352699E1F631D2ABAF60B13E41ED5EDBB90D252331BDB9CDB1B672E871F37CAC009FE9028B3B1E0ACE8F6F0678"
-    "3F581B860620BDD478969EDE3101AAEFF65C6DB03E143E586167DC87D0CCE39E9119782F7B60A7A1CF2B7EE234E013"
-    "E3DE6C56F0D51F30C389D31FA37C5F2875ACB44434E82EF40B316C93DE129BA0040CD796B02C370F1FA4CC0124F130"
-    "2E0201033029A1083106020100020101A203020120A30402020100A4053103020101A6053103020140BF8377020500"
-    "0420CCD540855F833A5E1480BFD2D36FAF3AEEE15DF5BEABE2691BC82DDE2A7AA910041064C9F689C60FF6223AB6E6"
-    "999E0EB6E5");
+    "3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac84b59b30b"
+    "455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e097474febc981195b"
+    "1d13a69086c0863f66a7b7fdb48792227b1ac5e2489febdf087ab5486483033a6f001ca5d1ec1e27f5c30f4cec2642"
+    "074a39ae68aee552e196627a8e3d867e67a8c01b11e75f13cca0a97ab668b50cda07a8ecb7cd8e3dd7009c9636534f"
+    "6f239cffe1fc8daa466f78b676c7119efb96bce4e69ca2a25d0b34ed9c3ff999b801597d5220e307eaa5bee507fb94"
+    "d1fa69f9e519b2de315bac92c36f2ea1fa1df4478c0ddedeae8c70e0233cd098040cd796b02c370f1fa4cc0124f130"
+    "2e0201033029a1083106020100020101a203020120a30402020100a4053103020101a6053103020140bf8377020500"
+    "0420ccd540855f833a5e1480bfd2d36faf3aeee15df5beabe2691bc82dde2a7aa910041064c9f689c60ff6223ab6e6"
+    "999e0eb6e5");
 
 auto wrapped_key_masked = hex2str(
-    "30820179020100048201001EF5320D3C920D7614688A439409ACE4318C48395ABB7247A68671BD4B7156A7773B31A4"
-    "4459B73858625988A312E4D8855138F555678F525E4C52D91444FDC936BE6AEB63FD73FD84201EF46F88A0B622F528"
-    "956C92C9C731EB65BCBC6A03BEAB45959B54A768E2842D2CE174EE542EF2A15DCAA7542F3574BEEB1A991F95439466"
-    "E1960A9CE9E4CBC77DB23765191E4758C850908BCC74E158B77AB774141F171262C1AC771FDFA2E942F2F7633E97E8"
-    "0BD492C3E821361AC6B4F568DE351C816C8C997212C707F728FB3BCAAA796EA6B8E7A80BE010970B380122940277E9"
-    "4C5E9288F7CB6878A4C4CC1E83AB85A81FD68E43B14F1F81AD21E0D3545D70EE040C6D9721D08589581AB49204A330"
-    "2E0201033029A1083106020100020101A203020120A30402020100A4053103020101A6053103020140BF8377020500"
-    "0420A61C6E247E25B3E6E69AA78EB03C2D4AC20D1F99A9A024A76F35C8E2CAB9B68D04102560C70109AE67C030F00B"
-    "98B512A670");
+    "3082017902010004820100aad93ed5924f283b4bb5526fbe7a1412f9d9749ec30db9062b29e574a8546f33c8873245"
+    "2f5b8e6a391ee76c39ed1712c61d8df6213dec1cffbc17a8c6d04c7b30893d8daa9b2015213e21946821553207f8f9"
+    "931c4caba23ed3bee28b36947e47f10e0a5c3dc51c988a628daad3e5e1f4005e79c2d5a96c284b4b8d7e4948f331e5"
+    "b85dd5a236f85579f3ea1d1b848487470bdb0ab4f81a12bee42c99fe0df4bee3759453e69ad1d68a809ce06b949f76"
+    "94a990429b2fe81e066ff43e56a21602db70757922a4bcc23ab89f1e35da77586775f423e519c2ea394caf48a28d0c"
+    "8020f1dcf6b3a68ec246f615ae96dae9a079b1f6eb959033c1af5c125fd94168040c6d9721d08589581ab49204a330"
+    "2e0201033029a1083106020100020101a203020120a30402020100a4053103020101a6053103020140bf8377020500"
+    "0420a61c6e247e25b3e6e69aa78eb03c2d4ac20d1f99a9a024a76f35c8e2cab9b68d04102560c70109ae67c030f00b"
+    "98b512a670");
 
 auto wrapping_key = hex2str(
     "308204be020100300d06092a864886f70d0101010500048204a8308204a40201000282010100aec367931d8900ce56"
@@ -2262,17 +2181,19 @@
 
 class ImportWrappedKeyTest : public KeymasterHidlTest {};
 
-TEST_F(ImportWrappedKeyTest, Success) {
+TEST_P(ImportWrappedKeyTest, Success) {
     auto wrapping_key_desc = AuthorizationSetBuilder()
                                  .RsaEncryptionKey(2048, 65537)
-                                 .Digest(Digest::SHA1)
+                                 .Digest(Digest::SHA_2_256)
                                  .Padding(PaddingMode::RSA_OAEP)
                                  .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
 
     ASSERT_EQ(ErrorCode::OK,
               ImportWrappedKey(
                   wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key,
-                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+                  AuthorizationSetBuilder()
+                      .Digest(Digest::SHA_2_256)
+                      .Padding(PaddingMode::RSA_OAEP)));
 
     string message = "Hello World!";
     auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
@@ -2281,42 +2202,48 @@
     EXPECT_EQ(message, plaintext);
 }
 
-TEST_F(ImportWrappedKeyTest, SuccessMasked) {
+TEST_P(ImportWrappedKeyTest, SuccessMasked) {
     auto wrapping_key_desc = AuthorizationSetBuilder()
                                  .RsaEncryptionKey(2048, 65537)
-                                 .Digest(Digest::SHA1)
+                                 .Digest(Digest::SHA_2_256)
                                  .Padding(PaddingMode::RSA_OAEP)
                                  .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
 
     ASSERT_EQ(ErrorCode::OK,
               ImportWrappedKey(
                   wrapped_key_masked, wrapping_key, wrapping_key_desc, masking_key,
-                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+                  AuthorizationSetBuilder()
+                      .Digest(Digest::SHA_2_256)
+                      .Padding(PaddingMode::RSA_OAEP)));
 }
 
-TEST_F(ImportWrappedKeyTest, WrongMask) {
+TEST_P(ImportWrappedKeyTest, WrongMask) {
     auto wrapping_key_desc = AuthorizationSetBuilder()
                                  .RsaEncryptionKey(2048, 65537)
-                                 .Digest(Digest::SHA1)
+                                 .Digest(Digest::SHA_2_256)
                                  .Padding(PaddingMode::RSA_OAEP)
                                  .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
 
     ASSERT_EQ(ErrorCode::VERIFICATION_FAILED,
               ImportWrappedKey(
                   wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key,
-                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+                  AuthorizationSetBuilder()
+                      .Digest(Digest::SHA_2_256)
+                      .Padding(PaddingMode::RSA_OAEP)));
 }
 
-TEST_F(ImportWrappedKeyTest, WrongPurpose) {
+TEST_P(ImportWrappedKeyTest, WrongPurpose) {
     auto wrapping_key_desc = AuthorizationSetBuilder()
                                  .RsaEncryptionKey(2048, 65537)
-                                 .Digest(Digest::SHA1)
+                                 .Digest(Digest::SHA_2_256)
                                  .Padding(PaddingMode::RSA_OAEP);
 
     ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
               ImportWrappedKey(
                   wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key,
-                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+                  AuthorizationSetBuilder()
+                      .Digest(Digest::SHA_2_256)
+                      .Padding(PaddingMode::RSA_OAEP)));
 }
 
 typedef KeymasterHidlTest EncryptionOperationsTest;
@@ -2326,7 +2253,7 @@
  *
  * Verifies that raw RSA encryption works.
  */
-TEST_F(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(2048, 65537)
@@ -2349,7 +2276,7 @@
  *
  * Verifies that raw RSA encryption of short messages works.
  */
-TEST_F(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(2048, 65537)
@@ -2378,7 +2305,7 @@
  *
  * Verifies that raw RSA encryption of too-long messages fails in the expected way.
  */
-TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLong) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(2048, 65537)
@@ -2398,7 +2325,7 @@
  *
  * Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected way.
  */
-TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(2048, 65537)
@@ -2440,7 +2367,7 @@
  *
  * Verifies that RSA-OAEP encryption operations work, with all digests.
  */
-TEST_F(EncryptionOperationsTest, RsaOaepSuccess) {
+TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
     auto digests = ValidDigests(false /* withNone */, true /* withMD5 */);
 
     size_t key_size = 2048;  // Need largish key for SHA-512 test.
@@ -2491,7 +2418,7 @@
  * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
  * without a digest.
  */
-TEST_F(EncryptionOperationsTest, RsaOaepInvalidDigest) {
+TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(2048, 65537)
@@ -2509,7 +2436,7 @@
  * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt with a
  * different digest than was used to encrypt.
  */
-TEST_F(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
+TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
     if (SecLevel() == SecurityLevel::STRONGBOX) return;
 
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -2537,7 +2464,7 @@
  * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a
  * too-large message.
  */
-TEST_F(EncryptionOperationsTest, RsaOaepTooLarge) {
+TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(2048, 65537)
@@ -2550,7 +2477,8 @@
               Begin(KeyPurpose::ENCRYPT,
                     AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::SHA_2_256)));
     string result;
-    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+    auto error = Finish(message, &result);
+    EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT);
     EXPECT_EQ(0U, result.size());
 }
 
@@ -2559,7 +2487,7 @@
  *
  * Verifies that RSA PKCS encryption/decrypts works.
  */
-TEST_F(EncryptionOperationsTest, RsaPkcs1Success) {
+TEST_P(EncryptionOperationsTest, RsaPkcs1Success) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(2048, 65537)
@@ -2598,7 +2526,7 @@
  *
  * Verifies that RSA PKCS encryption fails in the correct way when the mssage is too large.
  */
-TEST_F(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaEncryptionKey(2048, 65537)
@@ -2608,7 +2536,8 @@
     auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
     EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
     string result;
-    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+    auto error = Finish(message, &result);
+    EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT);
     EXPECT_EQ(0U, result.size());
 }
 
@@ -2617,7 +2546,7 @@
  *
  * Verifies that attempting to use ECDSA keys to encrypt fails in the correct way.
  */
-TEST_F(EncryptionOperationsTest, EcdsaEncrypt) {
+TEST_P(EncryptionOperationsTest, EcdsaEncrypt) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .EcdsaSigningKey(256)
@@ -2632,7 +2561,7 @@
  *
  * Verifies that attempting to use HMAC keys to encrypt fails in the correct way.
  */
-TEST_F(EncryptionOperationsTest, HmacEncrypt) {
+TEST_P(EncryptionOperationsTest, HmacEncrypt) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .HmacKey(128)
@@ -2652,7 +2581,7 @@
  *
  * Verifies that AES ECB mode works.
  */
-TEST_F(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2681,7 +2610,7 @@
  *
  * Verifies that AES encryption fails in the correct way when an unauthorized mode is specified.
  */
-TEST_F(EncryptionOperationsTest, AesWrongMode) {
+TEST_P(EncryptionOperationsTest, AesWrongMode) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2696,12 +2625,46 @@
 }
 
 /*
+ * EncryptionOperationsTest.AesWrongPurpose
+ *
+ * Verifies that AES encryption fails in the correct way when an unauthorized purpose is specified.
+ */
+TEST_P(EncryptionOperationsTest, AesWrongPurpose) {
+    auto err = GenerateKey(AuthorizationSetBuilder()
+                                   .Authorization(TAG_NO_AUTH_REQUIRED)
+                                   .AesKey(128)
+                                   .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT)
+                                   .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                   .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                   .Padding(PaddingMode::NONE));
+    ASSERT_EQ(ErrorCode::OK, err) << "Got " << err;
+
+    err = Begin(KeyPurpose::DECRYPT,
+                AuthorizationSetBuilder().BlockMode(BlockMode::GCM).Padding(PaddingMode::NONE));
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
+
+    CheckedDeleteKey();
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesKey(128)
+                                                 .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                                 .Padding(PaddingMode::NONE)));
+
+    err = Begin(KeyPurpose::ENCRYPT,
+                AuthorizationSetBuilder().BlockMode(BlockMode::GCM).Padding(PaddingMode::NONE));
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
+}
+
+/*
  * EncryptionOperationsTest.AesEcbNoPaddingWrongInputSize
  *
  * Verifies that AES encryption fails in the correct way when provided an input that is not a
  * multiple of the block size and no padding is specified.
  */
-TEST_F(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
+TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2722,7 +2685,7 @@
  *
  * Verifies that AES PKCS7 padding works for any message length.
  */
-TEST_F(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2747,7 +2710,7 @@
  * Verifies that AES enryption fails in the correct way when an unauthorized padding mode is
  * specified.
  */
-TEST_F(EncryptionOperationsTest, AesEcbWrongPadding) {
+TEST_P(EncryptionOperationsTest, AesEcbWrongPadding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2768,7 +2731,7 @@
  *
  * Verifies that AES decryption fails in the correct way when the padding is corrupted.
  */
-TEST_F(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2799,7 +2762,7 @@
  *
  * Verifies that AES CTR mode works.
  */
-TEST_F(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -2846,7 +2809,7 @@
  *
  * Verifies that AES works, all modes, when provided data in various size increments.
  */
-TEST_F(EncryptionOperationsTest, AesIncremental) {
+TEST_P(EncryptionOperationsTest, AesIncremental) {
     auto block_modes = {
         BlockMode::ECB, BlockMode::CBC, BlockMode::CTR, BlockMode::GCM,
     };
@@ -2985,7 +2948,7 @@
  *
  * Verifies AES CTR implementation against SP800-38A test vectors.
  */
-TEST_F(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
     std::vector<uint32_t> InvalidSizes = InvalidKeySizes(Algorithm::AES);
     for (size_t i = 0; i < 3; i++) {
         const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
@@ -3005,7 +2968,7 @@
  *
  * Verifies that keymaster rejects use of CTR mode with PKCS7 padding in the correct way.
  */
-TEST_F(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
+TEST_P(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3020,7 +2983,7 @@
  *
  * Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
  */
-TEST_F(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
+TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3052,7 +3015,7 @@
  *
  * Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
  */
-TEST_F(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3085,7 +3048,7 @@
  *
  * Verifies that AES caller-provided nonces work correctly.
  */
-TEST_F(EncryptionOperationsTest, AesCallerNonce) {
+TEST_P(EncryptionOperationsTest, AesCallerNonce) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3134,7 +3097,7 @@
  * Verifies that caller-provided nonces are not permitted when not specified in the key
  * authorizations.
  */
-TEST_F(EncryptionOperationsTest, AesCallerNonceProhibited) {
+TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3169,7 +3132,7 @@
  *
  * Verifies that AES GCM mode works.
  */
-TEST_F(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3215,11 +3178,97 @@
 }
 
 /*
+ * EncryptionOperationsTest.AesGcmRoundTripWithDelaySuccess
+ *
+ * Verifies that AES GCM mode works, even when there's a long delay
+ * between operations.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripWithDelaySuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto update_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params))
+        << "Begin encrypt";
+    string ciphertext;
+    AuthorizationSet update_out_params;
+    sleep(5);
+    ASSERT_EQ(ErrorCode::OK,
+              Finish(op_handle_, update_params, message, "", &update_out_params, &ciphertext));
+
+    ASSERT_EQ(ciphertext.length(), message.length() + 16);
+
+    // Grab nonce
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt.
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)) << "Begin decrypt";
+    string plaintext;
+    size_t input_consumed;
+    sleep(5);
+    ASSERT_EQ(ErrorCode::OK, Update(op_handle_, update_params, ciphertext, &update_out_params,
+                                    &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    sleep(5);
+    EXPECT_EQ(ErrorCode::OK, Finish("", &plaintext));
+    EXPECT_EQ(message.length(), plaintext.length());
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmDifferentNonces
+ *
+ * Verifies that encrypting the same data with different nonces produces different outputs.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmDifferentNonces) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                                 .Authorization(TAG_CALLER_NONCE)));
+
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+    string nonce1 = "000000000000";
+    string nonce2 = "111111111111";
+    string nonce3 = "222222222222";
+
+    string ciphertext1 =
+            EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, HidlBuf(nonce1));
+    string ciphertext2 =
+            EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, HidlBuf(nonce2));
+    string ciphertext3 =
+            EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, HidlBuf(nonce3));
+
+    ASSERT_NE(ciphertext1, ciphertext2);
+    ASSERT_NE(ciphertext1, ciphertext3);
+    ASSERT_NE(ciphertext2, ciphertext3);
+}
+
+/*
  * EncryptionOperationsTest.AesGcmTooShortTag
  *
  * Verifies that AES GCM mode fails correctly when a too-short tag length is specified.
  */
-TEST_F(EncryptionOperationsTest, AesGcmTooShortTag) {
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3240,7 +3289,7 @@
  *
  * Verifies that AES GCM mode fails correctly when a too-short tag is provided to decryption.
  */
-TEST_F(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3283,7 +3332,7 @@
  *
  * Verifies that AES GCM mode fails correctly when the decryption key is incorrect.
  */
-TEST_F(EncryptionOperationsTest, AesGcmCorruptKey) {
+TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) {
     const uint8_t nonce_bytes[] = {
         0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
     };
@@ -3335,7 +3384,7 @@
  * Verifies that AES GCM mode works when provided additional authenticated data, but no data to
  * encrypt.
  */
-TEST_F(EncryptionOperationsTest, AesGcmAadNoData) {
+TEST_P(EncryptionOperationsTest, AesGcmAadNoData) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3380,7 +3429,7 @@
  *
  * Verifies that AES GCM mode works when provided additional authenticated data in multiple chunks.
  */
-TEST_F(EncryptionOperationsTest, AesGcmMultiPartAad) {
+TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) {
     const size_t tag_bits = 128;
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -3441,7 +3490,7 @@
  *
  * Verifies that AES GCM mode fails correctly when given AAD after data to encipher.
  */
-TEST_F(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
+TEST_P(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3489,7 +3538,7 @@
  *
  * Verifies that AES GCM decryption fails correctly when additional authenticated date is wrong.
  */
-TEST_F(EncryptionOperationsTest, AesGcmBadAad) {
+TEST_P(EncryptionOperationsTest, AesGcmBadAad) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3533,7 +3582,7 @@
  *
  * Verifies that AES GCM decryption fails correctly when the nonce is incorrect.
  */
-TEST_F(EncryptionOperationsTest, AesGcmWrongNonce) {
+TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3577,7 +3626,7 @@
  *
  * Verifies that AES GCM decryption fails correctly when the tag is wrong.
  */
-TEST_F(EncryptionOperationsTest, AesGcmCorruptTag) {
+TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -3625,7 +3674,7 @@
  *
  * Verifies that 3DES is basically functional.
  */
-TEST_F(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) {
     auto auths = AuthorizationSetBuilder()
                      .TripleDesEncryptionKey(168)
                      .BlockMode(BlockMode::ECB)
@@ -3654,7 +3703,7 @@
  *
  * Verifies that CBC keys reject ECB usage.
  */
-TEST_F(EncryptionOperationsTest, TripleDesEcbNotAuthorized) {
+TEST_P(EncryptionOperationsTest, TripleDesEcbNotAuthorized) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::CBC)
@@ -3670,7 +3719,7 @@
  *
  * Tests ECB mode with PKCS#7 padding, various message sizes.
  */
-TEST_F(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::ECB)
@@ -3693,7 +3742,7 @@
  *
  * Verifies that keys configured for no padding reject PKCS7 padding
  */
-TEST_F(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::ECB)
@@ -3711,7 +3760,7 @@
  *
  * Verifies that corrupted padding is detected.
  */
-TEST_F(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) {
+TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::ECB)
@@ -3827,7 +3876,7 @@
  *
  * Verifies that NIST (plus a few extra) test vectors produce the correct results.
  */
-TEST_F(EncryptionOperationsTest, TripleDesTestVector) {
+TEST_P(EncryptionOperationsTest, TripleDesTestVector) {
     constexpr size_t num_tests = sizeof(kTripleDesTestVectors) / sizeof(TripleDesTestVector);
     for (auto* test = kTripleDesTestVectors; test < kTripleDesTestVectors + num_tests; ++test) {
         SCOPED_TRACE(test->name);
@@ -3842,7 +3891,7 @@
  *
  * Validates CBC mode functionality.
  */
-TEST_F(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::CBC)
@@ -3871,7 +3920,7 @@
  *
  * Validates that 3DES keys can allow caller-specified IVs, and use them correctly.
  */
-TEST_F(EncryptionOperationsTest, TripleDesCallerIv) {
+TEST_P(EncryptionOperationsTest, TripleDesCallerIv) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::CBC)
@@ -3906,7 +3955,7 @@
  *
  * Verifies that 3DES keys without TAG_CALLER_NONCE do not allow caller-specified IVS.
  */
-TEST_F(EncryptionOperationsTest, TripleDesCallerNonceProhibited) {
+TEST_P(EncryptionOperationsTest, TripleDesCallerNonceProhibited) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::CBC)
@@ -3938,7 +3987,7 @@
  *
  * Verifies that 3DES ECB-only keys do not allow CBC usage.
  */
-TEST_F(EncryptionOperationsTest, TripleDesCbcNotAuthorized) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcNotAuthorized) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::ECB)
@@ -3956,7 +4005,7 @@
  *
  * Verifies that unpadded CBC operations reject inputs that are not a multiple of block size.
  */
-TEST_F(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::CBC)
@@ -3978,7 +4027,7 @@
  *
  * Verifies that PKCS7 padding works correctly in CBC mode.
  */
-TEST_F(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::CBC)
@@ -4001,7 +4050,7 @@
  *
  * Verifies that a key that requires PKCS7 padding cannot be used in unpadded mode.
  */
-TEST_F(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::CBC)
@@ -4021,7 +4070,7 @@
  *
  * Verifies that corrupted PKCS7 padding is rejected during decryption.
  */
-TEST_F(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::CBC)
@@ -4052,7 +4101,7 @@
  *
  * Verifies that 3DES CBC works with many different input sizes.
  */
-TEST_F(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .TripleDesEncryptionKey(168)
                                              .BlockMode(BlockMode::CBC)
@@ -4097,7 +4146,7 @@
  *
  * Verifies that the max uses per boot tag works correctly with AES keys.
  */
-TEST_F(MaxOperationsTest, TestLimitAes) {
+TEST_P(MaxOperationsTest, TestLimitAes) {
     if (SecLevel() == SecurityLevel::STRONGBOX) return;
 
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -4124,7 +4173,7 @@
  *
  * Verifies that the max uses per boot tag works correctly with RSA keys.
  */
-TEST_F(MaxOperationsTest, TestLimitRsa) {
+TEST_P(MaxOperationsTest, TestLimitRsa) {
     if (SecLevel() == SecurityLevel::STRONGBOX) return;
 
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -4153,7 +4202,7 @@
  * Verifies that the addRngEntropy method doesn't blow up.  There's no way to test that entropy is
  * actually added.
  */
-TEST_F(AddEntropyTest, AddEntropy) {
+TEST_P(AddEntropyTest, AddEntropy) {
     EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf("foo")));
 }
 
@@ -4162,7 +4211,7 @@
  *
  * Verifies that the addRngEntropy method doesn't blow up when given an empty buffer.
  */
-TEST_F(AddEntropyTest, AddEmptyEntropy) {
+TEST_P(AddEntropyTest, AddEmptyEntropy) {
     EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf()));
 }
 
@@ -4171,7 +4220,7 @@
  *
  * Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data.
  */
-TEST_F(AddEntropyTest, AddLargeEntropy) {
+TEST_P(AddEntropyTest, AddLargeEntropy) {
     EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a'))));
 }
 
@@ -4182,7 +4231,7 @@
  *
  * Verifies that attesting to RSA keys works and generates the expected output.
  */
-TEST_F(AttestationTest, RsaAttestation) {
+TEST_P(AttestationTest, RsaAttestation) {
     auto creation_time = std::chrono::system_clock::now();
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -4216,7 +4265,7 @@
  *
  * Verifies that attesting to RSA requires app ID.
  */
-TEST_F(AttestationTest, RsaAttestationRequiresAppId) {
+TEST_P(AttestationTest, RsaAttestationRequiresAppId) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(2048, 65537)
@@ -4236,7 +4285,7 @@
  *
  * Verifies that attesting to EC keys works and generates the expected output.
  */
-TEST_F(AttestationTest, EcAttestation) {
+TEST_P(AttestationTest, EcAttestation) {
     auto creation_time = std::chrono::system_clock::now();
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -4267,7 +4316,7 @@
  *
  * Verifies that attesting to EC keys requires app ID
  */
-TEST_F(AttestationTest, EcAttestationRequiresAttestationAppId) {
+TEST_P(AttestationTest, EcAttestationRequiresAttestationAppId) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .EcdsaSigningKey(EcCurve::P_256)
@@ -4282,11 +4331,44 @@
 }
 
 /*
+ * AttestationTest.AttestationApplicationIDLengthProperlyEncoded
+ *
+ * Verifies that the Attestation Application ID software enforced tag has a proper length encoding.
+ * Some implementations break strict encoding rules by encoding a length between 127 and 256 in one
+ * byte. Proper DER encoding specifies that for lengths greather than 127, one byte should be used
+ * to specify how many following bytes will be used to encode the length.
+ */
+TEST_P(AttestationTest, AttestationApplicationIDLengthProperlyEncoded) {
+    std::vector<uint32_t> app_id_lengths{143, 258};
+    for (uint32_t length : app_id_lengths) {
+        auto creation_time = std::chrono::system_clock::now();
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                     .EcdsaSigningKey(EcCurve::P_256)
+                                                     .Digest(Digest::SHA_2_256)));
+
+        hidl_vec<hidl_vec<uint8_t>> cert_chain;
+        const string app_id(length, 'a');
+        ASSERT_EQ(ErrorCode::OK,
+                  AttestKey(AuthorizationSetBuilder()
+                                    .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                                    .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id)),
+                            &cert_chain));
+        EXPECT_GE(cert_chain.size(), 2U);
+
+        EXPECT_TRUE(verify_attestation_record("challenge", app_id,                    //
+                                              key_characteristics_.softwareEnforced,  //
+                                              key_characteristics_.hardwareEnforced,  //
+                                              SecLevel(), cert_chain[0], creation_time));
+        CheckedDeleteKey();
+    }
+}
+/*
  * AttestationTest.AesAttestation
  *
  * Verifies that attesting to AES keys fails in the expected way.
  */
-TEST_F(AttestationTest, AesAttestation) {
+TEST_P(AttestationTest, AesAttestation) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .AesEncryptionKey(128)
@@ -4306,7 +4388,7 @@
  *
  * Verifies that attesting to HMAC keys fails in the expected way.
  */
-TEST_F(AttestationTest, HmacAttestation) {
+TEST_P(AttestationTest, HmacAttestation) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .HmacKey(128)
@@ -4329,75 +4411,61 @@
  *
  * This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly
  * valid key blob.
- *
- * TODO(swillden):  Update to incorporate changes in rollback resistance semantics.
  */
-TEST_F(KeyDeletionTest, DeleteKey) {
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                             .RsaSigningKey(2048, 65537)
-                                             .Digest(Digest::NONE)
-                                             .Padding(PaddingMode::NONE)
-                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+TEST_P(KeyDeletionTest, DeleteKey) {
+    auto error = GenerateKey(AuthorizationSetBuilder()
+                                     .RsaSigningKey(2048, 65537)
+                                     .Digest(Digest::NONE)
+                                     .Padding(PaddingMode::NONE)
+                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                     .Authorization(TAG_ROLLBACK_RESISTANCE));
+    ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
 
     // Delete must work if rollback protection is implemented
-    AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
-    bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+    if (error == ErrorCode::OK) {
+        AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+        ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
 
-    if (rollback_protected) {
         ASSERT_EQ(ErrorCode::OK, DeleteKey(true /* keep key blob */));
-    } else {
-        auto delete_result = DeleteKey(true /* keep key blob */);
-        ASSERT_TRUE(delete_result == ErrorCode::OK | delete_result == ErrorCode::UNIMPLEMENTED);
-    }
 
-    string message = "12345678901234567890123456789012";
-    AuthorizationSet begin_out_params;
-
-    if (rollback_protected) {
+        string message = "12345678901234567890123456789012";
+        AuthorizationSet begin_out_params;
         EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
                   Begin(KeyPurpose::SIGN, key_blob_,
                         AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
                         &begin_out_params, &op_handle_));
-    } else {
-        EXPECT_EQ(ErrorCode::OK,
-                  Begin(KeyPurpose::SIGN, key_blob_,
-                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
-                        &begin_out_params, &op_handle_));
+        AbortIfNeeded();
+        key_blob_ = HidlBuf();
     }
-    AbortIfNeeded();
-    key_blob_ = HidlBuf();
 }
 
 /**
  * KeyDeletionTest.DeleteInvalidKey
  *
- * This test checks that the HAL excepts invalid key blobs.
- *
- * TODO(swillden):  Update to incorporate changes in rollback resistance semantics.
+ * This test checks that the HAL excepts invalid key blobs..
  */
-TEST_F(KeyDeletionTest, DeleteInvalidKey) {
+TEST_P(KeyDeletionTest, DeleteInvalidKey) {
     // Generate key just to check if rollback protection is implemented
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                             .RsaSigningKey(2048, 65537)
-                                             .Digest(Digest::NONE)
-                                             .Padding(PaddingMode::NONE)
-                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+    auto error = GenerateKey(AuthorizationSetBuilder()
+                                     .RsaSigningKey(2048, 65537)
+                                     .Digest(Digest::NONE)
+                                     .Padding(PaddingMode::NONE)
+                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                     .Authorization(TAG_ROLLBACK_RESISTANCE));
+    ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
 
     // Delete must work if rollback protection is implemented
-    AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
-    bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+    if (error == ErrorCode::OK) {
+        AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+        ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
 
-    // Delete the key we don't care about the result at this point.
-    DeleteKey();
+        // Delete the key we don't care about the result at this point.
+        DeleteKey();
 
-    // Now create an invalid key blob and delete it.
-    key_blob_ = HidlBuf("just some garbage data which is not a valid key blob");
+        // Now create an invalid key blob and delete it.
+        key_blob_ = HidlBuf("just some garbage data which is not a valid key blob");
 
-    if (rollback_protected) {
         ASSERT_EQ(ErrorCode::OK, DeleteKey());
-    } else {
-        auto delete_result = DeleteKey();
-        ASSERT_TRUE(delete_result == ErrorCode::OK | delete_result == ErrorCode::UNIMPLEMENTED);
     }
 }
 
@@ -4411,39 +4479,34 @@
  * device has been wiped manually (e.g., fastboot flashall -w), and new FBE/FDE keys have
  * been provisioned. Use this test only on dedicated testing devices that have no valuable
  * credentials stored in Keystore/Keymaster.
- *
- * TODO(swillden):  Update to incorporate changes in rollback resistance semantics.
  */
-TEST_F(KeyDeletionTest, DeleteAllKeys) {
+TEST_P(KeyDeletionTest, DeleteAllKeys) {
     if (!arm_deleteAllKeys) return;
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                             .RsaSigningKey(2048, 65537)
-                                             .Digest(Digest::NONE)
-                                             .Padding(PaddingMode::NONE)
-                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+    auto error = GenerateKey(AuthorizationSetBuilder()
+                                     .RsaSigningKey(2048, 65537)
+                                     .Digest(Digest::NONE)
+                                     .Padding(PaddingMode::NONE)
+                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                     .Authorization(TAG_ROLLBACK_RESISTANCE));
+    ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
 
     // Delete must work if rollback protection is implemented
-    AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
-    bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+    if (error == ErrorCode::OK) {
+        AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+        ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
 
-    ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
+        ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
 
-    string message = "12345678901234567890123456789012";
-    AuthorizationSet begin_out_params;
+        string message = "12345678901234567890123456789012";
+        AuthorizationSet begin_out_params;
 
-    if (rollback_protected) {
         EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
                   Begin(KeyPurpose::SIGN, key_blob_,
                         AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
                         &begin_out_params, &op_handle_));
-    } else {
-        EXPECT_EQ(ErrorCode::OK,
-                  Begin(KeyPurpose::SIGN, key_blob_,
-                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
-                        &begin_out_params, &op_handle_));
+        AbortIfNeeded();
+        key_blob_ = HidlBuf();
     }
-    AbortIfNeeded();
-    key_blob_ = HidlBuf();
 }
 
 using UpgradeKeyTest = KeymasterHidlTest;
@@ -4453,7 +4516,7 @@
  *
  * Verifies that calling upgrade key on an up-to-date key works (i.e. does nothing).
  */
-TEST_F(UpgradeKeyTest, UpgradeKey) {
+TEST_P(UpgradeKeyTest, UpgradeKey) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .AesEncryptionKey(128)
                                              .Padding(PaddingMode::NONE)
@@ -4465,18 +4528,180 @@
     EXPECT_EQ(result, std::make_pair(ErrorCode::OK, HidlBuf()));
 }
 
+using ClearOperationsTest = KeymasterHidlTest;
+
+/*
+ * ClearSlotsTest.TooManyOperations
+ *
+ * Verifies that TOO_MANY_OPERATIONS is returned after the max number of
+ * operations are started without being finished or aborted. Also verifies
+ * that aborting the operations clears the operations.
+ *
+ */
+TEST_P(ClearOperationsTest, TooManyOperations) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(2048, 65537)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    int max_operations = SecLevel() == SecurityLevel::STRONGBOX ? 4 : 16;
+    OperationHandle op_handles[max_operations];
+    AuthorizationSet out_params;
+    for(int i=0; i<max_operations; i++) {
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
+    }
+    EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
+         Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
+    // Try again just in case there's a weird overflow bug
+    EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
+         Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
+    for(int i=0; i<max_operations; i++) {
+        EXPECT_EQ(ErrorCode::OK, Abort(op_handles[i]));
+    }
+    EXPECT_EQ(ErrorCode::OK,
+         Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
+    AbortIfNeeded();
+}
+
+/*
+ * ClearSlotsTest.ServiceDeath
+ *
+ * Verifies that the service is restarted after death and the ongoing
+ * operations are cleared.
+ */
+TEST_P(ClearOperationsTest, ServiceDeath) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(2048, 65537)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    int max_operations = SecLevel() == SecurityLevel::STRONGBOX ? 4 : 16;
+    OperationHandle op_handles[max_operations];
+    AuthorizationSet out_params;
+    for(int i=0; i<max_operations; i++) {
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
+    }
+    EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
+         Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
+
+    DebugInfo debug_info;
+    GetDebugInfo(&debug_info);
+    kill(debug_info.pid, SIGKILL);
+    // wait 1 second for keymaster to restart
+    sleep(1);
+    InitializeKeymaster();
+
+    for(int i=0; i<max_operations; i++) {
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
+    }
+    EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
+         Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
+    for(int i=0; i<max_operations; i++) {
+        EXPECT_EQ(ErrorCode::OK, Abort(op_handles[i]));
+    }
+}
+
+typedef KeymasterHidlTest TransportLimitTest;
+
+/*
+ * TransportLimitTest.LargeFinishInput
+ *
+ * Verifies that passing large input data to finish either succeeds or fails as expected.
+ */
+TEST_P(TransportLimitTest, LargeFinishInput) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::ECB)
+                                                 .Padding(PaddingMode::NONE)));
+
+    for (int msg_size = 10 /*1KB*/; msg_size <= 17 /*128KB*/; msg_size++) {
+        auto cipher_params =
+                AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+
+        AuthorizationSet out_params;
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
+
+        string plain_message = std::string(1 << msg_size, 'x');
+        string encrypted_message;
+        auto rc = Finish(plain_message, &encrypted_message);
+
+        if (rc == ErrorCode::OK) {
+            EXPECT_EQ(plain_message.size(), encrypted_message.size())
+                    << "Encrypt finish returned OK, but did not consume all of the given input";
+        } else {
+            EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
+                    << "Encrypt finish failed in an unexpected way when given a large input";
+            continue;
+        }
+        cipher_params.push_back(out_params);
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
+
+        string decrypted_message;
+        rc = Finish(encrypted_message, &decrypted_message);
+
+        if (rc == ErrorCode::OK) {
+            EXPECT_EQ(plain_message.size(), decrypted_message.size())
+                    << "Decrypt finish returned OK, did not consume all of the given input";
+        } else {
+            EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
+                    << "Encrypt finish failed in an unexpected way when given a large input";
+        }
+    }
+
+    CheckedDeleteKey();
+}
+
+static const auto kKeymasterDeviceChoices =
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor));
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, NewKeyGenerationTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, ImportKeyTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, ImportWrappedKeyTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, SigningOperationsTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, VerificationOperationsTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, ExportKeyTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, EncryptionOperationsTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, MaxOperationsTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, AddEntropyTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, AttestationTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, KeyDeletionTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, TransportLimitTest, kKeymasterDeviceChoices,
+                         android::hardware::PrintInstanceNameToString);
+
 }  // namespace test
 }  // namespace V4_0
 }  // namespace keymaster
 }  // namespace hardware
 }  // namespace android
 
-using android::hardware::keymaster::V4_0::test::KeymasterHidlEnvironment;
-
 int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(KeymasterHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
-    KeymasterHidlEnvironment::Instance()->init(&argc, argv);
     for (int i = 1; i < argc; ++i) {
         if (argv[i][0] == '-') {
             if (std::string(argv[i]) == "--arm_deleteAllKeys") {
diff --git a/keymaster/4.0/vts/performance/Android.bp b/keymaster/4.0/vts/performance/Android.bp
new file mode 100644
index 0000000..9434bc9
--- /dev/null
+++ b/keymaster/4.0/vts/performance/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_benchmark {
+    name: "keymaster_benchmark",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "Benchmark.cpp",
+    ],
+    static_libs: [
+        "android.hardware.keymaster@4.0",
+        "libkeymaster4support",
+        "libsoftkeymasterdevice",
+        "libchrome"
+    ],
+}
diff --git a/keymaster/4.0/vts/performance/Benchmark.cpp b/keymaster/4.0/vts/performance/Benchmark.cpp
new file mode 100644
index 0000000..96ef5bf
--- /dev/null
+++ b/keymaster/4.0/vts/performance/Benchmark.cpp
@@ -0,0 +1,717 @@
+/*
+ * 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 "keymaster_benchmark"
+
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <keymaster/keymaster_configuration.h>
+#include <keymasterV4_0/authorization_set.h>
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binder/IServiceManager.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iostream>
+
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+
+#include <benchmark/benchmark.h>
+#include <hidl/Status.h>
+
+#include <base/command_line.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace test {
+
+// libutils:
+using android::OK;
+using android::sp;
+using android::status_t;
+
+// libhidl:
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+
+// IKeymaster:
+using android::IServiceManager;
+using android::hardware::hidl_string;
+using android::hardware::keymaster::V4_0::AuthorizationSet;
+using android::hardware::keymaster::V4_0::AuthorizationSetBuilder;
+using android::hardware::keymaster::V4_0::BlockMode;
+using android::hardware::keymaster::V4_0::ErrorCode;
+using android::hardware::keymaster::V4_0::IKeymasterDevice;
+using android::hardware::keymaster::V4_0::KeyCharacteristics;
+using android::hardware::keymaster::V4_0::SecurityLevel;
+
+// Standard library:
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::optional;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+class HidlBuf : public hidl_vec<uint8_t> {
+    typedef hidl_vec<uint8_t> super;
+
+  public:
+    HidlBuf() {}
+    HidlBuf(const super& other) : super(other) {}
+    HidlBuf(super&& other) : super(std::move(other)) {}
+    explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
+
+    HidlBuf& operator=(const super& other) {
+        super::operator=(other);
+        return *this;
+    }
+
+    HidlBuf& operator=(super&& other) {
+        super::operator=(std::move(other));
+        return *this;
+    }
+
+    HidlBuf& operator=(const string& other) {
+        resize(other.size());
+        std::copy(other.begin(), other.end(), begin());
+        return *this;
+    }
+
+    string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
+};
+
+#define SMALL_MESSAGE_SIZE 64
+#define MEDIUM_MESSAGE_SIZE 1024
+#define LARGE_MESSAGE_SIZE 131072
+
+class KeymasterWrapper {
+  private:
+    sp<IKeymasterDevice> keymaster_;
+    SecurityLevel securityLevel_;
+    hidl_string name_;
+    hidl_string author_;
+    HidlBuf key_blob_;
+    KeyCharacteristics key_characteristics_;
+    ErrorCode error_;
+    string key_transform_;
+    string keymaster_name_;
+    uint32_t os_version_;
+    uint32_t os_patch_level_;
+    std::vector<string> message_cache_;
+
+    bool GenerateKey(const AuthorizationSet& authSet) {
+        return (keymaster_
+                        ->generateKey(
+                                authSet.hidl_data(),
+                                [&](ErrorCode hidl_error, const hidl_vec<uint8_t>& hidl_key_blob,
+                                    const KeyCharacteristics& hidl_key_characteristics) {
+                                    error_ = hidl_error;
+                                    key_blob_ = hidl_key_blob;
+                                    key_characteristics_ = std::move(hidl_key_characteristics);
+                                })
+                        .isOk() &&
+                error_ == ErrorCode::OK);
+    }
+
+    bool GenerateKey(Algorithm algorithm, int keySize, Digest digest = Digest::NONE,
+                     PaddingMode padding = PaddingMode::NONE, optional<BlockMode> blockMode = {}) {
+        AuthorizationSetBuilder authSet = AuthorizationSetBuilder()
+                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                  .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT)
+                                                  .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT)
+                                                  .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+                                                  .Authorization(TAG_PURPOSE, KeyPurpose::VERIFY)
+                                                  .Authorization(TAG_KEY_SIZE, keySize)
+                                                  .Authorization(TAG_ALGORITHM, algorithm)
+                                                  .Digest(digest)
+                                                  .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                                  .Padding(padding);
+        if (blockMode) {
+            authSet.BlockMode(*blockMode);
+        }
+        if (algorithm == Algorithm::RSA) {
+            authSet.Authorization(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+        }
+        return GenerateKey(authSet);
+    }
+
+    KeymasterWrapper(const sp<IKeymasterDevice> keymaster) {
+        os_version_ = ::keymaster::GetOsVersion();
+        os_patch_level_ = ::keymaster::GetOsPatchlevel();
+        keymaster_ = keymaster;
+        keymaster_->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
+                                        const hidl_string& author) {
+            securityLevel_ = securityLevel;
+            name_ = name;
+            author_ = author;
+        });
+
+        message_cache_.push_back(string(SMALL_MESSAGE_SIZE, 'x'));
+        message_cache_.push_back(string(MEDIUM_MESSAGE_SIZE, 'x'));
+        message_cache_.push_back(string(LARGE_MESSAGE_SIZE, 'x'));
+    }
+
+  public:
+    static KeymasterWrapper* newInstance(const std::string& keymaster_name) {
+        auto keymaster = IKeymasterDevice::getService(keymaster_name);
+        if (!keymaster) {
+            std::cerr << "Error: unable to find keymaster service named " << keymaster_name
+                      << std::endl;
+            return nullptr;
+        }
+        return new KeymasterWrapper(keymaster);
+    }
+
+    bool GenerateKey(string transform, int keySize, bool sign = false) {
+        if (transform == key_transform_) {
+            return true;
+        } else if (key_transform_ != "") {
+            // Deleting old key first
+            if (!DeleteKey()) {
+                return false;
+            }
+        }
+        optional<Algorithm> algorithm = getAlgorithm(transform);
+        if (!algorithm) {
+            cerr << "Error: invalid algorithm " << transform << endl;
+            return false;
+        }
+        key_transform_ = transform;
+        return GenerateKey(*algorithm, keySize, getDigest(transform), getPadding(transform, sign),
+                           getBlockMode(transform));
+    }
+
+    bool DeleteKey() {
+        key_blob_ = HidlBuf();
+        key_transform_ = "";
+        return keymaster_->deleteKey(key_blob_).isOk();
+    }
+
+    AuthorizationSet getOperationParams(string transform, bool sign = false) {
+        AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+                                                  .Padding(getPadding(transform, sign))
+                                                  .Authorization(TAG_MAC_LENGTH, 128)
+                                                  .Digest(getDigest(transform));
+        optional<BlockMode> blockMode = getBlockMode(transform);
+        if (blockMode) {
+            builder.BlockMode(*blockMode);
+        }
+        return std::move(builder);
+    }
+
+    optional<OperationHandle> EncryptBegin(AuthorizationSet& in_params,
+                                           AuthorizationSet* out_params = new AuthorizationSet) {
+        return Begin(KeyPurpose::ENCRYPT, in_params, out_params);
+    }
+
+    optional<OperationHandle> DecryptBegin(AuthorizationSet& in_params,
+                                           AuthorizationSet* out_params = new AuthorizationSet) {
+        return Begin(KeyPurpose::DECRYPT, in_params, out_params);
+    }
+
+    optional<OperationHandle> SignBegin(AuthorizationSet& in_params,
+                                        AuthorizationSet* out_params = new AuthorizationSet) {
+        return Begin(KeyPurpose::SIGN, in_params, out_params);
+    }
+
+    optional<OperationHandle> VerifyBegin(AuthorizationSet& in_params,
+                                          AuthorizationSet* out_params = new AuthorizationSet) {
+        return Begin(KeyPurpose::VERIFY, in_params, out_params);
+    }
+
+    optional<OperationHandle> Begin(KeyPurpose operation, const AuthorizationSet& in_params,
+                                    AuthorizationSet* out_params) {
+        OperationHandle op_handle;
+        if (!keymaster_
+                     ->begin(operation, key_blob_, in_params.hidl_data(), HardwareAuthToken(),
+                             [&](ErrorCode hidl_error,
+                                 const hidl_vec<KeyParameter>& hidl_out_params,
+                                 uint64_t hidl_op_handle) {
+                                 error_ = hidl_error;
+                                 out_params->push_back(AuthorizationSet(hidl_out_params));
+                                 op_handle = hidl_op_handle;
+                             })
+                     .isOk() ||
+            error_ != ErrorCode::OK) {
+            keymaster_->abort(op_handle);
+            return {};
+        }
+        return op_handle;
+    }
+
+    optional<string> ProcessMessage(const OperationHandle& op_handle, const string& message,
+                                    const AuthorizationSet& in_params,
+                                    AuthorizationSet* out_params = new AuthorizationSet,
+                                    const string& signature = "") {
+        static const int HIDL_BUFFER_LIMIT = 1 << 14;  // 16KB
+
+        string output;
+        size_t input_consumed = 0;
+        while (message.length() - input_consumed > 0) {
+            if (!keymaster_
+                         ->update(op_handle, in_params.hidl_data(),
+                                  HidlBuf(message.substr(input_consumed, HIDL_BUFFER_LIMIT)),
+                                  HardwareAuthToken(), VerificationToken(),
+                                  [&](ErrorCode hidl_error, uint32_t hidl_input_consumed,
+                                      const hidl_vec<KeyParameter>& hidl_out_params,
+                                      const HidlBuf& hidl_output) {
+                                      error_ = hidl_error;
+                                      out_params->push_back(AuthorizationSet(hidl_out_params));
+                                      output.append(hidl_output.to_string());
+                                      input_consumed += hidl_input_consumed;
+                                  })
+                         .isOk() ||
+                error_ != ErrorCode::OK) {
+                keymaster_->abort(op_handle);
+                return {};
+            }
+        }
+
+        if (!keymaster_
+                     ->finish(op_handle, in_params.hidl_data(),
+                              HidlBuf(message.substr(input_consumed)), HidlBuf(signature),
+                              HardwareAuthToken(), VerificationToken(),
+                              [&](ErrorCode hidl_error,
+                                  const hidl_vec<KeyParameter>& hidl_out_params,
+                                  const HidlBuf& hidl_output) {
+                                  error_ = hidl_error;
+                                  out_params->push_back(AuthorizationSet(hidl_out_params));
+                                  output.append(hidl_output.to_string());
+                              })
+                     .isOk() ||
+            error_ != ErrorCode::OK) {
+            keymaster_->abort(op_handle);
+            return {};
+        }
+
+        return output;
+    }
+
+    int getError() { return static_cast<int>(error_); }
+
+    const string getHardwareName() { return name_; }
+
+    SecurityLevel getSecurityLevel() { return securityLevel_; }
+
+    const string& GenerateMessage(int size) {
+        for (const string& message : message_cache_) {
+            if (message.size() == size) {
+                return message;
+            }
+        }
+        string message = string(size, 'x');
+        message_cache_.push_back(message);
+        return std::move(message);
+    }
+
+    optional<BlockMode> getBlockMode(string transform) {
+        if (transform.find("/ECB") != string::npos) {
+            return BlockMode::ECB;
+        } else if (transform.find("/CBC") != string::npos) {
+            return BlockMode::CBC;
+        } else if (transform.find("/CTR") != string::npos) {
+            return BlockMode::CTR;
+        } else if (transform.find("/GCM") != string::npos) {
+            return BlockMode::GCM;
+        }
+        return {};
+    }
+
+    PaddingMode getPadding(string transform, bool sign) {
+        if (transform.find("/PKCS7") != string::npos) {
+            return PaddingMode::PKCS7;
+        } else if (transform.find("/PSS") != string::npos) {
+            return PaddingMode::RSA_PSS;
+        } else if (transform.find("/OAEP") != string::npos) {
+            return PaddingMode::RSA_OAEP;
+        } else if (transform.find("/PKCS1") != string::npos) {
+            return sign ? PaddingMode::RSA_PKCS1_1_5_SIGN : PaddingMode::RSA_PKCS1_1_5_ENCRYPT;
+        } else if (sign && transform.find("RSA") != string::npos) {
+            // RSA defaults to PKCS1 for sign
+            return PaddingMode::RSA_PKCS1_1_5_SIGN;
+        }
+        return PaddingMode::NONE;
+    }
+
+    optional<Algorithm> getAlgorithm(string transform) {
+        if (transform.find("AES") != string::npos) {
+            return Algorithm::AES;
+        } else if (transform.find("Hmac") != string::npos) {
+            return Algorithm::HMAC;
+        } else if (transform.find("DESede") != string::npos) {
+            return Algorithm::TRIPLE_DES;
+        } else if (transform.find("RSA") != string::npos) {
+            return Algorithm::RSA;
+        } else if (transform.find("EC") != string::npos) {
+            return Algorithm::EC;
+        }
+        cerr << "Can't find algorithm for " << transform << endl;
+        return {};
+    }
+
+    Digest getDigest(string transform) {
+        if (transform.find("MD5") != string::npos) {
+            return Digest::MD5;
+        } else if (transform.find("SHA1") != string::npos ||
+                   transform.find("SHA-1") != string::npos) {
+            return Digest::SHA1;
+        } else if (transform.find("SHA224") != string::npos) {
+            return Digest::SHA_2_224;
+        } else if (transform.find("SHA256") != string::npos) {
+            return Digest::SHA_2_256;
+        } else if (transform.find("SHA384") != string::npos) {
+            return Digest::SHA_2_384;
+        } else if (transform.find("SHA512") != string::npos) {
+            return Digest::SHA_2_512;
+        } else if (transform.find("RSA") != string::npos &&
+                   transform.find("OAEP") != string::npos) {
+            return Digest::SHA1;
+        }
+        return Digest::NONE;
+    }
+};
+
+KeymasterWrapper* keymaster;
+
+static void settings(benchmark::internal::Benchmark* benchmark) {
+    benchmark->Unit(benchmark::kMillisecond);
+}
+
+static void addDefaultLabel(benchmark::State& state) {
+    string secLevel;
+    switch (keymaster->getSecurityLevel()) {
+        case SecurityLevel::STRONGBOX:
+            secLevel = "STRONGBOX";
+            break;
+        case SecurityLevel::SOFTWARE:
+            secLevel = "SOFTWARE";
+            break;
+        case SecurityLevel::TRUSTED_ENVIRONMENT:
+            secLevel = "TEE";
+            break;
+    }
+    state.SetLabel("hardware_name:" + keymaster->getHardwareName() + " sec_level:" + secLevel);
+}
+
+// clang-format off
+#define BENCHMARK_KM(func, transform, keySize) \
+    BENCHMARK_CAPTURE(func, transform/keySize, #transform "/" #keySize, keySize)->Apply(settings);
+#define BENCHMARK_KM_MSG(func, transform, keySize, msgSize)                                      \
+    BENCHMARK_CAPTURE(func, transform/keySize/msgSize, #transform "/" #keySize "/" #msgSize, \
+                      keySize, msgSize)                                                          \
+            ->Apply(settings);
+
+#define BENCHMARK_KM_ALL_MSGS(func, transform, keySize)             \
+    BENCHMARK_KM_MSG(func, transform, keySize, SMALL_MESSAGE_SIZE)  \
+    BENCHMARK_KM_MSG(func, transform, keySize, MEDIUM_MESSAGE_SIZE) \
+    BENCHMARK_KM_MSG(func, transform, keySize, LARGE_MESSAGE_SIZE)
+
+#define BENCHMARK_KM_CIPHER(transform, keySize, msgSize)   \
+    BENCHMARK_KM_MSG(encrypt, transform, keySize, msgSize) \
+    BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
+
+#define BENCHMARK_KM_CIPHER_ALL_MSGS(transform, keySize) \
+    BENCHMARK_KM_ALL_MSGS(encrypt, transform, keySize)   \
+    BENCHMARK_KM_ALL_MSGS(decrypt, transform, keySize)
+
+#define BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, keySize) \
+    BENCHMARK_KM_ALL_MSGS(sign, transform, keySize)         \
+    BENCHMARK_KM_ALL_MSGS(verify, transform, keySize)
+// clang-format on
+
+/*
+ * ============= KeyGen TESTS ==================
+ */
+static void keygen(benchmark::State& state, string transform, int keySize) {
+    addDefaultLabel(state);
+    for (auto _ : state) {
+        keymaster->GenerateKey(transform, keySize);
+        state.PauseTiming();
+        keymaster->DeleteKey();
+        state.ResumeTiming();
+    }
+}
+
+BENCHMARK_KM(keygen, AES, 128);
+BENCHMARK_KM(keygen, AES, 256);
+
+BENCHMARK_KM(keygen, RSA, 2048);
+BENCHMARK_KM(keygen, RSA, 3072);
+BENCHMARK_KM(keygen, RSA, 4096);
+
+BENCHMARK_KM(keygen, EC, 224);
+BENCHMARK_KM(keygen, EC, 256);
+BENCHMARK_KM(keygen, EC, 384);
+BENCHMARK_KM(keygen, EC, 521);
+
+BENCHMARK_KM(keygen, DESede, 168);
+
+BENCHMARK_KM(keygen, Hmac, 64);
+BENCHMARK_KM(keygen, Hmac, 128);
+BENCHMARK_KM(keygen, Hmac, 256);
+BENCHMARK_KM(keygen, Hmac, 512);
+BENCHMARK_KM(keygen, Hmac, 1024);
+BENCHMARK_KM(keygen, Hmac, 2048);
+BENCHMARK_KM(keygen, Hmac, 4096);
+BENCHMARK_KM(keygen, Hmac, 8192);
+
+/*
+ * ============= SIGNATURE TESTS ==================
+ */
+
+static void sign(benchmark::State& state, string transform, int keySize, int msgSize) {
+    addDefaultLabel(state);
+    if (!keymaster->GenerateKey(transform, keySize, true)) {
+        state.SkipWithError(
+                ("Key generation error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    auto params = keymaster->getOperationParams(transform, true);
+    string message = keymaster->GenerateMessage(msgSize);
+
+    for (auto _ : state) {
+        state.PauseTiming();
+        auto opHandle = keymaster->SignBegin(params);
+        if (!opHandle) {
+            state.SkipWithError(
+                    ("Error beginning sign, " + std::to_string(keymaster->getError())).c_str());
+            return;
+        }
+        state.ResumeTiming();
+        if (!keymaster->ProcessMessage(*opHandle, message, params)) {
+            state.SkipWithError(("Sign error, " + std::to_string(keymaster->getError())).c_str());
+            break;
+        }
+    }
+}
+
+static void verify(benchmark::State& state, string transform, int keySize, int msgSize) {
+    addDefaultLabel(state);
+    if (!keymaster->GenerateKey(transform, keySize, true)) {
+        state.SkipWithError(
+                ("Key generation error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    AuthorizationSet out_params;
+    AuthorizationSet in_params = keymaster->getOperationParams(transform, true);
+    string message = keymaster->GenerateMessage(msgSize);
+    auto opHandle = keymaster->SignBegin(in_params, &out_params);
+    if (!opHandle) {
+        state.SkipWithError(
+                ("Error beginning sign, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    optional<string> signature =
+            keymaster->ProcessMessage(*opHandle, message, in_params, &out_params);
+    if (!signature) {
+        state.SkipWithError(("Sign error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    in_params.push_back(out_params);
+    for (auto _ : state) {
+        state.PauseTiming();
+        opHandle = keymaster->VerifyBegin(in_params);
+        if (!opHandle) {
+            state.SkipWithError(
+                    ("Verify begin error, " + std::to_string(keymaster->getError())).c_str());
+            return;
+        }
+        state.ResumeTiming();
+        if (!keymaster->ProcessMessage(*opHandle, message, in_params, &out_params, *signature)) {
+            state.SkipWithError(("Verify error, " + std::to_string(keymaster->getError())).c_str());
+            break;
+        }
+    }
+}
+
+// clang-format off
+#define BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(transform) \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 64)      \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 128)     \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 256)     \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 512)     \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 1024)    \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 2024)    \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 4096)    \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 8192)
+
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA1)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA256)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA224)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA256)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA384)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA512)
+
+#define BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(transform) \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 224)      \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 256)      \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 384)      \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 521)
+
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(NONEwithECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA1withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA224withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA256withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA384withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA512withECDSA);
+
+#define BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(transform) \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 2048)   \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 3072)   \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 4096)
+
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(MD5withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA1withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA);
+
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(MD5withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA1withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA/PSS);
+// clang-format on
+
+/*
+ * ============= CIPHER TESTS ==================
+ */
+
+static void encrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+    addDefaultLabel(state);
+    if (!keymaster->GenerateKey(transform, keySize)) {
+        state.SkipWithError(
+                ("Key generation error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    auto params = keymaster->getOperationParams(transform);
+    string message = keymaster->GenerateMessage(msgSize);
+
+    for (auto _ : state) {
+        state.PauseTiming();
+        auto opHandle = keymaster->EncryptBegin(params);
+        if (!opHandle) {
+            state.SkipWithError(
+                    ("Encryption begin error, " + std::to_string(keymaster->getError())).c_str());
+            return;
+        }
+        state.ResumeTiming();
+        if (!keymaster->ProcessMessage(*opHandle, message, params)) {
+            state.SkipWithError(
+                    ("Encryption error, " + std::to_string(keymaster->getError())).c_str());
+            break;
+        }
+    }
+}
+
+static void decrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+    addDefaultLabel(state);
+    if (!keymaster->GenerateKey(transform, keySize)) {
+        state.SkipWithError(
+                ("Key generation error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    AuthorizationSet out_params;
+    AuthorizationSet in_params = keymaster->getOperationParams(transform);
+    string message = keymaster->GenerateMessage(msgSize);
+    auto opHandle = keymaster->EncryptBegin(in_params, &out_params);
+    if (!opHandle) {
+        state.SkipWithError(
+                ("Encryption begin error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    auto encryptedMessage = keymaster->ProcessMessage(*opHandle, message, in_params, &out_params);
+    if (!encryptedMessage) {
+        state.SkipWithError(("Encryption error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    in_params.push_back(out_params);
+    for (auto _ : state) {
+        state.PauseTiming();
+        opHandle = keymaster->DecryptBegin(in_params);
+        if (!opHandle) {
+            state.SkipWithError(
+                    ("Decryption begin error, " + std::to_string(keymaster->getError())).c_str());
+            return;
+        }
+        state.ResumeTiming();
+        if (!keymaster->ProcessMessage(*opHandle, *encryptedMessage, in_params)) {
+            state.SkipWithError(
+                    ("Decryption error, " + std::to_string(keymaster->getError())).c_str());
+            break;
+        }
+    }
+}
+
+// clang-format off
+// AES
+#define BENCHMARK_KM_CIPHER_ALL_AES_KEYS(transform) \
+    BENCHMARK_KM_CIPHER_ALL_MSGS(transform, 128)    \
+    BENCHMARK_KM_CIPHER_ALL_MSGS(transform, 256)
+
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/CBC/NoPadding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/CBC/PKCS7Padding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/CTR/NoPadding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/ECB/NoPadding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/ECB/PKCS7Padding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/GCM/NoPadding);
+
+// Triple DES
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/CBC/NoPadding, 168);
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/CBC/PKCS7Padding, 168);
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/ECB/NoPadding, 168);
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/ECB/PKCS7Padding, 168);
+
+#define BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(transform, msgSize) \
+    BENCHMARK_KM_CIPHER(transform, 2048, msgSize)            \
+    BENCHMARK_KM_CIPHER(transform, 3072, msgSize)            \
+    BENCHMARK_KM_CIPHER(transform, 4096, msgSize)
+
+BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/NoPadding, SMALL_MESSAGE_SIZE);
+BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/PKCS1Padding, SMALL_MESSAGE_SIZE);
+BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/OAEPPadding, SMALL_MESSAGE_SIZE);
+// clang-format on
+
+}  // namespace test
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    ::benchmark::Initialize(&argc, argv);
+    base::CommandLine::Init(argc, argv);
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    auto service_name = command_line->GetSwitchValueASCII("service_name");
+    if (service_name.empty()) {
+        service_name = "default";
+    }
+    android::hardware::keymaster::V4_0::test::keymaster =
+            android::hardware::keymaster::V4_0::test::KeymasterWrapper::newInstance(service_name);
+    if (!android::hardware::keymaster::V4_0::test::keymaster) {
+        return 1;
+    }
+    ::benchmark::RunSpecifiedBenchmarks();
+}
\ No newline at end of file
diff --git a/keymaster/4.0/vts/performance/README b/keymaster/4.0/vts/performance/README
new file mode 100644
index 0000000..57d984a
--- /dev/null
+++ b/keymaster/4.0/vts/performance/README
@@ -0,0 +1,19 @@
+# Keymaster Benchmark
+
+The Keymaster Benchmark is a standalone tool for measuring the performance of keymaster implementations.
+
+## Building
+
+Build:
+`m  keymaster_benchmark`
+
+Transfer to device/emulator:
+`adb sync data`
+
+The benchmark executable should will be located at `data/benchmarktest/keymaster_benchmark/keymaster_benchmark` on the device.
+
+## Usage
+
+Keymaster Benchmark is built on [Google microbenchmark library](https://github.com/google/benchmark).
+All of the commandline arguments provided by the microbenchmark library are valid, such as `--benchmark_filter=<regex>` or `benchmark_out_format={json|console|csv}`.
+In addition to the command line arguments provided by microbenchmark, `--service_name=<service_name>` is provided allow specification of the keymaster service name, e.g. specify `--service_name=strongbox` to benchmark strongbox.
diff --git a/keymaster/4.1/Android.bp b/keymaster/4.1/Android.bp
new file mode 100644
index 0000000..3b505d8
--- /dev/null
+++ b/keymaster/4.1/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.keymaster@4.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IKeymasterDevice.hal",
+        "IOperation.hal",
+    ],
+    interfaces: [
+        "android.hardware.keymaster@3.0",
+        "android.hardware.keymaster@4.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/keymaster/4.1/IKeymasterDevice.hal b/keymaster/4.1/IKeymasterDevice.hal
new file mode 100644
index 0000000..64d2c9f
--- /dev/null
+++ b/keymaster/4.1/IKeymasterDevice.hal
@@ -0,0 +1,70 @@
+/*
+ * 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.keymaster@4.1;
+
+import @4.0::ErrorCode;
+import @4.0::HardwareAuthToken;
+import @4.0::IKeymasterDevice;
+import @4.0::KeyParameter;
+import @4.0::KeyPurpose;
+import @4.0::OperationHandle;
+import IOperation;
+
+/**
+ * @4.1::IKeymasterDevice is a minor extension to @4.0::IKeymasterDevice.  It adds support for
+ *
+ * - Partial hardware enforcment of UNLOCKED_DEVICE_REQUIRED keys;
+ * - Device-unique attestaion;
+ * - Early boot only keys;
+ * - Better cleanup of operations when clients die without completing or aborting them.
+ */
+interface IKeymasterDevice extends @4.0::IKeymasterDevice {
+    /**
+     * Called by client to notify the IKeymasterDevice that the device is now locked, and keys with
+     * the UNLOCKED_DEVICE_REQUIRED tag should no longer be usable.  When this function is called,
+     * the IKeymasterDevice should note the current timestamp, and attempts to use
+     * UNLOCKED_DEVICE_REQUIRED keys must be rejected with Error::DEVICE_LOCKED until an
+     * authentication token with a later timestamp is presented.  If the `passwordOnly' argument is
+     * set to true the sufficiently-recent authentication token must indicate that the user
+     * authenticated with a password, not a biometric.
+     *
+     * @param passwordOnly specifies whether the device must be unlocked with a password, rather
+     * than a biometric, before UNLOCKED_DEVICE_REQUIRED keys can be used.
+     */
+    deviceLocked(bool passwordOnly) generates (ErrorCode error);
+
+    /**
+     * Called by client to notify the IKeymasterDevice that the device has left the early boot
+     * state, and that keys with the EARLY_BOOT_ONLY tag may no longer be used.  All attempts to use
+     * an EARLY_BOOT_ONLY key after this method is called must fail with Error::INVALID_KEY_BLOB.
+     */
+    earlyBootEnded() generates (ErrorCode error);
+
+    /**
+     * Begins a cryptographic operation.  beginOp() is a variation on begin().  beginOp() has
+     * identical functionality to begin, but instead of an OperationHandle it returns an IOperation
+     * object.  An IKeymasterDevice HAL service must call linkToDeath() on the Operation before
+     * returning it, and the provided hidl_death_recipient, if called, must abort() the operation.
+     * This is to ensure that in the event a client crashes while an operation is in progress, the
+     * operation slot is freed and available for use by other clients.
+     *
+     * @4.1::IKeymasterDevices must implement both beginOp() and begin().
+     */
+    beginOp(KeyPurpose purpose, vec<uint8_t> keyBlob, vec<KeyParameter> inParams,
+        HardwareAuthToken authToken)
+        generates (ErrorCode error, vec<KeyParameter> outParam, IOperation operation);
+};
diff --git a/keymaster/4.1/IOperation.hal b/keymaster/4.1/IOperation.hal
new file mode 100644
index 0000000..7103e9e
--- /dev/null
+++ b/keymaster/4.1/IOperation.hal
@@ -0,0 +1,31 @@
+/*
+ * 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.keymaster@4.1;
+
+import @4.0::ErrorCode;
+import @4.0::OperationHandle;
+
+/**
+ * IOperation represents an in-progress IKeymasterDevice operation.  It is returned by
+ * IKeymasterDevice.beginOp().
+ */
+interface IOperation {
+    /**
+     * Returns the operation handle to be used as an authentication challenge.
+     */
+    getOperationChallenge() generates (ErrorCode error, OperationHandle operation);
+};
diff --git a/keymaster/4.1/default/Android.bp b/keymaster/4.1/default/Android.bp
new file mode 100644
index 0000000..b06878b
--- /dev/null
+++ b/keymaster/4.1/default/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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_binary {
+    name: "android.hardware.keymaster@4.1-service",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.keymaster@4.1-service.rc"],
+    srcs: ["service.cpp"],
+
+    shared_libs: [
+        "android.hardware.keymaster@4.0",
+        "android.hardware.keymaster@4.1",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libkeymaster4",
+        "libkeymaster41",
+        "liblog",
+        "libutils",
+    ],
+
+}
diff --git a/keymaster/4.1/default/OWNERS b/keymaster/4.1/default/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/keymaster/4.1/default/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/keymaster/4.1/default/android.hardware.keymaster@4.1-service.rc b/keymaster/4.1/default/android.hardware.keymaster@4.1-service.rc
new file mode 100644
index 0000000..740b3c2
--- /dev/null
+++ b/keymaster/4.1/default/android.hardware.keymaster@4.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.keymaster-4-1 /vendor/bin/hw/android.hardware.keymaster@4.1-service
+    interface android.hardware.keymaster@4.0::IKeymasterDevice default
+    interface android.hardware.keymaster@4.1::IKeymasterDevice default
+    class early_hal
+    user system
+    group system drmrpc
diff --git a/keymaster/4.1/default/service.cpp b/keymaster/4.1/default/service.cpp
new file mode 100644
index 0000000..d79a291
--- /dev/null
+++ b/keymaster/4.1/default/service.cpp
@@ -0,0 +1,35 @@
+/*
+** Copyright 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 <android-base/logging.h>
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <AndroidKeymaster41Device.h>
+
+using android::hardware::keymaster::V4_0::SecurityLevel;
+
+int main() {
+    ::android::hardware::configureRpcThreadpool(1, true /* willJoinThreadpool */);
+    auto keymaster = ::keymaster::V4_1::CreateKeymasterDevice(SecurityLevel::SOFTWARE);
+    auto status = keymaster->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Could not register service for Keymaster 4.1 (" << status << ")";
+    }
+
+    android::hardware::joinRpcThreadpool();
+    return -1;  // Should never get here.
+}
diff --git a/keymaster/4.1/support/Android.bp b/keymaster/4.1/support/Android.bp
new file mode 100644
index 0000000..34b6108
--- /dev/null
+++ b/keymaster/4.1/support/Android.bp
@@ -0,0 +1,32 @@
+//
+// 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 {
+    name: "libkeymaster4_1support",
+    vendor_available: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "android.hardware.keymaster@3.0",
+        "android.hardware.keymaster@4.0",
+        "android.hardware.keymaster@4.1",
+        "libkeymaster4support",
+    ]
+}
diff --git a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
new file mode 100644
index 0000000..afc0eaf
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
+#define HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
+
+#include <keymasterV4_0/authorization_set.h>
+
+#include <keymasterV4_1/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1 {
+
+using V4_0::AuthorizationSet;
+using V4_0::AuthorizationSetBuilder;
+using V4_0::KeyParameter;
+
+}  // namespace android::hardware::keymaster::V4_1
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
new file mode 100644
index 0000000..6ffe8e1
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_KEYMASTER_TAGS_H_
+#define HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_KEYMASTER_TAGS_H_
+
+#include <android/hardware/keymaster/4.1/types.h>
+
+#include <keymasterV4_0/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1 {
+
+using V4_0::BlockMode;
+using V4_0::Digest;
+using V4_0::EcCurve;
+using V4_0::ErrorCode;
+using V4_0::HardwareAuthToken;
+using V4_0::KeyParameter;
+using V4_0::PaddingMode;
+using V4_0::TagType;
+using V4_0::VerificationToken;
+
+using V4_0::TypedTag;
+
+using V4_0::TAG_ACTIVE_DATETIME;
+using V4_0::TAG_ALGORITHM;
+using V4_0::TAG_ALLOW_WHILE_ON_BODY;
+using V4_0::TAG_APPLICATION_DATA;
+using V4_0::TAG_APPLICATION_ID;
+using V4_0::TAG_ASSOCIATED_DATA;
+using V4_0::TAG_ATTESTATION_APPLICATION_ID;
+using V4_0::TAG_ATTESTATION_CHALLENGE;
+using V4_0::TAG_AUTH_TIMEOUT;
+using V4_0::TAG_BLOB_USAGE_REQUIREMENTS;
+using V4_0::TAG_BLOCK_MODE;
+using V4_0::TAG_BOOT_PATCHLEVEL;
+using V4_0::TAG_BOOTLOADER_ONLY;
+using V4_0::TAG_CALLER_NONCE;
+using V4_0::TAG_CONFIRMATION_TOKEN;
+using V4_0::TAG_CREATION_DATETIME;
+using V4_0::TAG_DIGEST;
+using V4_0::TAG_EC_CURVE;
+using V4_0::TAG_HARDWARE_TYPE;
+using V4_0::TAG_INCLUDE_UNIQUE_ID;
+using V4_0::TAG_INVALID;
+using V4_0::TAG_KEY_SIZE;
+using V4_0::TAG_MAC_LENGTH;
+using V4_0::TAG_MAX_USES_PER_BOOT;
+using V4_0::TAG_MIN_MAC_LENGTH;
+using V4_0::TAG_MIN_SECONDS_BETWEEN_OPS;
+using V4_0::TAG_NO_AUTH_REQUIRED;
+using V4_0::TAG_NONCE;
+using V4_0::TAG_ORIGIN;
+using V4_0::TAG_ORIGINATION_EXPIRE_DATETIME;
+using V4_0::TAG_OS_PATCHLEVEL;
+using V4_0::TAG_OS_VERSION;
+using V4_0::TAG_PADDING;
+using V4_0::TAG_PURPOSE;
+using V4_0::TAG_RESET_SINCE_ID_ROTATION;
+using V4_0::TAG_ROLLBACK_RESISTANCE;
+using V4_0::TAG_ROOT_OF_TRUST;
+using V4_0::TAG_RSA_PUBLIC_EXPONENT;
+using V4_0::TAG_TRUSTED_CONFIRMATION_REQUIRED;
+using V4_0::TAG_TRUSTED_USER_PRESENCE_REQUIRED;
+using V4_0::TAG_UNIQUE_ID;
+using V4_0::TAG_UNLOCKED_DEVICE_REQUIRED;
+using V4_0::TAG_USAGE_EXPIRE_DATETIME;
+using V4_0::TAG_USER_AUTH_TYPE;
+using V4_0::TAG_USER_ID;
+using V4_0::TAG_USER_SECURE_ID;
+using V4_0::TAG_VENDOR_PATCHLEVEL;
+
+#define DECLARE_KM_4_1_TYPED_TAG(name)                                                   \
+    typedef typename V4_0::Tag2TypedTag<(static_cast<V4_0::Tag>(V4_1::Tag::name))>::type \
+            TAG_##name##_t;                                                              \
+    static TAG_##name##_t TAG_##name;
+
+DECLARE_KM_4_1_TYPED_TAG(EARLY_BOOT_ONLY);
+DECLARE_KM_4_1_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION);
+
+}  // namespace android::hardware::keymaster::V4_1
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_KEYMASTER_TAGS_H_
diff --git a/keymaster/4.1/types.hal b/keymaster/4.1/types.hal
new file mode 100644
index 0000000..bdf1731
--- /dev/null
+++ b/keymaster/4.1/types.hal
@@ -0,0 +1,42 @@
+/*
+ * 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.keymaster@4.1;
+
+import @4.0::ErrorCode;
+import @4.0::Tag;
+import @4.0::TagType;
+
+enum Tag : @4.0::Tag {
+    /**
+     * Keys tagged with EARLY_BOOT_ONLY may only be used, or created, during early boot, until
+     * IKeymasterDevice::earlyBootEnded() is called.
+     */
+    EARLY_BOOT_ONLY = TagType:BOOL | 305,
+    /**
+     * DEVICE_UNIQUE_ATTESTATION is an argument to IKeymasterDevice::attestKey().  It indicates that
+     * attestation using a device-unique key is requested, rather than a batch key.  Only
+     * SecurityLevel::STRONGBOX IKeymasterDevices may support device-unique attestations.
+     * SecurityLevel::TRUSTED_ENVIRONMENT IKeymasterDevices must return ErrorCode::INVALID_ARGUMENT
+     * if they receive DEVICE_UNIQUE_ATTESTATION.  SecurityLevel::STRONGBOX IKeymasterDevices need
+     * not support DEVICE_UNIQUE_ATTESTATION, and return ErrorCode::CANNOT_ATTEST_IDS if they do not
+     * support it.
+     *
+     * IKeymasterDevice implementations that support device-unique attestation MUST add the
+     * DEVICE_UNIQUE_ATTESTATION tag to device-unique attestations.
+     */
+    DEVICE_UNIQUE_ATTESTATION = TagType:BOOL | 720,
+};
diff --git a/keymaster/4.1/vts/OWNERS b/keymaster/4.1/vts/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/keymaster/4.1/vts/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/keymaster/4.1/vts/functional/Android.bp b/keymaster/4.1/vts/functional/Android.bp
new file mode 100644
index 0000000..f5a0c9c
--- /dev/null
+++ b/keymaster/4.1/vts/functional/Android.bp
@@ -0,0 +1,30 @@
+//
+// 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: "VtsHalKeymasterV4_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "EarlyBootKeyTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.keymaster@4.0",
+        "android.hardware.keymaster@4.1",
+        "libkeymaster4support",
+        "libkeymaster4_1support",
+    ],
+    test_suites: ["vts-core"],
+}
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
similarity index 66%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
index 8bb72a1..4a19010 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
@@ -14,13 +14,8 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
+namespace android::hardware::keymaster::V4_1::test {
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
+// TODO(swillden): Put tests here.
 
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
-
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+}  // namespace android::hardware::keymaster::V4_1::test
diff --git a/light/2.0/Android.bp b/light/2.0/Android.bp
index 6068752..d51f10d 100644
--- a/light/2.0/Android.bp
+++ b/light/2.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/light/2.0/default/Android.bp b/light/2.0/default/Android.bp
index 72cc873..ed48825 100644
--- a/light/2.0/default/Android.bp
+++ b/light/2.0/default/Android.bp
@@ -23,7 +23,6 @@
         "libbase",
         "liblog",
         "libhidlbase",
-        "libhidltransport",
         "libhardware",
         "libutils",
         "android.hardware.light@2.0",
@@ -44,7 +43,6 @@
         "libutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.light@2.0",
     ],
 }
diff --git a/light/2.0/vts/functional/Android.bp b/light/2.0/vts/functional/Android.bp
index 9f03d27..2c0a08f 100644
--- a/light/2.0/vts/functional/Android.bp
+++ b/light/2.0/vts/functional/Android.bp
@@ -19,6 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalLightV2_0TargetTest.cpp"],
     static_libs: ["android.hardware.light@2.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/light/2.0/vts/functional/VtsHalLightV2_0TargetTest.cpp b/light/2.0/vts/functional/VtsHalLightV2_0TargetTest.cpp
index 13290d9..6fcecd2 100644
--- a/light/2.0/vts/functional/VtsHalLightV2_0TargetTest.cpp
+++ b/light/2.0/vts/functional/VtsHalLightV2_0TargetTest.cpp
@@ -16,11 +16,13 @@
 
 #define LOG_TAG "light_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/light/2.0/ILight.h>
 #include <android/hardware/light/2.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
 #include <unistd.h>
 #include <set>
 
@@ -73,25 +75,10 @@
     Type::WIFI
 };
 
-// Test environment for Light HIDL HAL.
-class LightHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static LightHidlEnvironment* Instance() {
-        static LightHidlEnvironment* instance = new LightHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<ILight>(); }
-   private:
-    LightHidlEnvironment() {}
-};
-
-class LightHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-public:
+class LightHidlTest : public testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override {
-        light = ::testing::VtsHalHidlTargetTestBase::getService<ILight>(
-            LightHidlEnvironment::Instance()->getServiceName<ILight>());
+        light = ILight::getService(GetParam());
 
         ASSERT_NE(light, nullptr);
         LOG(INFO) << "Test is remote " << light->isRemote();
@@ -120,13 +107,12 @@
             EXPECT_EQ(Status::SUCCESS, static_cast<Status>(ret));
         }
     }
-
 };
 
 /**
  * Ensure all lights which are reported as supported work.
  */
-TEST_F(LightHidlTest, TestSupported) {
+TEST_P(LightHidlTest, TestSupported) {
     for (const Type& type: supportedTypes) {
         Return<Status> ret = light->setLight(type, kWhite);
         EXPECT_OK(ret);
@@ -137,7 +123,7 @@
 /**
  * Ensure BRIGHTNESS_NOT_SUPPORTED is returned if LOW_PERSISTANCE is not supported.
  */
-TEST_F(LightHidlTest, TestLowPersistance) {
+TEST_P(LightHidlTest, TestLowPersistance) {
     for (const Type& type: supportedTypes) {
         Return<Status> ret = light->setLight(type, kLowPersistance);
         EXPECT_OK(ret);
@@ -151,7 +137,7 @@
 /**
  * Ensure lights which are not supported return LIGHT_NOT_SUPPORTED
  */
-TEST_F(LightHidlTest, TestUnsupported) {
+TEST_P(LightHidlTest, TestUnsupported) {
     std::set<Type> unsupportedTypes = kAllTypes;
     for (const Type& type: supportedTypes) {
         unsupportedTypes.erase(type);
@@ -164,11 +150,7 @@
     }
 }
 
-int main(int argc, char **argv) {
-    ::testing::AddGlobalTestEnvironment(LightHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    LightHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, LightHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ILight::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/light/utils/Android.bp b/light/utils/Android.bp
index ebcbfa2..4c287e4 100644
--- a/light/utils/Android.bp
+++ b/light/utils/Android.bp
@@ -24,7 +24,6 @@
         "android.hardware.light@2.0",
         "libbase",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
     ],
 }
diff --git a/light/utils/main.cpp b/light/utils/main.cpp
index d07e799..b834132 100644
--- a/light/utils/main.cpp
+++ b/light/utils/main.cpp
@@ -25,7 +25,7 @@
     std::cerr << msg << std::endl;
 }
 
-int main() {
+int main(int argc, char* argv[]) {
     using ::android::hardware::hidl_vec;
     using ::android::hardware::light::V2_0::Brightness;
     using ::android::hardware::light::V2_0::Flash;
@@ -41,10 +41,29 @@
         return -1;
     }
 
-    const static LightState off = {
-        .color = 0u, .flashMode = Flash::NONE, .brightnessMode = Brightness::USER,
+    static LightState off = {
+            .color = 0u,
+            .flashMode = Flash::NONE,
+            .brightnessMode = Brightness::USER,
     };
 
+    if (argc > 2) {
+        error("Usage: blank_screen [color]");
+        return -1;
+    }
+
+    if (argc > 1) {
+        char* col_ptr;
+        unsigned int col_new;
+
+        col_new = strtoul(argv[1], &col_ptr, 0);
+        if (*col_ptr != '\0') {
+            error("Failed to convert " + std::string(argv[1]) + " to number");
+            return -1;
+        }
+        off.color = col_new;
+    }
+
     service->getSupportedTypes([&](const hidl_vec<Type>& types) {
         for (Type type : types) {
             Status ret = service->setLight(type, off);
diff --git a/media/1.0/Android.bp b/media/1.0/Android.bp
index 844cfa2..2dbe466 100644
--- a/media/1.0/Android.bp
+++ b/media/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/media/bufferpool/1.0/Android.bp b/media/bufferpool/1.0/Android.bp
index 86297d3..079e47f 100644
--- a/media/bufferpool/1.0/Android.bp
+++ b/media/bufferpool/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index 0faa00e..6a82616 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/media/c2/1.0/Android.bp b/media/c2/1.0/Android.bp
index 895e9db..391e6c4 100644
--- a/media/c2/1.0/Android.bp
+++ b/media/c2/1.0/Android.bp
@@ -31,4 +31,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/media/omx/1.0/Android.bp b/media/omx/1.0/Android.bp
index ee51d5d..5fe73ab 100644
--- a/media/omx/1.0/Android.bp
+++ b/media/omx/1.0/Android.bp
@@ -23,4 +23,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/memtrack/1.0/Android.bp b/memtrack/1.0/Android.bp
index 0f24977..a50195e 100644
--- a/memtrack/1.0/Android.bp
+++ b/memtrack/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/memtrack/1.0/default/Android.bp b/memtrack/1.0/default/Android.bp
index 76d7fc8..8aa33ee 100644
--- a/memtrack/1.0/default/Android.bp
+++ b/memtrack/1.0/default/Android.bp
@@ -23,7 +23,6 @@
         "libbase",
         "liblog",
         "libhidlbase",
-        "libhidltransport",
         "libhardware",
         "libutils",
         "android.hardware.memtrack@1.0",
@@ -46,7 +45,6 @@
         "libutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.memtrack@1.0",
     ],
 
diff --git a/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc b/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
index 4327a20..f5eee54 100644
--- a/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
+++ b/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.memtrack-hal-1-0 /vendor/bin/hw/android.hardware.memtrack@1.0-service
+    interface android.hardware.memtrack@1.0::IMemtrack default
     class hal
     user system
     group system
diff --git a/memtrack/1.0/vts/functional/Android.bp b/memtrack/1.0/vts/functional/Android.bp
index d682e0b..9e5cf6d 100644
--- a/memtrack/1.0/vts/functional/Android.bp
+++ b/memtrack/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalMemtrackV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.memtrack@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp b/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp
index 691ecca..cccedca 100644
--- a/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp
+++ b/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp
@@ -20,8 +20,9 @@
 
 #include <android/hardware/memtrack/1.0/IMemtrack.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <fcntl.h>
 #include <algorithm>
@@ -39,23 +40,10 @@
 using std::vector;
 using std::count_if;
 
-// Test environment for Memtrack HIDL HAL.
-class MemtrackHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static MemtrackHidlEnvironment* Instance() {
-        static MemtrackHidlEnvironment* instance = new MemtrackHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IMemtrack>(); }
-};
-
-class MemtrackHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class MemtrackHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-      memtrack = ::testing::VtsHalHidlTargetTestBase::getService<IMemtrack>(
-          MemtrackHidlEnvironment::Instance()->getServiceName<IMemtrack>());
+      memtrack = IMemtrack::getService(GetParam());
       ASSERT_NE(memtrack, nullptr);
   }
 
@@ -93,7 +81,7 @@
 
 /* Sanity check results when getMemory() is passed a negative PID
  */
-TEST_F(MemtrackHidlTest, BadPidTest) {
+TEST_P(MemtrackHidlTest, BadPidTest) {
   MemtrackStatus s;
   hidl_vec<MemtrackRecord> v;
   auto cb = generate_cb(&s, &v);
@@ -108,7 +96,7 @@
 
 /* Sanity check results when getMemory() is passed a bad memory usage type
  */
-TEST_F(MemtrackHidlTest, BadTypeTest) {
+TEST_P(MemtrackHidlTest, BadTypeTest) {
   MemtrackStatus s;
   hidl_vec<MemtrackRecord> v;
   auto cb = generate_cb(&s, &v);
@@ -121,7 +109,7 @@
  * for all memory types, including valid flag combinations for every
  * MemtrackRecord returned.
  */
-TEST_F(MemtrackHidlTest, GetMemoryTest) {
+TEST_P(MemtrackHidlTest, GetMemoryTest) {
   /* Opening this device causes the kernel to provide memtrack with memory
    * info for this process.
    */
@@ -172,11 +160,7 @@
                   static_cast<uint32_t>(MemtrackType::NUM_TYPES));
 }
 
-int main(int argc, char **argv) {
-    ::testing::AddGlobalTestEnvironment(MemtrackHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    MemtrackHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, MemtrackHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMemtrack::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/neuralnetworks/1.0/Android.bp b/neuralnetworks/1.0/Android.bp
index 63b5b98..3e740c4 100644
--- a/neuralnetworks/1.0/Android.bp
+++ b/neuralnetworks/1.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/neuralnetworks/1.0/IPreparedModel.hal b/neuralnetworks/1.0/IPreparedModel.hal
index ecaa7f8..3dc3202 100644
--- a/neuralnetworks/1.0/IPreparedModel.hal
+++ b/neuralnetworks/1.0/IPreparedModel.hal
@@ -42,11 +42,21 @@
      * execute function. This callback must be provided with the ErrorStatus of
      * the execution.
      *
-     * If the prepared model was prepared from a model wherein all
-     * tensor operands have fully specified dimensions, and the inputs
-     * to the function are valid, then the execution should launch
-     * and complete successfully (ErrorStatus::NONE). There must be
-     * no failure unless the device itself is in a bad state.
+     * If the launch is successful, the caller must not change the content of
+     * any data object referenced by 'request' (described by the
+     * {@link DataLocation} of a {@link RequestArgument}) until the
+     * asynchronous task has invoked the callback object. The asynchronous task
+     * must not change the content of any of the data objects corresponding to
+     * 'request' inputs.
+     *
+     * If the prepared model was prepared from a model wherein all tensor
+     * operands have fully specified dimensions, and the inputs to the function
+     * are valid, then:
+     * - the execution should launch successfully (ErrorStatus::NONE): There
+     *   must be no failure unless the device itself is in a bad state.
+     * - if at execution time every operation's input operands have legal
+     *   values, the execution should complete successfully (ErrorStatus::NONE):
+     *   There must be no failure unless the device itself is in a bad state.
      *
      * Multiple threads can call the execute function on the same IPreparedModel
      * object concurrently with different requests.
diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal
index 02db063..ba9d068 100644
--- a/neuralnetworks/1.0/types.hal
+++ b/neuralnetworks/1.0/types.hal
@@ -25,25 +25,24 @@
  * with at least one dimension). Types not prefaced by TENSOR_* represent
  * scalar values and must have no dimensions.
  *
- * Although many types are defined, most operators accept just a few
+ * Although we define many types, most operators accept just a few
  * types. Most used are {@link OperandType::TENSOR_FLOAT32},
  * {@link OperandType::TENSOR_QUANT8_ASYMM},
  * and {@link OperandType::INT32}.
  */
 enum OperandType : int32_t {
     /** A 32 bit floating point scalar value. */
-    FLOAT32             = 0,
+    FLOAT32 = 0,
     /** A signed 32 bit integer scalar value. */
-    INT32               = 1,
+    INT32 = 1,
     /** An unsigned 32 bit integer scalar value. */
-    UINT32              = 2,
-
+    UINT32 = 2,
     /** A tensor of 32 bit floating point values. */
-    TENSOR_FLOAT32      = 3,
+    TENSOR_FLOAT32 = 3,
     /** A tensor of 32 bit integer values. */
-    TENSOR_INT32        = 4,
+    TENSOR_INT32 = 4,
     /**
-     * A tensor of 8 bit integers that represent real numbers.
+     * A tensor of 8 bit unsigned integers that represent real numbers.
      *
      * Attached to this tensor are two numbers that can be used to convert the
      * 8 bit integer to the real value and vice versa. These two numbers are:
@@ -51,21 +50,21 @@
      * - zeroPoint: a 32 bit integer, in range [0, 255].
      *
      * The formula is:
-     * real_value = (integer_value - zeroPoint) * scale.
+     *   real_value = (integer_value - zeroPoint) * scale.
      */
     TENSOR_QUANT8_ASYMM = 5,
 
     /**
-     * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
-     * OEM operation and data types.
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
      *
      * OEM specific scalar value.
      */
     OEM                 = 10000,
 
     /**
-     * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
-     * OEM operation and data types.
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
      *
      * A tensor of OEM specific values.
      */
@@ -78,7 +77,6 @@
  * The type of an operation in a model.
  */
 enum OperationType : int32_t {
-
     /**
      * Adds two tensors, element-wise.
      *
@@ -110,14 +108,16 @@
      * * 0: A tensor.
      * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
      *      as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
      * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
      *      {@link FusedActivationFunc} values. Specifies the activation to
      *      invoke on the result.
      *
      * Outputs:
      * * 0: The sum, a tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
      */
     ADD = 0,
 
@@ -187,8 +187,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth].
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     AVERAGE_POOL_2D = 1,
 
@@ -206,22 +206,23 @@
      *
      * Inputs:
      * * 0 ~ n-1: The list of n input tensors, of shape
-     *            [D0, D1, ..., Daxis(i), ..., Dm]. For inputs of
-     *            {@link OperandType::TENSOR_QUANT8_ASYMM}, all input tensors
-     *            must have the same scale and zeroPoint.
+     *            [D0, D1, ..., Daxis(i), ..., Dm].
+     *            All input tensors of
+     *            {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *            must have the same scale and zeroPoint as the output tensor.
      * * n: An {@link OperandType::INT32} scalar, specifying the
      *      concatenation axis.
      *
      * Outputs:
      * * 0: The output, a tensor of the same {@link OperandType} as the input
      *      tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm].
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor, the scale and zeroPoint
+     *      values must be the same as the input tensors'.
      */
     CONCATENATION = 2,
 
     /**
-     * Performs an 2-D convolution operation.
+     * Performs a 2-D convolution operation.
      *
      * The CONV_2D op sweeps a 2-D filter that can mix channels together over a
      * batch of images, applying the filter to each window of each image of the
@@ -238,11 +239,17 @@
      *             filter[channel, di, dj, k]
      *         ) + bias[channel]
      *
-     * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * Supported tensor {@link OperandType} configurations:
+     * * 32 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias.
      *
-     * Supported tensor rank: 4, with "NHWC" data layout.
+     * * Quantized:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width,
+     * and Channels) data layout.
      *
      * Both explicit padding and implicit padding are supported.
      *
@@ -252,12 +259,12 @@
      * * 1: A 4-D tensor, of shape
      *      [depth_out, filter_height, filter_width, depth_in], specifying the
      *      filter.
-     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias.
-     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias
-     *      should also be of {@link OperandType::TENSOR_FLOAT32}. For input
-     *      tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias
-     *      should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
-     *      0 and bias_scale == input_scale * filter_scale.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
      * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
      *      the left, in the ‘width’ dimension.
      * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -281,11 +288,11 @@
      *      [depth_out, filter_height, filter_width, depth_in], specifying the
      *      filter.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
-     *      tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
-     *      also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
-     *      of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
-     *      of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
-     *      bias_scale == input_scale * filter_scale.
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
      * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
      *      padding scheme, has to be one of the
      *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
@@ -299,11 +306,9 @@
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
-     *      [batches, out_height, out_width, depth_out]. For output tensor of
-     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition
-     *      must be satisfied: output_scale > input_scale * filter_scale.
-     *
-     * Available since API level 27.
+     *      [batches, out_height, out_width, depth_out].
+     *      For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the following condition must be satisfied: output_scale > input_scale * filter_scale
      */
     CONV_2D = 3,
 
@@ -329,11 +334,17 @@
      *             filter[1, di, dj, k * channel_multiplier + q]
      *         ) + bias[k * channel_multiplier + q]
      *
-     * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * Supported tensor {@link OperandType} configurations:
+     * * 32 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias.
      *
-     * Supported tensor rank: 4, with "NHWC" data layout.
+     * * Quantized:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width,
+     * and Channels) data layout.
      *
      * Both explicit padding and implicit padding are supported.
      *
@@ -343,11 +354,11 @@
      * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
      *      specifying the filter.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
-     *      tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
-     *      also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
-     *      of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
-     *      of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
-     *      bias_scale == input_scale * filter_scale.
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
      * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
      *      the left, in the ‘width’ dimension.
      * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -372,11 +383,11 @@
      * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
      *      specifying the filter.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
-     *      tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
-     *      also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
-     *      of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
-     *      of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
-     *      bias_scale == input_scale * filter_scale.
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
      * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
      *      padding scheme, has to be one of the
      *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
@@ -392,11 +403,10 @@
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
-     *      [batches, out_height, out_width, depth_out]. For output tensor of
-     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition
-     *      must be satisfied: output_scale > input_scale * filter_scale.
-     *
-     * Available since API level 27.
+     *      [batches, out_height, out_width, depth_out]. For
+     *      output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the following condition must be satisfied:
+     *      output_scale > input_scale * filter_scale
      */
     DEPTHWISE_CONV_2D = 4,
 
@@ -419,7 +429,8 @@
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
-     * Supported tensor rank: 4, with "NHWC" data layout.
+     * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width,
+     * and Channels) data layout.
      *
      * Inputs:
      * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
@@ -431,8 +442,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape [batch, height*block_size,
      *      width*block_size, depth/(block_size*block_size)].
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     DEPTH_TO_SPACE = 5,
 
@@ -443,19 +454,19 @@
      *
      *     output = (input - zeroPoint) * scale.
      *
-     * Supported tensor {@link OperandType}:
+     * Supported input tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
+     * Supported output tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT32}.
+     *
      * Supported tensor rank: up to 4
      *
      * Inputs:
-     * * 0: A tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}.
+     * * 0: A tensor.
      *
      * Outputs:
-     * * 0: The output tensor of same shape as input0, but with
-     *      {@link OperandType::TENSOR_FLOAT32}.
-     *
-     * Available since API level 27.
+     * * 0: A tensor with the same shape as input0.
      */
     DEQUANTIZE = 6,
 
@@ -479,6 +490,13 @@
      * If a value in Lookups is out of bounds, the operation must fail
      * and an error must be reported.
      *
+     * Supported value tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported value tensor rank: from 2
+     *
      * Inputs:
      * * 0: Lookups. A 1-D tensor of {@link OperandType::TENSOR_INT32}.
      *      The values are indices into the first dimension of Values.
@@ -489,8 +507,8 @@
      * * 0: A n-D tensor with the same rank and shape as the Values
      *      tensor, except for the first dimension which has the same size
      *      as Lookups' only dimension.
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input1.
      */
     EMBEDDING_LOOKUP = 7,
 
@@ -508,8 +526,6 @@
      * Outputs:
      * * 0: The output tensor, of the same {@link OperandType} and dimensions as
      *      the input tensor.
-     *
-     * Available since API level 27.
      */
     FLOOR = 8,
 
@@ -549,12 +565,9 @@
      *      invoke on the result.
      *
      * Outputs:
-     * * 0: The output tensor, of shape [batch_size, num_units]. For output
-     *      tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following
-     *      condition must be satisfied:
-     *      output_scale > input_scale * filter_scale.
-     *
-     * Available since API level 27.
+     * * 0: The output tensor, of shape [batch_size, num_units]. For
+     *      output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following
+     *      condition must be satisfied: output_scale > input_scale * filter_scale.
      */
     FULLY_CONNECTED = 9,
 
@@ -585,6 +598,13 @@
      * must be selected. If no entry in Keys has 123456, a slice of zeroes
      * must be concatenated.
      *
+     * Supported value tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported value tensor rank: from 2
+     *
      * Inputs:
      * * 0: Lookups. A 1-D {@link OperandType::TENSOR_INT32} tensor with
      *      shape [ k ].
@@ -598,13 +618,13 @@
      *
      * Outputs:
      * * 0: Output. A tensor with shape [ k …].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input2.
      * * 1: Hits. A boolean tensor with shape [ k ] indicates whether the lookup
      *      hits (True) or not (False).
      *      Stored as {@link OperandType::TENSOR_QUANT8_ASYMM} with offset 0
      *      and scale 1.0f.
      *      A non-zero byte represents True, a hit. A zero indicates otherwise.
-     *
-     * Available since API level 27.
      */
     HASHTABLE_LOOKUP = 10,
 
@@ -617,9 +637,6 @@
      *         input[batch, row, col, channel] /
      *         sqrt(sum_{c} pow(input[batch, row, col, c], 2))
      *
-     * For input tensor with more dimensions, independently normalizes each 1-D
-     * slice along dimension dim.
-     *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
      *
@@ -627,13 +644,10 @@
      * Height, Width, and Channels).
      *
      * Inputs:
-     * * 0: A 4-D tensor, of shape [batches, height, width, depth].
+     * * 0: A 4-D tensor, specifying the tensor to be normalized.
      *
      * Outputs:
-     * * 0: The output 4-D tensor, of the same shape as input
-     *      [batches, height, width, depth].
-     *
-     * Available since API level 27.
+     * * 0: A tensor of the same {@link OperandType} and same shape as input0.
      */
     L2_NORMALIZATION = 11,
 
@@ -652,7 +666,8 @@
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
      *
-     * Supported tensor rank: 4, with "NHWC" data layout.
+     * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width,
+     * and Channels) data layout.
      *
      * Both explicit padding and implicit padding are supported.
      *
@@ -700,8 +715,6 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth].
-     *
-     * Available since API level 27.
      */
     L2_POOL_2D = 12,
 
@@ -729,17 +742,18 @@
      *      the input.
      * * 1: An {@link OperandType::INT32} scalar, specifying the radius of
      *      the normalization window.
-     * * 2: An {@link OperandType::FLOAT32} scalar, specifying the bias, must
-     *      not be zero.
-     * * 3: An {@link OperandType::FLOAT32} scalar, specifying the scale
-     *      factor, alpha.
-     * * 4: An {@link OperandType::FLOAT32} scalar, specifying the exponent,
-     *      beta.
+     * * 2: A scalar, specifying the bias, must not be zero.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias
+     *      value must be of {@link OperandType::FLOAT32}.
+     * * 3: A scalar, specifying the scale factor, alpha.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the
+     *      alpha value must be of {@link OperandType::FLOAT32}.
+     * * 4: A scalar, specifying the exponent, beta.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the beta
+     *      value must be of {@link OperandType::FLOAT32}.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 27.
      */
     LOCAL_RESPONSE_NORMALIZATION = 13,
 
@@ -763,45 +777,53 @@
      * * 0: The output tensor of same shape as input0.
      *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the scale must be 1.f / 256 and the zeroPoint must be 0.
-     *
-     * Available since API level 27.
      */
     LOGISTIC = 14,
 
     /**
      * Projects an input to a bit vector via locality senstive hashing.
      *
+     * Supported input tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported input tensor rank: from 1
+     *
      * Inputs:
      * * 0: Hash functions. Dim.size == 2, DataType: Float.
-     *            Tensor[0].Dim[0]: Number of hash functions.
-     *            Tensor[0].Dim[1]: Number of seeds per hash functions.
-     *            Tensor[0].Dim[1] <= 32 in sparse case.
+     *      Tensor[0].Dim[0]: Number of hash functions.
+     *      Tensor[0].Dim[1]: Number of projected output bits generated by each
+     *      hash function.
+     *      If the projection type is Sparse:
+     *      Tensor[0].Dim[1] + ceil(log2(Tensor[0].Dim[0])) <= 32
      *
      * * 1: Input. Dim.size >= 1, no restriction on DataType.
      * * 2: Weight. Optional. Dim.size == 1, DataType: Float.
-     *     If not set, each input element is considered to have the same weight
-     *     of 1.0.
-     *     Tensor[1].Dim[0] == Tensor[2].Dim[0]
+     *      If not set, each input element is considered to have the same weight
+     *      of 1.0.
+     *      Tensor[1].Dim[0] == Tensor[2].Dim[0]
      * * 3: Type:
-     *        Sparse: Value LSHProjectionType_SPARSE(=1).
+     *        Sparse:
+     *          Value LSHProjectionType_SPARSE(=1).
      *          Computed bit vector is considered to be sparse.
      *          Each output element is an int32 made up of multiple bits
      *          computed from hash functions.
      *
-     *        Dense: Value LSHProjectionType_DENSE(=2).
+     *        Dense:
+     *          Value LSHProjectionType_DENSE(=2).
      *          Computed bit vector is considered to be dense. Each output
      *          element represents a bit and can take the value of either
      *          0 or 1.
      *
      * Outputs:
-     * * 0: If the projection type is sparse:
-     *        Output.Dim == { Tensor[0].Dim[0] }
-     *        A tensor of int32 that represents hash signatures.
-     *      If the projection type is Dense:
-     *        Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] }
-     *        A flattened tensor that represents projected bit vectors.
+     * * 0: If the projection type is Sparse:
+     *      Output.Dim == { Tensor[0].Dim[0] }
+     *      A tensor of int32 that represents hash signatures.
      *
-     * Available since API level 27.
+     *      If the projection type is Dense:
+     *      Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] }
+     *      A flattened tensor that represents projected bit vectors.
      */
     LSH_PROJECTION = 15,
 
@@ -901,71 +923,54 @@
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
      *
+     * All input and output tensors must be of the same type.
+     *
      * Inputs:
      * * 0: The input (\f$x_t\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, input_size], where “batch_size” corresponds to the
-     *      batching dimension, and “input_size” is the size of the input.
+     *      A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+     *      corresponds to the batching dimension, and “input_size” is the size
+     *      of the input.
      * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, input_size], where “num_units” corresponds to the
-     *      number of cell units.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of cell units.
      * * 2: The input-to-forget weights (\f$W_{xf}\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, input_size].
+     *      A 2-D tensor of shape [num_units, input_size].
      * * 3: The input-to-cell weights (\f$W_{xc}\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, input_size].
+     *      A 2-D tensor of shape [num_units, input_size].
      * * 4: The input-to-output weights (\f$W_{xo}\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, input_size].
+     *      A 2-D tensor of shape [num_units, input_size].
      * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, output_size], where “output_size” corresponds to either
-     *      the number of cell units (i.e., “num_units”), or the second
-     *      dimension of the “projection_weights”, if defined.
+     *      A 2-D tensor of shape [num_units, output_size], where “output_size”
+     *      corresponds to either the number of cell units (i.e., “num_units”),
+     *      or the second dimension of the “projection_weights”, if defined.
      * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, output_size].
+     *      A 2-D tensor of shape [num_units, output_size].
      * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, output_size].
+     *      A 2-D tensor of shape [num_units, output_size].
      * * 8: The recurrent-to-output weights (\f$W_{ho}\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, output_size].
+     *      A 2-D tensor of shape [num_units, output_size].
      * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional.
-     *      A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units].
+     *      A 1-D tensor of shape [num_units].
      * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional.
-     *      A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units].
+     *      A 1-D tensor of shape [num_units].
      * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional.
-     *      A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units].
+     *      A 1-D tensor of shape [num_units].
      * * 12:The input gate bias (\f$b_i\f$). Optional.
-     *      A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units].
+     *      A 1-D tensor of shape [num_units].
      * * 13:The forget gate bias (\f$b_f\f$).
-     *      A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units].
+     *      A 1-D tensor of shape [num_units].
      * * 14:The cell bias (\f$b_c\f$).
-     *      A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units].
+     *      A 1-D tensor of shape [num_units].
      * * 15:The output gate bias (\f$b_o\f$).
-     *      A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units].
+     *      A 1-D tensor of shape [num_units].
      * * 16:The projection weights (\f$W_{proj}\f$). Optional.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [output_size, num_units].
+     *      A 2-D tensor of shape [output_size, num_units].
      * * 17:The projection bias (\f$b_{proj}\f$). Optional.
-     *      A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [output_size].
+     *      A 1-D tensor of shape [output_size].
      * * 18:The output state (in) (\f$h_{t-1}\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, output_size].
+     *      A 2-D tensor of shape [batch_size, output_size].
      * * 19:The cell state (in) (\f$C_{t-1}\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, num_units].
+     *      A 2-D tensor of shape [batch_size, num_units].
      * * 20:The activation function (\f$g\f$).
      *      A value indicating the activation function:
      *      <ul>
@@ -984,21 +989,15 @@
      *
      * Outputs:
      * * 0: The scratch buffer.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, num_units * 3] with CIFG, or
+     *      A 2-D tensor of shape [batch_size, num_units * 3] with CIFG, or
      *      [batch_size, num_units * 4] without CIFG.
      * * 1: The output state (out) (\f$h_t\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, output_size].
+     *      A 2-D tensor of shape [batch_size, output_size].
      * * 2: The cell state (out) (\f$C_t\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, num_units].
+     *      A 2-D tensor of shape [batch_size, num_units].
      * * 3: The output (\f$o_t\f$).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, output_size]. This is effectively the same as the
-     *      current “output state (out)” value.
-     *
-     * Available since API level 27.
+     *      A 2-D tensor of shape [batch_size, output_size]. This is effectively
+     *      the same as the current “output state (out)” value.
      */
     LSTM = 16,
 
@@ -1019,7 +1018,8 @@
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
-     * Supported tensor rank: 4, with "NHWC" data layout.
+     * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width,
+     * and Channels) data layout.
      *
      * Both explicit padding and implicit padding are supported.
      *
@@ -1067,8 +1067,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth].
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     MAX_POOL_2D = 17,
 
@@ -1106,8 +1106,6 @@
      *      For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the following condition must be satisfied:
      *      output_scale > input1_scale * input2_scale.
-     *
-     * Available since API level 27.
      */
     MUL = 18,
 
@@ -1129,8 +1127,8 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     RELU = 19,
 
@@ -1151,9 +1149,9 @@
      * * 0: A tensor, specifying the input.
      *
      * Outputs:
-     * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 27.
+     * * 0: The output tensor of the same shape as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     RELU1 = 20,
 
@@ -1175,8 +1173,8 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     RELU6 = 21,
 
@@ -1205,8 +1203,8 @@
      *
      * Outputs:
      * * 0: The output tensor, of shape specified by the input shape.
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     RESHAPE = 22,
 
@@ -1220,9 +1218,10 @@
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
      *
-     * Supported tensor rank: 4, with "NHWC" data layout.
+     * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width,
+     * and Channels) data layout.
      *
-     * Inputs:
+     * Inputs (resizing by shape):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
      *      the input.
      * * 1: An {@link OperandType::INT32} scalar, specifying the output
@@ -1233,8 +1232,6 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, new_height, new_width, depth].
-     *
-     * Available since API level 27.
      */
     RESIZE_BILINEAR = 23,
 
@@ -1257,25 +1254,23 @@
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
      *
+     * The input tensors must all be the same type.
+     *
      * Inputs:
      * * 0: input.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32} of shape
-     *      [batch_size, input_size], where “batch_size” corresponds to the
-     *      batching dimension, and “input_size” is the size of the input.
+     *      A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+     *      corresponds to the batching dimension, and “input_size” is the size
+     *      of the input.
      * * 1: weights.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, input_size], where “num_units” corresponds to the
-     *      number of units.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of units.
      * * 2: recurrent_weights.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, num_units], with columns corresponding to the weights
-     *      from each unit.
+     *      A 2-D tensor of shape [num_units, num_units], with columns
+     *      corresponding to the weights from each unit.
      * * 3: bias.
-     *      A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units].
+     *      A 1-D tensor of shape [num_units].
      * * 4: hidden state (in).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, num_units].
+     *      A 2-D tensor of shape [batch_size, num_units].
      * * 5: fused_activation_function.
      *      An optional {@link FusedActivationFunc} value indicating the
      *      activation function. If “NONE” is specified then it results in a
@@ -1283,15 +1278,11 @@
      *
      * Outputs:
      * * 0: hidden state (out).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, num_units].
+     *      A 2-D tensor of shape [batch_size, num_units].
      *
      * * 1: output.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, num_units]. This is effectively the same as the
-     *      current state value.
-     *
-     * Available since API level 27.
+     *      A 2-D tensor of shape [batch_size, num_units]. This is effectively
+     *      the same as the current state value.
      */
     RNN = 24,
 
@@ -1306,6 +1297,9 @@
      *         exp((input[batch, i] - max(input[batch, :])) * beta) /
      *         sum_{k}{exp((input[batch, k] - max(input[batch, :])) * beta)}
      *
+     * For input tensor with rank other than 2, the activation will be applied
+     * independently on each 1-D slice along specified dimension.
+     *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
@@ -1314,15 +1308,15 @@
      *
      * Inputs:
      * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped.
-     * * 1: An {@link OperandType::FLOAT32} scalar, specifying the positive
-     *      scaling factor for the exponent, beta.
+     * * 1: A scalar, specifying the positive scaling factor for the exponent,
+     *      beta. If input0 is of {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the scalar must be of
+     *      {@link OperandType::FLOAT32}.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
      *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the scale must be 1.f / 256 and the zeroPoint must be 0.
-     *
-     * Available since API level 27.
      */
     SOFTMAX = 25,
 
@@ -1344,7 +1338,8 @@
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
-     * Supported tensor rank: 4, with "NHWC" data layout.
+     * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width,
+     * and Channels) data layout.
      *
      * Inputs:
      * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
@@ -1356,8 +1351,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape [batches, height/block_size,
      *      width/block_size, depth_in*block_size*block_size].
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     SPACE_TO_DEPTH = 26,
 
@@ -1403,25 +1398,23 @@
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
      *
+     * All input tensors must be the same type.
+     *
      * Inputs:
      * * 0: input.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, input_size], where “batch_size” corresponds to the
-     *      batching dimension, and “input_size” is the size of the input.
+     *      A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+     *      corresponds to the batching dimension, and “input_size” is the size
+     *      of the input.
      * * 1: weights_feature.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, input_size], where “num_units” corresponds to the
-     *      number of units.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of units.
      * * 2: weights_time.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [num_units, memory_size], where “memory_size” corresponds to the
-     *      fixed-size of the memory.
+     *      A 2-D tensor of shape [num_units, memory_size], where “memory_size”
+     *      corresponds to the fixed-size of the memory.
      * * 3: bias.
-     *      An optional 1-D tensor of {@link OperandType::TENSOR_FLOAT32},
-     *      of shape [num_units].
+     *      An optional 1-D tensor of shape [num_units].
      * * 4: state (in).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, (memory_size - 1) * num_units * rank].
+     *      A 2-D tensor of shape [batch_size, (memory_size - 1) * num_units * rank].
      * * 5: rank.
      *      The rank of the SVD approximation.
      * * 6: fused_activation_function.
@@ -1431,13 +1424,11 @@
      *
      * Outputs:
      * * 0: state (out).
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+     *      A 2-D tensor of the same {@link OperandType} as the inputs, with shape
      *      [batch_size, (memory_size - 1) * num_units * rank].
      * * 1: output.
-     *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+     *      A 2-D tensor of the same {@link OperandType} as the inputs, with shape
      *      [batch_size, num_units].
-     *
-     * Available since API level 27.
      */
     SVDF = 27,
 
@@ -1458,8 +1449,6 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 27.
      */
     TANH = 28,
 
diff --git a/neuralnetworks/1.0/types.t b/neuralnetworks/1.0/types.t
new file mode 100644
index 0000000..d7b26aa
--- /dev/null
+++ b/neuralnetworks/1.0/types.t
@@ -0,0 +1,431 @@
+%% template file for generating types.hal.
+%% see frameworks/ml/nn/tools/api/README.md.
+/*
+ * 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.neuralnetworks@1.0;
+
+%insert Operand_1.0_Comment
+enum OperandType : int32_t {
+%insert Operand_1.0
+
+    /**
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
+     *
+     * OEM specific scalar value.
+     */
+    OEM                 = 10000,
+
+    /**
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
+     *
+     * A tensor of OEM specific values.
+     */
+    TENSOR_OEM_BYTE     = 10001,
+};
+
+%insert Operation_1.0_Comment
+enum OperationType : int32_t {
+%insert Operation_1.0
+
+    /**
+     * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
+     * OEM operation and data types.
+     *
+     * This operation is OEM specific. It should only be used for OEM
+     * applications.
+     */
+    OEM_OPERATION = 10000,
+};
+
+/**
+ * Fused activation function types.
+ */
+enum FusedActivationFunc : int32_t {
+    NONE  = 0,
+    RELU  = 1,
+    RELU1 = 2,
+    RELU6 = 3,
+};
+
+/**
+ * How an operand is used.
+ */
+enum OperandLifeTime : int32_t {
+    /**
+     * The operand is internal to the model. It's created by an operation and
+     * consumed by other operations. It must be an output operand of
+     * exactly one operation.
+     */
+    TEMPORARY_VARIABLE,
+
+    /**
+     * The operand is an input of the model. It must not be an output
+     * operand of any operation.
+     *
+     * An operand can't be both input and output of a model.
+     */
+    MODEL_INPUT,
+
+    /**
+     * The operand is an output of the model. It must be an output
+     * operand of exactly one operation.
+     *
+     * An operand can't be both input and output of a model.
+     */
+    MODEL_OUTPUT,
+
+    /**
+     * The operand is a constant found in Model.operandValues. It must
+     * not be an output operand of any operation.
+     */
+    CONSTANT_COPY,
+
+    /**
+     * The operand is a constant that was specified via a Memory
+     * object. It must not be an output operand of any operation.
+     */
+    CONSTANT_REFERENCE,
+
+    /**
+     * The operand does not have a value. This is valid only for optional
+     * arguments of operations.
+     */
+    NO_VALUE,
+};
+
+/**
+ * Status of a device.
+ */
+enum DeviceStatus : int32_t {
+    AVAILABLE,
+    BUSY,
+    OFFLINE,
+    UNKNOWN,
+};
+
+/**
+ * Performance information for the reference workload.
+ *
+ * Used by a driver to report its performance characteristics.
+ */
+struct PerformanceInfo {
+    /**
+     * Ratio of the time taken by the driver to execute the
+     * workload compared to the time the CPU would take for the
+     * same workload. A lower number is better.
+     */
+    float execTime;
+
+    /**
+     * Ratio of the energy used by the driver compared to what
+     * the CPU would use for doing the same workload. A lower number
+     * is better.
+     */
+    float powerUsage;
+};
+
+/**
+ * The capabilities of a driver.
+ */
+struct Capabilities {
+    /**
+     * Driver performance when operating on float32 data.
+     */
+    PerformanceInfo float32Performance;
+
+    /**
+     * Driver performance when operating on asymmetric 8-bit quantized data.
+     */
+    PerformanceInfo quantized8Performance;
+};
+
+/**
+ * Describes the location of a data object.
+ */
+struct DataLocation {
+    /**
+     * The index of the memory pool where this location is found.
+     */
+    uint32_t poolIndex;
+
+    /**
+     * Offset in bytes from the start of the pool.
+     */
+    uint32_t offset;
+
+    /**
+     * The length of the data in bytes.
+     */
+    uint32_t length;
+};
+
+/**
+ * Describes one operand of the model's graph.
+ */
+struct Operand {
+    /**
+     * Data type of the operand.
+     */
+    OperandType type;
+
+    /**
+     * Dimensions of the operand.
+     *
+     * For a scalar operand, dimensions.size() must be 0.
+     *
+     * For a tensor operand, dimensions.size() must be at least 1;
+     * however, any of the dimensions may be unspecified.
+     *
+     * A tensor operand with all dimensions specified has "fully
+     * specified" dimensions. Whenever possible (i.e., whenever the
+     * dimensions are known at model construction time), a tensor
+     * operand should have (but is not required to have) fully
+     * specified dimensions, in order to enable the best possible
+     * performance.
+     *
+     * If a tensor operand's dimensions are not fully specified, the
+     * dimensions of the operand are deduced from the operand
+     * dimensions and values of the operation for which that operand
+     * is an output.
+     *
+     * In the following situations, a tensor operand's dimensions must
+     * be fully specified:
+     *
+     *     . The operand has lifetime CONSTANT_COPY or
+     *       CONSTANT_REFERENCE.
+     *
+     *     . The operand has lifetime MODEL_INPUT or MODEL_OUTPUT. Fully
+     *       specified dimensions must either be present in the
+     *       Operand or they must be provided in the corresponding
+     *       RequestArgument.
+     *       EXCEPTION: If the input or output is optional and omitted
+     *       (by setting the hasNoValue field of the corresponding
+     *       RequestArgument to true) then it need not have fully
+     *       specified dimensions.
+     *
+     * A tensor operand with some number of unspecified dimensions is
+     * represented by setting each unspecified dimension to 0.
+     */
+    vec<uint32_t> dimensions;
+
+    /**
+     * The number of times this operand appears as an operation input.
+     *
+     * (For example, if this operand appears once in one operation's
+     * input list, and three times in another operation's input list,
+     * then numberOfConsumers = 4.)
+     */
+    uint32_t numberOfConsumers;
+
+    /**
+     * Quantized scale of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or
+     * TENSOR_INT32.
+     */
+    float scale;
+
+    /**
+     * Quantized zero-point offset of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM.
+     */
+    int32_t zeroPoint;
+
+    /**
+     * How the operand is used.
+     */
+    OperandLifeTime lifetime;
+
+    /**
+     * Where to find the data for this operand.
+     * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
+     * NO_VALUE:
+     * - All the fields must be 0.
+     * If the lifetime is CONSTANT_COPY:
+     * - location.poolIndex is 0.
+     * - location.offset is the offset in bytes into Model.operandValues.
+     * - location.length is set.
+     * If the lifetime is CONSTANT_REFERENCE:
+     * - location.poolIndex is set.
+     * - location.offset is the offset in bytes into the specified pool.
+     * - location.length is set.
+     */
+    DataLocation location;
+};
+
+/**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+    /**
+     * The operation type.
+     */
+    OperationType type;
+
+    /**
+     * Describes the table that contains the indexes of the inputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> inputs;
+
+    /**
+     * Describes the table that contains the indexes of the outputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> outputs;
+};
+
+/**
+ * A Neural Network Model.
+ *
+ * This includes not only the execution graph, but also constant data such as
+ * weights or scalars added at construction time. The only information that
+ * might not be known is the shape of the input tensors.
+ */
+struct Model {
+    /**
+     * All operands included in the model.
+     */
+    vec<Operand> operands;
+
+    /**
+     * All operations included in the model.
+     *
+     * The operations are sorted into execution order. Every operand
+     * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
+     * written before it is read.
+     */
+    vec<Operation> operations;
+
+    /**
+     * Input indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> inputIndexes;
+
+    /**
+     * Output indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> outputIndexes;
+
+    /**
+     * A byte buffer containing operand data that were copied into the model.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_COPY.
+     */
+    vec<uint8_t> operandValues;
+
+    /**
+     * A collection of shared memory pools containing operand values.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_REFERENCE.
+     */
+    vec<memory> pools;
+};
+
+/**
+ * Metadata information specifying the location of the input or output data and
+ * any updates to the input or output operand.
+ */
+struct RequestArgument {
+    /**
+     * If true, the argument does not have a value. This can be used for
+     * operations that take optional arguments. If true, the fields of location
+     * are set to 0 and the dimensions vector is left empty.
+     */
+    bool hasNoValue;
+
+    /**
+     * The location within one of the memory pools passed in the Request.
+     */
+    DataLocation location;
+
+    /**
+     * Updated dimension information.
+     *
+     * If dimensions.size() > 0, dimension information was provided
+     * along with the argument. This can be the case for models that
+     * accept inputs of varying size. This can't change the rank, just
+     * the value of the dimensions that were unspecified in the
+     * model. If dimensions.size() > 0, then all dimensions must be
+     * specified here; and any dimension that was specified in the
+     * model must have the same value here.
+     *
+     * If the dimensions in the model are not fully specified, then
+     * they must be fully specified here, unless hasNoValue is set to
+     * true. If the dimensions in the model are fully specified, then
+     * either dimensions.size() may be 0, or the dimensions in the
+     * model must be identical to the dimensions here.
+     */
+    vec<uint32_t> dimensions;
+};
+
+/**
+ * Inputs to be sent to and outputs to be retrieved from a prepared model.
+ *
+ * A Request serves two primary tasks:
+ * 1) Provides the input and output data to be used when executing the model.
+ * 2) Specifies any updates to the input operand metadata that were left
+ *    unspecified at model preparation time.
+ *
+ * An output must not overlap with any other output, with an input, or
+ * with an operand of lifetime CONSTANT_REFERENCE.
+ */
+struct Request {
+    /**
+     * Input data and information to be used in the execution of a prepared
+     * model.
+     *
+     * The index of the input corresponds to the index in Model.inputIndexes.
+     *   E.g., input[i] corresponds to Model.inputIndexes[i].
+     */
+    vec<RequestArgument> inputs;
+
+    /**
+     * Output data and information to be used in the execution of a prepared
+     * model.
+     *
+     * The index of the output corresponds to the index in Model.outputIndexes.
+     *   E.g., output[i] corresponds to Model.outputIndexes[i].
+     */
+    vec<RequestArgument> outputs;
+
+    /**
+     * A collection of shared memory pools containing operand data for both the
+     * inputs and the outputs to a model.
+     */
+    vec<memory> pools;
+};
+
+/**
+ * Return status of a function.
+ */
+enum ErrorStatus : int32_t {
+    NONE,
+    DEVICE_UNAVAILABLE,
+    GENERAL_FAILURE,
+    OUTPUT_INSUFFICIENT_SIZE,
+    INVALID_ARGUMENT,
+};
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 9057695..ba9fb45 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -15,91 +15,61 @@
 //
 
 cc_library_static {
-    name: "VtsHalNeuralnetworksTest_utils",
+    name: "VtsHalNeuralNetworksV1_0_utils",
     srcs: [
         "Callbacks.cpp",
-        "GeneratedTestHarness.cpp",
+        "Utils.cpp",
     ],
     defaults: ["VtsHalTargetTestDefaults"],
-    export_include_dirs: ["."],
+    export_include_dirs: ["include"],
     shared_libs: [
         "libfmq",
         "libnativewindow",
     ],
     static_libs: [
         "android.hardware.neuralnetworks@1.0",
-        "android.hardware.neuralnetworks@1.1",
-        "android.hardware.neuralnetworks@1.2",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libgmock",
         "libhidlmemory",
+        "libneuralnetworks_generated_test_harness",
         "libneuralnetworks_utils",
     ],
     header_libs: [
         "libneuralnetworks_headers",
-        "libneuralnetworks_generated_test_harness_headers",
-        "libneuralnetworks_generated_tests",
     ],
 }
 
-cc_defaults {
-    name: "VtsHalNeuralNetworksTargetTestDefaults",
-    defaults: ["VtsHalTargetTestDefaults"],
-    srcs: [
-        "ValidateModel.cpp",
-        "ValidateRequest.cpp",
-        "VtsHalNeuralnetworks.cpp",
-    ],
-    shared_libs: [
-        "libfmq",
-        "libnativewindow",
-    ],
-    static_libs: [
-        "android.hardware.neuralnetworks@1.0",
-        "android.hardware.neuralnetworks@1.1",
-        "android.hardware.neuralnetworks@1.2",
-        "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
-        "libgmock",
-        "libhidlmemory",
-        "libneuralnetworks_utils",
-        "VtsHalNeuralnetworksTest_utils",
-    ],
-    header_libs: [
-        "libneuralnetworks_headers",
-        "libneuralnetworks_generated_test_harness_headers",
-        "libneuralnetworks_generated_tests",
-    ],
-    // Bug: http://b/74200014 - Disable arm32 asan since it triggers internal
-    // error in ld.gold.
-    arch: {
-        arm: {
-            sanitize: {
-                never: true,
-            },
-        },
-    },
-    test_suites: ["general-tests"],
-}
-
 cc_test {
     name: "VtsHalNeuralnetworksV1_0TargetTest",
-    defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+    defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "BasicTests.cpp",
-        "GeneratedTests.cpp",
+        "TestAssertions.cpp",
+        "ValidateModel.cpp",
+        "ValidateRequest.cpp",
+        "VtsHalNeuralnetworks.cpp",
+        "GeneratedTestHarness.cpp",
     ],
-}
-
-cc_test {
-    name: "PresubmitHalNeuralnetworksV1_0TargetTest",
-    defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
-    srcs: [
-        "BasicTests.cpp",
-        "GeneratedTests.cpp",
+    shared_libs: [
+        "libfmq",
+        "libnativewindow",
     ],
-    cflags: [
-        "-DPRESUBMIT_NOT_VTS",
+    static_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libgmock",
+        "libhidlmemory",
+        "libneuralnetworks_generated_test_harness",
+        "libneuralnetworks_utils",
+        "VtsHalNeuralNetworksV1_0_utils",
     ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+    ],
+    header_libs: [
+        "libneuralnetworks_headers",
+    ],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/neuralnetworks/1.0/vts/functional/BasicTests.cpp b/neuralnetworks/1.0/vts/functional/BasicTests.cpp
index 945c406..cc44c9e 100644
--- a/neuralnetworks/1.0/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.0/vts/functional/BasicTests.cpp
@@ -18,39 +18,29 @@
 
 #include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
 // create device test
-TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
+TEST_P(NeuralnetworksHidlTest, CreateDevice) {}
 
 // status test
-TEST_F(NeuralnetworksHidlTest, StatusTest) {
-    Return<DeviceStatus> status = device->getStatus();
+TEST_P(NeuralnetworksHidlTest, StatusTest) {
+    Return<DeviceStatus> status = kDevice->getStatus();
     ASSERT_TRUE(status.isOk());
     EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
 }
 
 // initialization
-TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) {
     Return<void> ret =
-        device->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) {
-            EXPECT_EQ(ErrorStatus::NONE, status);
-            EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
-            EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
-            EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
-            EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
-        });
+            kDevice->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) {
+                EXPECT_EQ(ErrorStatus::NONE, status);
+                EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
+                EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
+                EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
+                EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
+            });
     EXPECT_TRUE(ret.isOk());
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_0
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.cpp b/neuralnetworks/1.0/vts/functional/Callbacks.cpp
index c30702c..37afcf0 100644
--- a/neuralnetworks/1.0/vts/functional/Callbacks.cpp
+++ b/neuralnetworks/1.0/vts/functional/Callbacks.cpp
@@ -14,160 +14,78 @@
  * limitations under the License.
  */
 
-#include "Callbacks.h"
+#define LOG_TAG "Callbacks"
+
+#include "1.0/Callbacks.h"
+
 #include <android-base/logging.h>
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace implementation {
+namespace android::hardware::neuralnetworks::V1_0::implementation {
 
-CallbackBase::CallbackBase() : mNotified(false) {}
-
-CallbackBase::~CallbackBase() {
-    // Note that we cannot call CallbackBase::join_thread from here:
-    // CallbackBase is intended to be reference counted, and it is possible that
-    // the reference count drops to zero in the bound thread, causing the
-    // bound thread to call this destructor. If a thread tries to join
-    // itself, it throws an exception, producing a message like the
-    // following:
-    //
-    //     terminating with uncaught exception of type std::__1::system_error:
-    //     thread::join failed: Resource deadlock would occur
-}
-
-void CallbackBase::wait() {
-    std::unique_lock<std::mutex> lock(mMutex);
-    mCondition.wait(lock, [this]{return mNotified;});
-    join_thread_locked();
-}
-
-bool CallbackBase::on_finish(std::function<bool(void)> post_work) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (mPostWork != nullptr) {
-        LOG(ERROR) << "CallbackBase::on_finish -- a post-work function has already been bound to "
-                   "this callback object";
-        return false;
-    }
-    if (post_work == nullptr) {
-        LOG(ERROR) << "CallbackBase::on_finish -- the new post-work function is invalid";
-        return false;
-    }
-    mPostWork = std::move(post_work);
-    return true;
-}
-
-bool CallbackBase::bind_thread(std::thread&& asyncThread) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (mThread.joinable()) {
-        LOG(ERROR) << "CallbackBase::bind_thread -- a thread has already been bound to this "
-                   "callback object";
-        return false;
-    }
-    if (!asyncThread.joinable()) {
-        LOG(ERROR) << "CallbackBase::bind_thread -- the new thread is not joinable";
-        return false;
-    }
-    mThread = std::move(asyncThread);
-    return true;
-}
-
-void CallbackBase::join_thread() {
-    std::lock_guard<std::mutex> lock(mMutex);
-    join_thread_locked();
-}
-
-void CallbackBase::notify() {
-    {
-        std::lock_guard<std::mutex> lock(mMutex);
-        mNotified = true;
-        if (mPostWork != nullptr) {
-            bool success = mPostWork();
-            if (!success) {
-                LOG(ERROR) << "CallbackBase::notify -- post work failed";
-            }
-        }
-    }
-    mCondition.notify_all();
-}
-
-void CallbackBase::join_thread_locked() {
-    if (mThread.joinable()) {
-        mThread.join();
-    }
-}
-
-PreparedModelCallback::PreparedModelCallback() :
-        mErrorStatus(ErrorStatus::GENERAL_FAILURE), mPreparedModel(nullptr) {}
-
-PreparedModelCallback::~PreparedModelCallback() {}
+// PreparedModelCallback methods begin here
 
 Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
-                                           const sp<V1_0::IPreparedModel>& preparedModel) {
-    mErrorStatus = errorStatus;
-    mPreparedModel = preparedModel;
-    CallbackBase::notify();
+                                           const sp<IPreparedModel>& preparedModel) {
+    {
+        std::lock_guard<std::mutex> hold(mMutex);
+
+        // quick-return if object has already been notified
+        if (mNotified) {
+            return Void();
+        }
+
+        // store results and mark as notified
+        mErrorStatus = errorStatus;
+        mPreparedModel = preparedModel;
+        mNotified = true;
+    }
+
+    mCondition.notify_all();
     return Void();
 }
 
-Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus,
-                                               const sp<V1_2::IPreparedModel>& preparedModel) {
-    mErrorStatus = errorStatus;
-    mPreparedModel = preparedModel;
-    CallbackBase::notify();
-    return Void();
+void PreparedModelCallback::wait() const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    mCondition.wait(lock, [this] { return mNotified; });
 }
 
-ErrorStatus PreparedModelCallback::getStatus() {
+ErrorStatus PreparedModelCallback::getStatus() const {
     wait();
     return mErrorStatus;
 }
 
-sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() {
+sp<IPreparedModel> PreparedModelCallback::getPreparedModel() const {
     wait();
     return mPreparedModel;
 }
 
-ExecutionCallback::ExecutionCallback() : mErrorStatus(ErrorStatus::GENERAL_FAILURE) {}
-
-ExecutionCallback::~ExecutionCallback() {}
+// ExecutionCallback methods begin here
 
 Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) {
-    mErrorStatus = errorStatus;
-    mOutputShapes = {};
-    mTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
-    CallbackBase::notify();
+    {
+        std::lock_guard<std::mutex> hold(mMutex);
+
+        // quick-return if object has already been notified
+        if (mNotified) {
+            return Void();
+        }
+
+        mErrorStatus = errorStatus;
+        mNotified = true;
+    }
+    mCondition.notify_all();
+
     return Void();
 }
 
-Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus,
-                                           const hidl_vec<OutputShape>& outputShapes,
-                                           const Timing& timing) {
-    mErrorStatus = errorStatus;
-    mOutputShapes = outputShapes;
-    mTiming = timing;
-    CallbackBase::notify();
-    return Void();
+void ExecutionCallback::wait() const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    mCondition.wait(lock, [this] { return mNotified; });
 }
 
-ErrorStatus ExecutionCallback::getStatus() {
+ErrorStatus ExecutionCallback::getStatus() const {
     wait();
     return mErrorStatus;
 }
 
-const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() {
-    wait();
-    return mOutputShapes;
-}
-
-Timing ExecutionCallback::getTiming() {
-    wait();
-    return mTiming;
-}
-
-}  // namespace implementation
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_0::implementation
diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.h b/neuralnetworks/1.0/vts/functional/Callbacks.h
deleted file mode 100644
index 4707d0a..0000000
--- a/neuralnetworks/1.0/vts/functional/Callbacks.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
-#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
-
-#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
-#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <chrono>
-#include <condition_variable>
-#include <functional>
-#include <mutex>
-#include <thread>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace implementation {
-
-using V1_0::ErrorStatus;
-
-/**
- * The CallbackBase class is used internally by the NeuralNetworks runtime to
- * synchronize between different threads. An asynchronous task is launched
- * paired with a callback object. When a client thread requires the output being
- * generated by the asynchronous task, the client thread can wait for the result
- * and be blocked until it has completed or a timeout condition has been
- * reached. Any wait* may safely be called concurrently, even on the same
- * callback object. When the asynchronous task has finished its workload, it
- * must immediately call "notify". If the asynchronous task has failed to launch,
- * the function that tried to launch the asynchronous task must immediately call
- * "notify". This "notify" call awakens any client threads waiting on the
- * callback object.
- *
- * The CallbackBase class implements some of the base synchronization common to
- * both PrepareModelCallback and ExecutionCallback. For consistency, any HIDL
- * callback class must inherit from CallbackBase as well as the HIDL callback
- * interface it implements.
- *
- * This class exists to enable synchronization across HIDL. When synchronization
- * is only required in the same process, consider using std::future, std::mutex,
- * std::condition_variable, or std::experimental::latch instead.
- */
-class CallbackBase {
- public:
-    CallbackBase();
-    ~CallbackBase();
-
-    /**
-     * CallbackBase::wait blocks until notify has been called on the callback
-     * object.
-     */
-    void wait();
-
-    /**
-     * CallbackBase::wait_for blocks until notify has been called on the
-     * callback object or the time duration from the time the wait_for function
-     * was called has expired, whichever comes first.
-     *
-     * @return Status std::cv_status::no_timeout if the callback was notified
-     *                before the time duration expired, std::cv_status::timeout
-     *                otherwise.
-     */
-    template<class Rep, class Period>
-    std::cv_status wait_for(const std::chrono::duration<Rep,Period>& timeout_duration);
-
-    /**
-     * CallbackBase::on_finish binds a function to the callback object. This
-     * bound function will be executed when CallbackBase::notify is called,
-     * before any calls to wait* return. (Note that CallbackBase::wait_for can
-     * return std::cv_status::timeout before CallbackBase::notify is called for
-     * the first time, and hence before the bound function is executed.)
-     *
-     * The bound function must not synchronize with or otherwise access the
-     * callback object it is bound to, as this could cause a deadlock.
-     *
-     * CallbackBase::on_finish can be called at most once on a given callback
-     * object, and the call to CallbackBase::on_finish must finish before
-     * CallbackBase::notify is called.
-     *
-     * @param post_work Function to be invoked the first time
-     *                  CallbackBase::notify is called. Must have a target --
-     *                  i.e., must not compare equal to nullptr. post_work
-     *                  returns true if it successfully completes, false if it
-     *                  fails.
-     * @return bool True if the function was successfully bound, false if
-     *              unsuccessful.
-     *
-     * TODO: Why does the return value of the callback matter?
-     */
-    bool on_finish(std::function<bool(void)> post_work);
-
-    /**
-     * CallbackBase::bind_thread binds a thread to the event for later use by
-     * CallbackBase::join_thread.
-     *
-     * The thread must be passed using std::move.
-     *
-     * Once a thread is bound with CallbackBase::bind_thread, the client code
-     * should ensure that one of the following occurs before the event is
-     * destroyed:
-     * - CallbackBase::join_thread has been called.
-     * - CallbackBase::wait has been called.
-     * - CallbackBase::wait_for has been called and returned other than
-     *   std::cv_status::no_timeout.
-     *
-     * The bound thread shall not call any CallbackBase method with the
-     * exception of CallbackBase::notify, which it must call when the thread has
-     * finished its computation.
-     *
-     * CallbackBase::bind_thread can be called at most once on a given callback
-     * object.
-     *
-     * @param asyncThread Thread to be bound to the callback object. The thread
-     *                    object must represent a thread of execution -- i.e.,
-     *                    asyncThread.joinable() must be true.
-     * @return bool True if successful, false if thread was not properly bound.
-     */
-    bool bind_thread(std::thread&& asyncThread);
-
-    /**
-     * CallbackBase::join_thread ensures that the thread (if any) bound to this
-     * event with CallbackBase::bind_thread has fully finished and cleaned its
-     * resources. It is legal to call this function multiple times, concurrently
-     * or sequentially.
-     */
-    void join_thread();
-
- protected:
-    /**
-     * CallbackBase::notify enables all prior and future wait* calls on the
-     * callback object to proceed. The call to CallbackBase::notify happens
-     * before any wait* calls on this callback object return (except in the case
-     * of wait_for timing out). The asynchronous call the callback object is
-     * paired with must ensure that any update to state that should be visible
-     * to the caller of wait* happens before the call to CallbackBase::notify.
-     *
-     * CallbackBase::notify must be called exactly once on a given callback
-     * object.
-     */
-    void notify();
-
- private:
-    // Same as CallbackBase::join_thread but assumes we already hold a lock on
-    // mMutex.
-    void join_thread_locked();
-
-    bool                      mNotified;
-    std::mutex                mMutex;
-    std::condition_variable   mCondition;
-    std::function<bool(void)> mPostWork;
-    std::thread               mThread;
-};
-
-/**
- * The PreparedModelCallback class is used to receive the error status of
- * preparing a model as well as the prepared model from a task executing
- * asynchronously with respect to the runtime. If a calling thread calls wait*
- * or get* on a PreparedModelCallback object and the corresponding asynchronous
- * task has not finished preparing the model, the calling thread will block
- * until the asynchronous task has either called notify or notify_1_2. For more
- * information on the synchronization behavior, refer to the CallbackBase class.
- *
- * This class inherits the basic blocking and signaling calls from
- * CallbackBase, and implements the HIDL notify and notify_1_2 calls from
- * IPreparedModelCallback. This callback object is passed as an argument to
- * IDevice::prepareModel.
- */
-class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback {
- public:
-    PreparedModelCallback();
-    ~PreparedModelCallback() override;
-
-    /**
-     * IPreparedModelCallback::notify and IPreparedModelCallback::notify_1_2
-     * mark the callback object with the return status of the asynchronous
-     * model preparation along with the prepared model, and call
-     * CallbackBase::notify, enabling all prior and future wait* calls on the
-     * PreparedModelCallback object to proceed. For more information on the
-     * synchronization behavior, refer to the CallbackBase class.
-     *
-     * Either IPreparedModelCallback::notify or IPreparedModelCallback::notify_1_2
-     * must be called exactly once on a given PreparedModelCallback object.
-     *
-     * @param status Error status returned from asynchronously preparing the
-     *               model; will be:
-     *               - NONE if the asynchronous preparation was successful
-     *               - DEVICE_UNAVAILABLE if driver is offline or busy
-     *               - GENERAL_FAILURE if there is an unspecified error
-     *               - INVALID_ARGUMENT if the input model is invalid
-     * @param preparedModel Returned model that has been prepared for execution,
-     *                      nullptr if the model was unable to be prepared.
-     */
-    Return<void> notify(ErrorStatus status, const sp<V1_0::IPreparedModel>& preparedModel) override;
-    Return<void> notify_1_2(ErrorStatus status,
-                            const sp<V1_2::IPreparedModel>& preparedModel) override;
-
-    /**
-     * Retrieves the error status returned from the asynchronous task launched
-     * by IDevice::prepareModel. If IDevice::prepareModel has not finished
-     * asynchronously preparing the model, this call will block until the
-     * asynchronous task notifies the object.
-     *
-     * @return status Error status returned from asynchronously preparing the
-     *                model; will be:
-     *                - NONE if the asynchronous preparation was successful
-     *                - DEVICE_UNAVAILABLE if driver is offline or busy
-     *                - GENERAL_FAILURE if there is an unspecified error
-     *                - INVALID_ARGUMENT if the input model is invalid
-     */
-    ErrorStatus getStatus();
-
-    /**
-     * Retrieves the model that has been prepared for execution from the
-     * asynchronous task launched by IDevice::prepareModel. If
-     * IDevice::prepareModel has not finished asynchronously preparing the
-     * model, this call will block until the asynchronous task notifies the
-     * object.
-     *
-     * @return preparedModel Returned model that has been prepared for
-     *                       execution, nullptr if the model was unable to be
-     *                       prepared.
-     */
-    sp<V1_0::IPreparedModel> getPreparedModel();
-
-   private:
-    ErrorStatus        mErrorStatus;
-    sp<V1_0::IPreparedModel> mPreparedModel;
-};
-
-/**
- * The ExecutionCallback class is used to receive the error status of the
- * execution from a task executing asynchronously with respect to the runtime.
- * If a calling thread calls wait* or get* on a PreparedModelCallback object and
- * the corresponding asynchronous task has not finished the execution, the
- * calling thread will block until the asynchronous task has either called notify
- * or notify_1_2. For more information on the synchronization behavior, refer to
- * the CallbackBase class.
- *
- * This class inherits the basic blocking and signaling calls from
- * CallbackBase, and implements the HIDL notify and notify_1_2 calls from
- * IExecutionCallback. This callback object is passed as an argument to
- * IPreparedModel::execute.
- */
-class ExecutionCallback : public CallbackBase,  public IExecutionCallback {
- public:
-    ExecutionCallback();
-    ~ExecutionCallback() override;
-
-    /**
-     * IExecutionCallback::notify and IExecutionCallback::notify_1_2 mark the
-     * callback object with the return status of the asynchronous execution that
-     * held this callback and enable all prior and future wait* calls on the
-     * ExecutionCallback object to proceed. For more information on the
-     * synchronization behavior, refer to the CallbackBase class.
-     *
-     * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
-     * be called exactly once on a given ExecutionCallback object.
-     *
-     * @param status Error status returned from launching the asynchronous task
-     *               (if the launch fails) or from the asynchronous task itself
-     *               (if the launch succeeds). Must be:
-     *               - NONE if the asynchronous execution was successful
-     *               - DEVICE_UNAVAILABLE if driver is offline or busy
-     *               - GENERAL_FAILURE if there is an unspecified error
-     *               - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
-     *                 not large enough to store the resultant values
-     *               - INVALID_ARGUMENT if the input request is invalid
-     */
-    Return<void> notify(ErrorStatus status) override;
-
-    /**
-     * Similar to IExecutionCallback::notify, but for V1_2::IPreparedModel to
-     * also notify output shapes along with error status.
-     *
-     * @param status Error status returned from launching the asynchronous task
-     *               (if the launch fails) or from the asynchronous task itself
-     *               (if the launch succeeds). Must be:
-     *               - NONE if the asynchronous execution was successful
-     *               - DEVICE_UNAVAILABLE if driver is offline or busy
-     *               - GENERAL_FAILURE if the asynchronous task resulted in an
-     *                 unspecified error
-     *               - OUTPUT_INSUFFICIENT_SIZE if at least one output
-     *                 operand buffer is not large enough to store the
-     *                 corresponding output
-     *               - INVALID_ARGUMENT if one of the input arguments to
-     *                 prepareModel is invalid
-     * @param outputShapes A list of shape information of model output operands.
-     *                     The index into "outputShapes" corresponds to the index
-     *                     of the output operand in the Request outputs vector.
-     *                     outputShapes must be empty unless the status is either
-     *                     NONE or OUTPUT_INSUFFICIENT_SIZE.
-     * @return Timing Duration of execution. Unless MeasureTiming::YES was passed when
-     *                launching the execution and status is NONE, all times must
-     *                be reported as UINT64_MAX. A driver may choose to report
-     *                any time as UINT64_MAX, indicating that particular measurement is
-     *                not available.
-     */
-    Return<void> notify_1_2(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
-                            const Timing& timing) override;
-
-    // An overload of the latest notify interface to hide the version from ExecutionBuilder.
-    Return<void> notify(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
-                        const Timing& timing) {
-        return notify_1_2(status, outputShapes, timing);
-    }
-
-    /**
-     * Retrieves the error status returned from the asynchronous task launched
-     * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If
-     * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished
-     * asynchronously executing, this call will block until the asynchronous task
-     * notifies the object.
-     *
-     * @return status Error status returned from launching the asynchronous task
-     *                (if the launch fails) or from the asynchronous task itself
-     *                (if the launch succeeds). Must be:
-     *                - NONE if the asynchronous execution was successful
-     *                - DEVICE_UNAVAILABLE if driver is offline or busy
-     *                - GENERAL_FAILURE if the asynchronous task resulted in an
-     *                  unspecified error
-     *                - OUTPUT_INSUFFICIENT_SIZE if at least one output
-     *                  operand buffer is not large enough to store the
-     *                  corresponding output
-     *                - INVALID_ARGUMENT if one of the input arguments to
-     *                  prepareModel is invalid
-     */
-    ErrorStatus getStatus();
-
-    /**
-     * Retrieves the output shapes returned from the asynchronous task launched
-     * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished
-     * asynchronously executing, this call will block until the asynchronous task
-     * notifies the object.
-     *
-     * If the asynchronous task was launched by IPreparedModel::execute, an empty vector
-     * will be returned.
-     *
-     * @return outputShapes A list of shape information of model output operands.
-     *                      The index into "outputShapes" corresponds to the index
-     *                      of the output operand in the Request outputs vector.
-     *                      outputShapes must be empty unless the status is either
-     *                      NONE or OUTPUT_INSUFFICIENT_SIZE.
-     */
-    const std::vector<OutputShape>& getOutputShapes();
-
-    /**
-     * Retrieves the duration of execution ofthe asynchronous task launched
-     * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished
-     * asynchronously executing, this call will block until the asynchronous task
-     * notifies the object.
-     *
-     * If the asynchronous task was launched by IPreparedModel::execute, every time
-     * must be UINT64_MAX.
-     *
-     * @return timing Duration of the execution. Every time must be UINT64_MAX unless
-     *                the status is NONE.
-     */
-    Timing getTiming();
-
-   private:
-    ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
-    std::vector<OutputShape> mOutputShapes = {};
-    Timing mTiming = {};
-};
-
-
-// template function implementation(s) below this point
-
-template<class Rep, class Period>
-std::cv_status CallbackBase::wait_for(const std::chrono::duration<Rep,Period>& timeout_duration) {
-    std::unique_lock<std::mutex> lock(mMutex);
-    std::cv_status status = mCondition.wait_for(lock, timeout_duration, [this]{return mNotified;});
-    if (status != std::cv_status::timeout) {
-        join_thread_locked();
-    }
-    return status;
-}
-
-}  // namespace implementation
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index c819b52..595ad85 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -15,572 +15,161 @@
  */
 
 #include "GeneratedTestHarness.h"
-#include "Callbacks.h"
-#include "ExecutionBurstController.h"
+
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "MemoryUtils.h"
 #include "TestHarness.h"
-#include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
 
 #include <android-base/logging.h>
 #include <android/hardware/neuralnetworks/1.0/IDevice.h>
-#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
 #include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
 #include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hardware/neuralnetworks/1.1/IDevice.h>
-#include <android/hardware/neuralnetworks/1.2/IDevice.h>
-#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
-#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMemory.h>
 #include <hidlmemory/mapping.h>
+
+#include <gtest/gtest.h>
 #include <iostream>
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-namespace generated_tests {
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::test_helper::bool8;
-using ::test_helper::compare;
-using ::test_helper::expectMultinomialDistributionWithinTolerance;
-using ::test_helper::filter;
-using ::test_helper::for_all;
-using ::test_helper::for_each;
-using ::test_helper::MixedTyped;
-using ::test_helper::MixedTypedExample;
-using ::test_helper::resize_accordingly;
-using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+using namespace test_helper;
+using hidl::memory::V1_0::IMemory;
+using implementation::ExecutionCallback;
+using implementation::PreparedModelCallback;
 
-template <typename T>
-void copy_back_(std::map<int, std::vector<T>>* dst, const std::vector<RequestArgument>& ra,
-                char* src) {
-    for_each<T>(*dst, [&ra, src](int index, std::vector<T>& m) {
-        ASSERT_EQ(m.size(), ra[index].location.length / sizeof(T));
-        char* begin = src + ra[index].location.offset;
-        memcpy(m.data(), begin, ra[index].location.length);
-    });
-}
+Model createModel(const TestModel& testModel) {
+    // Model operands.
+    hidl_vec<Operand> operands(testModel.operands.size());
+    size_t constCopySize = 0, constRefSize = 0;
+    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+        const auto& op = testModel.operands[i];
 
-void copy_back(MixedTyped* dst, const std::vector<RequestArgument>& ra, char* src) {
-    copy_back_(&dst->float32Operands, ra, src);
-    copy_back_(&dst->int32Operands, ra, src);
-    copy_back_(&dst->quant8AsymmOperands, ra, src);
-    copy_back_(&dst->quant16SymmOperands, ra, src);
-    copy_back_(&dst->float16Operands, ra, src);
-    copy_back_(&dst->bool8Operands, ra, src);
-    copy_back_(&dst->quant8ChannelOperands, ra, src);
-    copy_back_(&dst->quant16AsymmOperands, ra, src);
-    copy_back_(&dst->quant8SymmOperands, ra, src);
-    static_assert(9 == MixedTyped::kNumTypes,
-                  "Number of types in MixedTyped changed, but copy_back function wasn't updated");
-}
+        DataLocation loc = {};
+        if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+            loc = {.poolIndex = 0,
+                   .offset = static_cast<uint32_t>(constCopySize),
+                   .length = static_cast<uint32_t>(op.data.size())};
+            constCopySize += op.data.alignedSize();
+        } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+            loc = {.poolIndex = 0,
+                   .offset = static_cast<uint32_t>(constRefSize),
+                   .length = static_cast<uint32_t>(op.data.size())};
+            constRefSize += op.data.alignedSize();
+        }
 
-static bool isZeroSized(const MixedTyped& example, uint32_t index) {
-    for (auto i : example.operandDimensions.at(index)) {
-        if (i == 0) return true;
+        operands[i] = {.type = static_cast<OperandType>(op.type),
+                       .dimensions = op.dimensions,
+                       .numberOfConsumers = op.numberOfConsumers,
+                       .scale = op.scale,
+                       .zeroPoint = op.zeroPoint,
+                       .lifetime = static_cast<OperandLifeTime>(op.lifetime),
+                       .location = loc};
     }
-    return false;
+
+    // Model operations.
+    hidl_vec<Operation> operations(testModel.operations.size());
+    std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
+                   [](const TestOperation& op) -> Operation {
+                       return {.type = static_cast<OperationType>(op.type),
+                               .inputs = op.inputs,
+                               .outputs = op.outputs};
+                   });
+
+    // Constant copies.
+    hidl_vec<uint8_t> operandValues(constCopySize);
+    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+        const auto& op = testModel.operands[i];
+        if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+            const uint8_t* begin = op.data.get<uint8_t>();
+            const uint8_t* end = begin + op.data.size();
+            std::copy(begin, end, operandValues.data() + operands[i].location.offset);
+        }
+    }
+
+    // Shared memory.
+    hidl_vec<hidl_memory> pools;
+    if (constRefSize > 0) {
+        hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize));
+        CHECK_NE(pools[0].size(), 0u);
+
+        // load data
+        sp<IMemory> mappedMemory = mapMemory(pools[0]);
+        CHECK(mappedMemory.get() != nullptr);
+        uint8_t* mappedPtr =
+                reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
+        CHECK(mappedPtr != nullptr);
+
+        for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+            const auto& op = testModel.operands[i];
+            if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+                const uint8_t* begin = op.data.get<uint8_t>();
+                const uint8_t* end = begin + op.data.size();
+                std::copy(begin, end, mappedPtr + operands[i].location.offset);
+            }
+        }
+    }
+
+    return {.operands = std::move(operands),
+            .operations = std::move(operations),
+            .inputIndexes = testModel.inputIndexes,
+            .outputIndexes = testModel.outputIndexes,
+            .operandValues = std::move(operandValues),
+            .pools = std::move(pools)};
 }
 
 // Top level driver for models and examples generated by test_generator.py
 // Test driver for those generated from ml/nn/runtime/test/spec
-static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>& preparedModel,
-                                                const Request& request, MeasureTiming,
-                                                sp<ExecutionCallback>& callback) {
-    return preparedModel->execute(request, callback);
-}
-static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
-                                                const Request& request, MeasureTiming measure,
-                                                sp<ExecutionCallback>& callback) {
-    return preparedModel->execute_1_2(request, measure, callback);
-}
-static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>&, const Request&,
-                                                MeasureTiming, hidl_vec<OutputShape>*, Timing*) {
-    ADD_FAILURE() << "asking for synchronous execution at V1_0";
-    return ErrorStatus::GENERAL_FAILURE;
-}
-static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
-                                                const Request& request, MeasureTiming measure,
-                                                hidl_vec<OutputShape>* outputShapes,
-                                                Timing* timing) {
-    ErrorStatus result;
-    Return<void> ret = preparedModel->executeSynchronously(
-            request, measure,
-            [&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
-                                            const Timing& time) {
-                result = error;
-                *outputShapes = shapes;
-                *timing = time;
-            });
-    if (!ret.isOk()) {
-        return ErrorStatus::GENERAL_FAILURE;
-    }
-    return result;
-}
-static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst(
-        const sp<V1_0::IPreparedModel>&) {
-    ADD_FAILURE() << "asking for burst execution at V1_0";
-    return nullptr;
-}
-static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst(
-        const sp<V1_2::IPreparedModel>& preparedModel) {
-    return ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
-}
-enum class Executor { ASYNC, SYNC, BURST };
-enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
-const float kDefaultAtol = 1e-5f;
-const float kDefaultRtol = 1e-5f;
-template <typename T_IPreparedModel>
-void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
-                           const std::vector<MixedTypedExample>& examples,
-                           bool hasRelaxedFloat32Model, float fpAtol, float fpRtol,
-                           Executor executor, MeasureTiming measure, OutputType outputType) {
-    const uint32_t INPUT = 0;
-    const uint32_t OUTPUT = 1;
+void Execute(const sp<IDevice>& device, const TestModel& testModel) {
+    const Model model = createModel(testModel);
+    const Request request = createRequest(testModel);
 
-    int example_no = 1;
-    for (auto& example : examples) {
-        SCOPED_TRACE(example_no++);
-        const MixedTyped& inputs = example.operands.first;
-        const MixedTyped& golden = example.operands.second;
+    // Create IPreparedModel.
+    sp<IPreparedModel> preparedModel;
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
 
-        const bool hasFloat16Inputs = !inputs.float16Operands.empty();
-        if (hasRelaxedFloat32Model || hasFloat16Inputs) {
-            // TODO: Adjust the error limit based on testing.
-            // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
-            fpAtol = 5.0f * 0.0009765625f;
-            // Set the relative tolerance to be 5ULP of the corresponding FP precision.
-            fpRtol = 5.0f * 0.0009765625f;
-        }
+    // Launch execution.
+    sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+    Return<ErrorStatus> executionLaunchStatus = preparedModel->execute(request, executionCallback);
+    ASSERT_TRUE(executionLaunchStatus.isOk());
+    EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
 
-        std::vector<RequestArgument> inputs_info, outputs_info;
-        uint32_t inputSize = 0, outputSize = 0;
-        // This function only partially specifies the metadata (vector of RequestArguments).
-        // The contents are copied over below.
-        for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
-            if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
-            RequestArgument arg = {
-                .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
-                .dimensions = {},
-            };
-            RequestArgument arg_empty = {
-                .hasNoValue = true,
-            };
-            inputs_info[index] = s ? arg : arg_empty;
-            inputSize += s;
-        });
-        // Compute offset for inputs 1 and so on
-        {
-            size_t offset = 0;
-            for (auto& i : inputs_info) {
-                if (!i.hasNoValue) i.location.offset = offset;
-                offset += i.location.length;
-            }
-        }
+    // Retrieve execution status.
+    executionCallback->wait();
+    ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
 
-        MixedTyped test;  // holding test results
+    // Retrieve execution results.
+    const std::vector<TestBuffer> outputs = getOutputBuffers(request);
 
-        // Go through all outputs, initialize RequestArgument descriptors
-        resize_accordingly(golden, test);
-        bool sizeLargerThanOne = true;
-        for_all(golden, [&golden, &outputs_info, &outputSize, &outputType, &sizeLargerThanOne](
-                                int index, auto, auto s) {
-            if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
-            if (index == 0) {
-                // On OutputType::INSUFFICIENT, set the output operand with index 0 with
-                // buffer size one byte less than needed.
-                if (outputType == OutputType::INSUFFICIENT) {
-                    if (s > 1 && !isZeroSized(golden, index)) {
-                        s -= 1;
-                    } else {
-                        sizeLargerThanOne = false;
-                    }
-                }
-            }
-            RequestArgument arg = {
-                .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
-                .dimensions = {},
-            };
-            outputs_info[index] = arg;
-            outputSize += s;
-        });
-        // If output0 does not have size larger than one byte,
-        // we can not provide an insufficient buffer
-        if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return;
-        // Compute offset for outputs 1 and so on
-        {
-            size_t offset = 0;
-            for (auto& i : outputs_info) {
-                i.location.offset = offset;
-                offset += i.location.length;
-            }
-        }
-        std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
-                                          nn::allocateSharedMemory(outputSize)};
-        ASSERT_NE(0ull, pools[INPUT].size());
-        ASSERT_NE(0ull, pools[OUTPUT].size());
-
-        // load data
-        sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
-        sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
-        ASSERT_NE(nullptr, inputMemory.get());
-        ASSERT_NE(nullptr, outputMemory.get());
-        char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
-        char* outputPtr = reinterpret_cast<char*>(static_cast<void*>(outputMemory->getPointer()));
-        ASSERT_NE(nullptr, inputPtr);
-        ASSERT_NE(nullptr, outputPtr);
-        inputMemory->update();
-        outputMemory->update();
-
-        // Go through all inputs, copy the values
-        for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
-            char* begin = (char*)p;
-            char* end = begin + s;
-            // TODO: handle more than one input
-            std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
-        });
-
-        inputMemory->commit();
-        outputMemory->commit();
-
-        const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools};
-
-        ErrorStatus executionStatus;
-        hidl_vec<OutputShape> outputShapes;
-        Timing timing;
-        switch (executor) {
-            case Executor::ASYNC: {
-                SCOPED_TRACE("asynchronous");
-
-                // launch execution
-                sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-                ASSERT_NE(nullptr, executionCallback.get());
-                Return<ErrorStatus> executionLaunchStatus =
-                        ExecutePreparedModel(preparedModel, request, measure, executionCallback);
-                ASSERT_TRUE(executionLaunchStatus.isOk());
-                EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
-
-                // retrieve execution status
-                executionCallback->wait();
-                executionStatus = executionCallback->getStatus();
-                outputShapes = executionCallback->getOutputShapes();
-                timing = executionCallback->getTiming();
-
-                break;
-            }
-            case Executor::SYNC: {
-                SCOPED_TRACE("synchronous");
-
-                // execute
-                Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
-                        preparedModel, request, measure, &outputShapes, &timing);
-                ASSERT_TRUE(executionReturnStatus.isOk());
-                executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
-
-                break;
-            }
-            case Executor::BURST: {
-                SCOPED_TRACE("burst");
-
-                // create burst
-                const std::shared_ptr<::android::nn::ExecutionBurstController> controller =
-                        CreateBurst(preparedModel);
-                ASSERT_NE(nullptr, controller.get());
-
-                // create memory keys
-                std::vector<intptr_t> keys(request.pools.size());
-                for (size_t i = 0; i < keys.size(); ++i) {
-                    keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
-                }
-
-                // execute burst
-                std::tie(executionStatus, outputShapes, timing) =
-                        controller->compute(request, measure, keys);
-
-                break;
-            }
-        }
-
-        if (outputType != OutputType::FULLY_SPECIFIED &&
-            executionStatus == ErrorStatus::GENERAL_FAILURE) {
-            LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
-                         "execute model that it does not support.";
-            std::cout << "[          ]   Early termination of test because vendor service cannot "
-                         "execute model that it does not support."
-                      << std::endl;
-            GTEST_SKIP();
-        }
-        if (measure == MeasureTiming::NO) {
-            EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
-            EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
-        } else {
-            if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) {
-                EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
-            }
-        }
-
-        switch (outputType) {
-            case OutputType::FULLY_SPECIFIED:
-                // If the model output operands are fully specified, outputShapes must be either
-                // either empty, or have the same number of elements as the number of outputs.
-                ASSERT_EQ(ErrorStatus::NONE, executionStatus);
-                ASSERT_TRUE(outputShapes.size() == 0 ||
-                            outputShapes.size() == test.operandDimensions.size());
-                break;
-            case OutputType::UNSPECIFIED:
-                // If the model output operands are not fully specified, outputShapes must have
-                // the same number of elements as the number of outputs.
-                ASSERT_EQ(ErrorStatus::NONE, executionStatus);
-                ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
-                break;
-            case OutputType::INSUFFICIENT:
-                ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
-                ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
-                ASSERT_FALSE(outputShapes[0].isSufficient);
-                return;
-        }
-        // Go through all outputs, overwrite output dimensions with returned output shapes
-        if (outputShapes.size() > 0) {
-            for_each<uint32_t>(test.operandDimensions,
-                               [&outputShapes](int idx, std::vector<uint32_t>& dim) {
-                                   dim = outputShapes[idx].dimensions;
-                               });
-        }
-
-        // validate results
-        outputMemory->read();
-        copy_back(&test, outputs_info, outputPtr);
-        outputMemory->commit();
-        // Filter out don't cares
-        MixedTyped filtered_golden = filter(golden, is_ignored);
-        MixedTyped filtered_test = filter(test, is_ignored);
-
-        // We want "close-enough" results for float
-        compare(filtered_golden, filtered_test, fpAtol, fpRtol);
-
-        if (example.expectedMultinomialDistributionTolerance > 0) {
-            expectMultinomialDistributionWithinTolerance(test, example);
-        }
-    }
-}
-template <typename T_IPreparedModel>
-void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
-                           const std::vector<MixedTypedExample>& examples,
-                           bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure,
-                           OutputType outputType) {
-    EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol,
-                          kDefaultRtol, executor, measure, outputType);
+    // We want "close-enough" results.
+    checkResults(testModel, outputs);
 }
 
-void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
-                           std::function<bool(int)> is_ignored,
-                           const std::vector<MixedTypedExample>& examples,
-                           bool hasRelaxedFloat32Model, bool testDynamicOutputShape) {
-    if (testDynamicOutputShape) {
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::ASYNC, MeasureTiming::NO, OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::SYNC, MeasureTiming::NO, OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::BURST, MeasureTiming::NO, OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::ASYNC, MeasureTiming::YES, OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::SYNC, MeasureTiming::YES, OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::BURST, MeasureTiming::YES, OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::ASYNC, MeasureTiming::NO, OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::SYNC, MeasureTiming::NO, OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::BURST, MeasureTiming::NO, OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::ASYNC, MeasureTiming::YES, OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::SYNC, MeasureTiming::YES, OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::BURST, MeasureTiming::YES, OutputType::INSUFFICIENT);
-    } else {
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::ASYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::SYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::BURST, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::ASYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::SYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
-                              Executor::BURST, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
-    }
+void GeneratedTestBase::SetUp() {
+    testing::TestWithParam<GeneratedTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
 }
 
-static void getPreparedModel(sp<PreparedModelCallback> callback,
-                             sp<V1_0::IPreparedModel>* preparedModel) {
-    *preparedModel = callback->getPreparedModel();
-}
-static void getPreparedModel(sp<PreparedModelCallback> callback,
-                             sp<V1_2::IPreparedModel>* preparedModel) {
-    sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
-    *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
+std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
 }
 
-void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
-             std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
-    V1_0::Model model = create_model();
-
-    // see if service can handle model
-    bool fullySupportsModel = false;
-    Return<void> supportedCall = device->getSupportedOperations(
-        model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
-            ASSERT_EQ(ErrorStatus::NONE, status);
-            ASSERT_NE(0ul, supported.size());
-            fullySupportsModel =
-                std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
-        });
-    ASSERT_TRUE(supportedCall.isOk());
-
-    // launch prepare model
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk());
-    ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
-
-    // retrieve prepared model
-    preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
-    sp<V1_0::IPreparedModel> preparedModel;
-    getPreparedModel(preparedModelCallback, &preparedModel);
-
-    // early termination if vendor service cannot fully prepare model
-    if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
-        ASSERT_EQ(nullptr, preparedModel.get());
-        LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
-                     "prepare model that it does not support.";
-        std::cout << "[          ]   Early termination of test because vendor service cannot "
-                     "prepare model that it does not support."
-                  << std::endl;
-        GTEST_SKIP();
-    }
-    EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
-    ASSERT_NE(nullptr, preparedModel.get());
-
-    float fpAtol = 1e-5f, fpRtol = 5.0f * 1.1920928955078125e-7f;
-    EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol, Executor::ASYNC,
-                          MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
+    const auto& [namedDevice, namedModel] = info.param;
+    return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
 }
 
-void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
-             std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
-    V1_1::Model model = create_model();
+// Tag for the generated tests
+class GeneratedTest : public GeneratedTestBase {};
 
-    // see if service can handle model
-    bool fullySupportsModel = false;
-    Return<void> supportedCall = device->getSupportedOperations_1_1(
-        model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
-            ASSERT_EQ(ErrorStatus::NONE, status);
-            ASSERT_NE(0ul, supported.size());
-            fullySupportsModel =
-                std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
-        });
-    ASSERT_TRUE(supportedCall.isOk());
-
-    // launch prepare model
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
-        model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk());
-    ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
-
-    // retrieve prepared model
-    preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
-    sp<V1_0::IPreparedModel> preparedModel;
-    getPreparedModel(preparedModelCallback, &preparedModel);
-
-    // early termination if vendor service cannot fully prepare model
-    if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
-        ASSERT_EQ(nullptr, preparedModel.get());
-        LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
-                     "prepare model that it does not support.";
-        std::cout << "[          ]   Early termination of test because vendor service cannot "
-                     "prepare model that it does not support."
-                  << std::endl;
-        GTEST_SKIP();
-    }
-    EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
-    ASSERT_NE(nullptr, preparedModel.get());
-
-    EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f, Executor::ASYNC,
-                          MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
+TEST_P(GeneratedTest, Test) {
+    Execute(kDevice, kTestModel);
 }
 
-void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model,
-                  sp<V1_2::IPreparedModel>* preparedModel) {
-    // see if service can handle model
-    bool fullySupportsModel = false;
-    Return<void> supportedCall = device->getSupportedOperations_1_2(
-        model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
-            ASSERT_EQ(ErrorStatus::NONE, status);
-            ASSERT_NE(0ul, supported.size());
-            fullySupportsModel =
-                std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
-        });
-    ASSERT_TRUE(supportedCall.isOk());
+INSTANTIATE_GENERATED_TEST(GeneratedTest,
+                           [](const TestModel& testModel) { return !testModel.expectFailure; });
 
-    // launch prepare model
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2(
-            model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(),
-            hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk());
-    ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
-
-    // retrieve prepared model
-    preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
-    getPreparedModel(preparedModelCallback, preparedModel);
-
-    // early termination if vendor service cannot fully prepare model
-    if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
-        ASSERT_EQ(nullptr, preparedModel->get());
-        LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
-                     "prepare model that it does not support.";
-        std::cout << "[          ]   Early termination of test because vendor service cannot "
-                     "prepare model that it does not support."
-                  << std::endl;
-        return;
-    }
-    EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
-    ASSERT_NE(nullptr, preparedModel->get());
-}
-
-// TODO: Reduce code duplication.
-void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model,
-             std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples,
-             bool testDynamicOutputShape) {
-    V1_2::Model model = create_model();
-    sp<V1_2::IPreparedModel> preparedModel = nullptr;
-    PrepareModel(device, model, &preparedModel);
-    if (preparedModel == nullptr) {
-        GTEST_SKIP();
-    }
-    EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          model.relaxComputationFloat32toFloat16, testDynamicOutputShape);
-}
-
-}  // namespace generated_tests
-
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
index c7d2399..f230a02 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
@@ -14,44 +14,43 @@
  * limitations under the License.
  */
 
-#ifndef VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H
-#define VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H
-
-#include "TestHarness.h"
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H
 
 #include <android/hardware/neuralnetworks/1.0/IDevice.h>
-#include <android/hardware/neuralnetworks/1.1/IDevice.h>
-#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <functional>
+#include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-namespace generated_tests {
-using ::test_helper::MixedTypedExample;
+using NamedModel = Named<const test_helper::TestModel*>;
+using GeneratedTestParam = std::tuple<NamedDevice, NamedModel>;
 
-void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model,
-                  sp<V1_2::IPreparedModel>* preparedModel);
+class GeneratedTestBase : public testing::TestWithParam<GeneratedTestParam> {
+  protected:
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(std::get<NamedDevice>(GetParam()));
+    const test_helper::TestModel& kTestModel = *getData(std::get<NamedModel>(GetParam()));
+};
 
-void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
-                           std::function<bool(int)> is_ignored,
-                           const std::vector<MixedTypedExample>& examples,
-                           bool hasRelaxedFloat32Model, bool testDynamicOutputShape);
+using FilterFn = std::function<bool(const test_helper::TestModel&)>;
+std::vector<NamedModel> getNamedModels(const FilterFn& filter);
 
-void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
-             std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples);
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
 
-void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
-             std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples);
+#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
+    INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite,                                    \
+                             testing::Combine(testing::ValuesIn(getNamedDevices()),       \
+                                              testing::ValuesIn(getNamedModels(filter))), \
+                             printGeneratedTest)
 
-void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model,
-             std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples,
-             bool testDynamicOutputShape = false);
+// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp.
+// TODO: Clean up the hierarchy for ValidationTest.
+class ValidationTest : public GeneratedTestBase {};
 
-}  // namespace generated_tests
+Model createModel(const test_helper::TestModel& testModel);
 
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
 
-#endif  // VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
deleted file mode 100644
index d1c7de3..0000000
--- a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_0_vts_tests.cpp"
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_0
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/TestAssertions.cpp b/neuralnetworks/1.0/vts/functional/TestAssertions.cpp
new file mode 100644
index 0000000..8fdc98d
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/TestAssertions.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.
+ */
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include "TestHarness.h"
+
+namespace android::hardware::neuralnetworks::V1_0 {
+
+// Make sure that the HIDL enums are compatible with the values defined in
+// frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h.
+using namespace test_helper;
+#define CHECK_TEST_ENUM(EnumType, enumValue) \
+    static_assert(static_cast<EnumType>(Test##EnumType::enumValue) == EnumType::enumValue)
+
+CHECK_TEST_ENUM(OperandType, FLOAT32);
+CHECK_TEST_ENUM(OperandType, INT32);
+CHECK_TEST_ENUM(OperandType, UINT32);
+CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT32);
+CHECK_TEST_ENUM(OperandType, TENSOR_INT32);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM);
+
+CHECK_TEST_ENUM(OperandLifeTime, TEMPORARY_VARIABLE);
+CHECK_TEST_ENUM(OperandLifeTime, MODEL_INPUT);
+CHECK_TEST_ENUM(OperandLifeTime, MODEL_OUTPUT);
+CHECK_TEST_ENUM(OperandLifeTime, CONSTANT_COPY);
+CHECK_TEST_ENUM(OperandLifeTime, CONSTANT_REFERENCE);
+CHECK_TEST_ENUM(OperandLifeTime, NO_VALUE);
+
+CHECK_TEST_ENUM(OperationType, ADD);
+CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D);
+CHECK_TEST_ENUM(OperationType, CONCATENATION);
+CHECK_TEST_ENUM(OperationType, CONV_2D);
+CHECK_TEST_ENUM(OperationType, DEPTHWISE_CONV_2D);
+CHECK_TEST_ENUM(OperationType, DEPTH_TO_SPACE);
+CHECK_TEST_ENUM(OperationType, DEQUANTIZE);
+CHECK_TEST_ENUM(OperationType, EMBEDDING_LOOKUP);
+CHECK_TEST_ENUM(OperationType, FLOOR);
+CHECK_TEST_ENUM(OperationType, FULLY_CONNECTED);
+CHECK_TEST_ENUM(OperationType, HASHTABLE_LOOKUP);
+CHECK_TEST_ENUM(OperationType, L2_NORMALIZATION);
+CHECK_TEST_ENUM(OperationType, L2_POOL_2D);
+CHECK_TEST_ENUM(OperationType, LOCAL_RESPONSE_NORMALIZATION);
+CHECK_TEST_ENUM(OperationType, LOGISTIC);
+CHECK_TEST_ENUM(OperationType, LSH_PROJECTION);
+CHECK_TEST_ENUM(OperationType, LSTM);
+CHECK_TEST_ENUM(OperationType, MAX_POOL_2D);
+CHECK_TEST_ENUM(OperationType, MUL);
+CHECK_TEST_ENUM(OperationType, RELU);
+CHECK_TEST_ENUM(OperationType, RELU1);
+CHECK_TEST_ENUM(OperationType, RELU6);
+CHECK_TEST_ENUM(OperationType, RESHAPE);
+CHECK_TEST_ENUM(OperationType, RESIZE_BILINEAR);
+CHECK_TEST_ENUM(OperationType, RNN);
+CHECK_TEST_ENUM(OperationType, SOFTMAX);
+CHECK_TEST_ENUM(OperationType, SPACE_TO_DEPTH);
+CHECK_TEST_ENUM(OperationType, SVDF);
+CHECK_TEST_ENUM(OperationType, TANH);
+
+#undef CHECK_TEST_ENUM
+
+}  // namespace android::hardware::neuralnetworks::V1_0
diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp
new file mode 100644
index 0000000..5b630fd
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/Utils.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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 "1.0/Utils.h"
+
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+namespace android::hardware::neuralnetworks {
+
+using namespace test_helper;
+using hidl::memory::V1_0::IMemory;
+using V1_0::DataLocation;
+using V1_0::Request;
+using V1_0::RequestArgument;
+
+constexpr uint32_t kInputPoolIndex = 0;
+constexpr uint32_t kOutputPoolIndex = 1;
+
+Request createRequest(const TestModel& testModel) {
+    // Model inputs.
+    hidl_vec<RequestArgument> inputs(testModel.inputIndexes.size());
+    size_t inputSize = 0;
+    for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
+        const auto& op = testModel.operands[testModel.inputIndexes[i]];
+        if (op.data.size() == 0) {
+            // Omitted input.
+            inputs[i] = {.hasNoValue = true};
+        } else {
+            DataLocation loc = {.poolIndex = kInputPoolIndex,
+                                .offset = static_cast<uint32_t>(inputSize),
+                                .length = static_cast<uint32_t>(op.data.size())};
+            inputSize += op.data.alignedSize();
+            inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
+        }
+    }
+
+    // Model outputs.
+    hidl_vec<RequestArgument> outputs(testModel.outputIndexes.size());
+    size_t outputSize = 0;
+    for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) {
+        const auto& op = testModel.operands[testModel.outputIndexes[i]];
+
+        // In the case of zero-sized output, we should at least provide a one-byte buffer.
+        // This is because zero-sized tensors are only supported internally to the driver, or
+        // reported in output shapes. It is illegal for the client to pre-specify a zero-sized
+        // tensor as model output. Otherwise, we will have two semantic conflicts:
+        // - "Zero dimension" conflicts with "unspecified dimension".
+        // - "Omitted operand buffer" conflicts with "zero-sized operand buffer".
+        size_t bufferSize = std::max<size_t>(op.data.size(), 1);
+
+        DataLocation loc = {.poolIndex = kOutputPoolIndex,
+                            .offset = static_cast<uint32_t>(outputSize),
+                            .length = static_cast<uint32_t>(bufferSize)};
+        outputSize += op.data.size() == 0 ? TestBuffer::kAlignment : op.data.alignedSize();
+        outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
+    }
+
+    // Allocate memory pools.
+    hidl_vec<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
+                                   nn::allocateSharedMemory(outputSize)};
+    CHECK_NE(pools[kInputPoolIndex].size(), 0u);
+    CHECK_NE(pools[kOutputPoolIndex].size(), 0u);
+    sp<IMemory> inputMemory = mapMemory(pools[kInputPoolIndex]);
+    CHECK(inputMemory.get() != nullptr);
+    uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
+    CHECK(inputPtr != nullptr);
+
+    // Copy input data to the memory pool.
+    for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
+        const auto& op = testModel.operands[testModel.inputIndexes[i]];
+        if (op.data.size() > 0) {
+            const uint8_t* begin = op.data.get<uint8_t>();
+            const uint8_t* end = begin + op.data.size();
+            std::copy(begin, end, inputPtr + inputs[i].location.offset);
+        }
+    }
+
+    return {.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
+}
+
+std::vector<TestBuffer> getOutputBuffers(const Request& request) {
+    sp<IMemory> outputMemory = mapMemory(request.pools[kOutputPoolIndex]);
+    CHECK(outputMemory.get() != nullptr);
+    uint8_t* outputPtr = static_cast<uint8_t*>(static_cast<void*>(outputMemory->getPointer()));
+    CHECK(outputPtr != nullptr);
+
+    // Copy out output results.
+    std::vector<TestBuffer> outputBuffers;
+    for (const auto& output : request.outputs) {
+        outputBuffers.emplace_back(output.location.length, outputPtr + output.location.offset);
+    }
+
+    return outputBuffers;
+}
+
+std::string gtestCompliantName(std::string name) {
+    // gtest test names must only contain alphanumeric characters
+    std::replace_if(
+            name.begin(), name.end(), [](char c) { return !std::isalnum(c); }, '_');
+    return name;
+}
+
+}  // namespace android::hardware::neuralnetworks
+
+namespace android::hardware::neuralnetworks::V1_0 {
+
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) {
+    return os << toString(errorStatus);
+}
+
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) {
+    return os << toString(deviceStatus);
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_0
diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
index 5d24fb5..cc15263 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
@@ -16,39 +16,32 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
+#include "1.0/Callbacks.h"
+#include "GeneratedTestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
-#include "Callbacks.h"
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using implementation::PreparedModelCallback;
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
 static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
-                                           const V1_0::Model& model) {
+                                           const Model& model) {
     SCOPED_TRACE(message + " [getSupportedOperations]");
 
     Return<void> ret =
-        device->getSupportedOperations(model, [&](ErrorStatus status, const hidl_vec<bool>&) {
-            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
-        });
+            device->getSupportedOperations(model, [&](ErrorStatus status, const hidl_vec<bool>&) {
+                EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+            });
     EXPECT_TRUE(ret.isOk());
 }
 
 static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
-                                 const V1_0::Model& model) {
+                                 const Model& model) {
     SCOPED_TRACE(message + " [prepareModel]");
 
     sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
     Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -64,7 +57,7 @@
 // mutation to it to invalidate the model, then pass it to interface calls that
 // use the model. Note that the model here is passed by value, and any mutation
 // to the model does not leave this function.
-static void validate(const sp<IDevice>& device, const std::string& message, V1_0::Model model,
+static void validate(const sp<IDevice>& device, const std::string& message, Model model,
                      const std::function<void(Model*)>& mutation) {
     mutation(&model);
     validateGetSupportedOperations(device, message, model);
@@ -94,13 +87,13 @@
 static uint32_t addOperand(Model* model) {
     return hidl_vec_push_back(&model->operands,
                               {
-                                  .type = OperandType::INT32,
-                                  .dimensions = {},
-                                  .numberOfConsumers = 0,
-                                  .scale = 0.0f,
-                                  .zeroPoint = 0,
-                                  .lifetime = OperandLifeTime::MODEL_INPUT,
-                                  .location = {.poolIndex = 0, .offset = 0, .length = 0},
+                                      .type = OperandType::INT32,
+                                      .dimensions = {},
+                                      .numberOfConsumers = 0,
+                                      .scale = 0.0f,
+                                      .zeroPoint = 0,
+                                      .lifetime = OperandLifeTime::MODEL_INPUT,
+                                      .location = {.poolIndex = 0, .offset = 0, .length = 0},
                               });
 }
 
@@ -114,13 +107,13 @@
 ///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
 
 static const int32_t invalidOperandTypes[] = {
-    static_cast<int32_t>(OperandType::FLOAT32) - 1,              // lower bound fundamental
-    static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1,  // upper bound fundamental
-    static_cast<int32_t>(OperandType::OEM) - 1,                  // lower bound OEM
-    static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1,      // upper bound OEM
+        static_cast<int32_t>(OperandType::FLOAT32) - 1,              // lower bound fundamental
+        static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1,  // upper bound fundamental
+        static_cast<int32_t>(OperandType::OEM) - 1,                  // lower bound OEM
+        static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1,      // upper bound OEM
 };
 
-static void mutateOperandTypeTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         for (int32_t invalidOperandType : invalidOperandTypes) {
             const std::string message = "mutateOperandTypeTest: operand " +
@@ -150,7 +143,7 @@
     }
 }
 
-static void mutateOperandRankTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void mutateOperandRankTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
         const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
@@ -179,7 +172,7 @@
     }
 }
 
-static void mutateOperandScaleTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void mutateOperandScaleTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         const float invalidScale = getInvalidScale(model.operands[operand].type);
         const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
@@ -207,10 +200,10 @@
     }
 }
 
-static void mutateOperandZeroPointTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void mutateOperandZeroPointTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         const std::vector<int32_t> invalidZeroPoints =
-            getInvalidZeroPoints(model.operands[operand].type);
+                getInvalidZeroPoints(model.operands[operand].type);
         for (int32_t invalidZeroPoint : invalidZeroPoints) {
             const std::string message = "mutateOperandZeroPointTest: operand " +
                                         std::to_string(operand) + " has zero point of " +
@@ -242,18 +235,18 @@
             break;
         case OperandType::TENSOR_FLOAT32:
             newOperand.dimensions =
-                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.scale = 0.0f;
             newOperand.zeroPoint = 0;
             break;
         case OperandType::TENSOR_INT32:
             newOperand.dimensions =
-                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.zeroPoint = 0;
             break;
         case OperandType::TENSOR_QUANT8_ASYMM:
             newOperand.dimensions =
-                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
             break;
         case OperandType::OEM:
@@ -264,7 +257,7 @@
     *operand = newOperand;
 }
 
-static bool mutateOperationOperandTypeSkip(size_t operand, const V1_0::Model& model) {
+static bool mutateOperationOperandTypeSkip(size_t operand, const Model& model) {
     // LSH_PROJECTION's second argument is allowed to have any type. This is the
     // only operation that currently has a type that can be anything independent
     // from any other type. Changing the operand type to any other type will
@@ -278,7 +271,7 @@
     return false;
 }
 
-static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         if (mutateOperationOperandTypeSkip(operand, model)) {
             continue;
@@ -303,13 +296,13 @@
 ///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
 
 static const int32_t invalidOperationTypes[] = {
-    static_cast<int32_t>(OperationType::ADD) - 1,            // lower bound fundamental
-    static_cast<int32_t>(OperationType::TANH) + 1,           // upper bound fundamental
-    static_cast<int32_t>(OperationType::OEM_OPERATION) - 1,  // lower bound OEM
-    static_cast<int32_t>(OperationType::OEM_OPERATION) + 1,  // upper bound OEM
+        static_cast<int32_t>(OperationType::ADD) - 1,            // lower bound fundamental
+        static_cast<int32_t>(OperationType::TANH) + 1,           // upper bound fundamental
+        static_cast<int32_t>(OperationType::OEM_OPERATION) - 1,  // lower bound OEM
+        static_cast<int32_t>(OperationType::OEM_OPERATION) + 1,  // upper bound OEM
 };
 
-static void mutateOperationTypeTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         for (int32_t invalidOperationType : invalidOperationTypes) {
             const std::string message = "mutateOperationTypeTest: operation " +
@@ -317,7 +310,7 @@
                                         std::to_string(invalidOperationType);
             validate(device, message, model, [operation, invalidOperationType](Model* model) {
                 model->operations[operation].type =
-                    static_cast<OperationType>(invalidOperationType);
+                        static_cast<OperationType>(invalidOperationType);
             });
         }
     }
@@ -325,8 +318,7 @@
 
 ///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
 
-static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device,
-                                                 const V1_0::Model& model) {
+static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const uint32_t invalidOperand = model.operands.size();
         for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
@@ -342,8 +334,7 @@
 
 ///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
 
-static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device,
-                                                  const V1_0::Model& model) {
+static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const uint32_t invalidOperand = model.operands.size();
         for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
@@ -381,7 +372,7 @@
     removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
 }
 
-static void removeOperandTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void removeOperandTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         const std::string message = "removeOperandTest: operand " + std::to_string(operand);
         validate(device, message, model,
@@ -398,7 +389,7 @@
     hidl_vec_removeAt(&model->operations, index);
 }
 
-static void removeOperationTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message = "removeOperationTest: operation " + std::to_string(operation);
         validate(device, message, model,
@@ -408,14 +399,14 @@
 
 ///////////////////////// REMOVE OPERATION INPUT /////////////////////////
 
-static void removeOperationInputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void removeOperationInputTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
-            const V1_0::Operation& op = model.operations[operation];
+            const Operation& op = model.operations[operation];
             // CONCATENATION has at least 2 inputs, with the last element being
             // INT32. Skip this test if removing one of CONCATENATION's
             // inputs still produces a valid model.
-            if (op.type == V1_0::OperationType::CONCATENATION && op.inputs.size() > 2 &&
+            if (op.type == OperationType::CONCATENATION && op.inputs.size() > 2 &&
                 input != op.inputs.size() - 1) {
                 continue;
             }
@@ -433,7 +424,7 @@
 
 ///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
 
-static void removeOperationOutputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void removeOperationOutputTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
             const std::string message = "removeOperationOutputTest: operation " +
@@ -454,7 +445,7 @@
 
 ///////////////////////// ADD OPERATION INPUT /////////////////////////
 
-static void addOperationInputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
         validate(device, message, model, [operation](Model* model) {
@@ -467,10 +458,10 @@
 
 ///////////////////////// ADD OPERATION OUTPUT /////////////////////////
 
-static void addOperationOutputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+static void addOperationOutputTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message =
-            "addOperationOutputTest: operation " + std::to_string(operation);
+                "addOperationOutputTest: operation " + std::to_string(operation);
         validate(device, message, model, [operation](Model* model) {
             uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
             hidl_vec_push_back(&model->operations[operation].outputs, index);
@@ -481,7 +472,7 @@
 
 ////////////////////////// ENTRY POINT //////////////////////////////
 
-void ValidationTest::validateModel(const V1_0::Model& model) {
+void validateModel(const sp<IDevice>& device, const Model& model) {
     mutateOperandTypeTest(device, model);
     mutateOperandRankTest(device, model);
     mutateOperandScaleTest(device, model);
@@ -498,9 +489,4 @@
     addOperationOutputTest(device, model);
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_0
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
index f0c93b7..05eefd1 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
@@ -16,28 +16,13 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
+#include "1.0/Callbacks.h"
+#include "GeneratedTestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
-#include "Callbacks.h"
-#include "TestHarness.h"
-#include "Utils.h"
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hidl::memory::V1_0::IMemory;
-using test_helper::for_all;
-using test_helper::MixedTyped;
-using test_helper::MixedTypedExample;
+using implementation::ExecutionCallback;
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
@@ -51,7 +36,6 @@
     SCOPED_TRACE(message + " [execute]");
 
     sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-    ASSERT_NE(nullptr, executionCallback.get());
     Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
     ASSERT_TRUE(executeLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
@@ -103,104 +87,9 @@
 
 ///////////////////////////// ENTRY POINT //////////////////////////////////
 
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples) {
-    const uint32_t INPUT = 0;
-    const uint32_t OUTPUT = 1;
-
-    std::vector<Request> requests;
-
-    for (const MixedTypedExample& example : examples) {
-        const MixedTyped& inputs = example.operands.first;
-        const MixedTyped& outputs = example.operands.second;
-
-        std::vector<RequestArgument> inputs_info, outputs_info;
-        uint32_t inputSize = 0, outputSize = 0;
-
-        // This function only partially specifies the metadata (vector of RequestArguments).
-        // The contents are copied over below.
-        for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
-            if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
-            RequestArgument arg = {
-                .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
-                .dimensions = {},
-            };
-            RequestArgument arg_empty = {
-                .hasNoValue = true,
-            };
-            inputs_info[index] = s ? arg : arg_empty;
-            inputSize += s;
-        });
-        // Compute offset for inputs 1 and so on
-        {
-            size_t offset = 0;
-            for (auto& i : inputs_info) {
-                if (!i.hasNoValue) i.location.offset = offset;
-                offset += i.location.length;
-            }
-        }
-
-        // Go through all outputs, initialize RequestArgument descriptors
-        for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
-            if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
-            RequestArgument arg = {
-                .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
-                .dimensions = {},
-            };
-            outputs_info[index] = arg;
-            outputSize += s;
-        });
-        // Compute offset for outputs 1 and so on
-        {
-            size_t offset = 0;
-            for (auto& i : outputs_info) {
-                i.location.offset = offset;
-                offset += i.location.length;
-            }
-        }
-        std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
-                                          nn::allocateSharedMemory(outputSize)};
-        if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
-            return {};
-        }
-
-        // map pool
-        sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
-        if (inputMemory == nullptr) {
-            return {};
-        }
-        char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
-        if (inputPtr == nullptr) {
-            return {};
-        }
-
-        // initialize pool
-        inputMemory->update();
-        for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
-            char* begin = (char*)p;
-            char* end = begin + s;
-            // TODO: handle more than one input
-            std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
-        });
-        inputMemory->commit();
-
-        requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
-    }
-
-    return requests;
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    removeInputTest(preparedModel, request);
+    removeOutputTest(preparedModel, request);
 }
 
-void ValidationTest::validateRequests(const sp<IPreparedModel>& preparedModel,
-                                      const std::vector<Request>& requests) {
-    // validate each request
-    for (const Request& request : requests) {
-        removeInputTest(preparedModel, request);
-        removeOutputTest(preparedModel, request);
-    }
-}
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_0
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
index aee2f85..cb22250 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
@@ -17,45 +17,45 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include "VtsHalNeuralnetworks.h"
+#include "1.0/Callbacks.h"
+#include "GeneratedTestHarness.h"
+#include "TestHarness.h"
 
 #include <android-base/logging.h>
+#include <hidl/ServiceManagement.h>
+#include <string>
+#include <utility>
 
-#include "Callbacks.h"
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
+using implementation::PreparedModelCallback;
 
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-
-static void createPreparedModel(const sp<IDevice>& device, const V1_0::Model& model,
-                                sp<IPreparedModel>* preparedModel) {
+void createPreparedModel(const sp<IDevice>& device, const Model& model,
+                         sp<IPreparedModel>* preparedModel) {
     ASSERT_NE(nullptr, preparedModel);
+    *preparedModel = nullptr;
 
     // see if service can handle model
     bool fullySupportsModel = false;
-    Return<void> supportedOpsLaunchStatus = device->getSupportedOperations(
+    const Return<void> supportedCall = device->getSupportedOperations(
             model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
                 ASSERT_EQ(ErrorStatus::NONE, status);
                 ASSERT_NE(0ul, supported.size());
                 fullySupportsModel = std::all_of(supported.begin(), supported.end(),
                                                  [](bool valid) { return valid; });
             });
-    ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
+    ASSERT_TRUE(supportedCall.isOk());
 
     // launch prepare model
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
+    const sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+    const Return<ErrorStatus> prepareLaunchStatus =
+            device->prepareModel(model, preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
 
     // retrieve prepared model
     preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
     *preparedModel = preparedModelCallback->getPreparedModel();
 
     // The getSupportedOperations call returns a list of operations that are
@@ -67,99 +67,73 @@
     // can continue.
     if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
         ASSERT_EQ(nullptr, preparedModel->get());
-        LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
-                     "prepare model that it does not support.";
-        std::cout << "[          ]   Unable to test Request validation because vendor service "
-                     "cannot prepare model that it does not support."
+        LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare "
+                     "model that it does not support.";
+        std::cout << "[          ]   Early termination of test because vendor service cannot "
+                     "prepare model that it does not support."
                   << std::endl;
-        return;
+        GTEST_SKIP();
     }
     ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
     ASSERT_NE(nullptr, preparedModel->get());
 }
 
-// A class for test environment setup
-NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
-
-NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {}
-
-NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
-    // This has to return a "new" object because it is freed inside
-    // ::testing::AddGlobalTestEnvironment when the gtest is being torn down
-    static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
-    return instance;
-}
-
-void NeuralnetworksHidlEnvironment::registerTestServices() {
-    registerTestService<IDevice>();
-}
-
-// The main test class for NEURALNETWORK HIDL HAL.
-NeuralnetworksHidlTest::NeuralnetworksHidlTest() {}
-
-NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
-
 void NeuralnetworksHidlTest::SetUp() {
-    ::testing::VtsHalHidlTargetTestBase::SetUp();
-    device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
-            NeuralnetworksHidlEnvironment::getInstance());
-
-#ifdef PRESUBMIT_NOT_VTS
-    const std::string name =
-            NeuralnetworksHidlEnvironment::getInstance()->getServiceName<IDevice>();
-    const std::string sampleDriver = "sample-";
-    if (device == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) {
-        GTEST_SKIP();
-    }
-#endif  // PRESUBMIT_NOT_VTS
-
-    ASSERT_NE(nullptr, device.get());
+    testing::TestWithParam<NeuralnetworksHidlTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
 }
 
-void NeuralnetworksHidlTest::TearDown() {
-    device = nullptr;
-    ::testing::VtsHalHidlTargetTestBase::TearDown();
+static NamedDevice makeNamedDevice(const std::string& name) {
+    return {name, IDevice::getService(name)};
 }
 
-void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
-    validateModel(model);
+static std::vector<NamedDevice> getNamedDevicesImpl() {
+    // Retrieves the name of all service instances that implement IDevice,
+    // including any Lazy HAL instances.
+    const std::vector<std::string> names = hardware::getAllHalInstanceNames(IDevice::descriptor);
 
-    // create IPreparedModel
+    // Get a handle to each device and pair it with its name.
+    std::vector<NamedDevice> namedDevices;
+    namedDevices.reserve(names.size());
+    std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice);
+    return namedDevices;
+}
+
+const std::vector<NamedDevice>& getNamedDevices() {
+    const static std::vector<NamedDevice> devices = getNamedDevicesImpl();
+    return devices;
+}
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info) {
+    return gtestCompliantName(getName(info.param));
+}
+
+INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest);
+
+// Forward declaration from ValidateModel.cpp
+void validateModel(const sp<IDevice>& device, const Model& model);
+// Forward declaration from ValidateRequest.cpp
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request);
+
+void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request) {
+    validateModel(device, model);
+
+    // Create IPreparedModel.
     sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
 
-    validateRequests(preparedModel, requests);
+    validateRequest(preparedModel, request);
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_0
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
-
-namespace android::hardware::neuralnetworks::V1_0 {
-
-::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) {
-    return os << toString(errorStatus);
+TEST_P(ValidationTest, Test) {
+    const Model model = createModel(kTestModel);
+    const Request request = createRequest(kTestModel);
+    ASSERT_FALSE(kTestModel.expectFailure);
+    validateEverything(kDevice, model, request);
 }
 
-::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) {
-    return os << toString(deviceStatus);
-}
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
 
-}  // namespace android::hardware::neuralnetworks::V1_0
-
-using android::hardware::neuralnetworks::V1_0::vts::functional::NeuralnetworksHidlEnvironment;
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
-    ::testing::InitGoogleTest(&argc, argv);
-    NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
-
-    int status = RUN_ALL_TESTS();
-    return status;
-}
+}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
index 22285be..17f4613 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
@@ -14,79 +14,42 @@
  * limitations under the License.
  */
 
-#ifndef VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
-#define VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H
+
+#include "1.0/Utils.h"
 
 #include <android/hardware/neuralnetworks/1.0/IDevice.h>
 #include <android/hardware/neuralnetworks/1.0/types.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
-#include <android-base/macros.h>
 #include <gtest/gtest.h>
-#include <iostream>
+
 #include <vector>
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-// A class for test environment setup
-class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
-    NeuralnetworksHidlEnvironment();
-    ~NeuralnetworksHidlEnvironment() override;
+using NamedDevice = Named<sp<IDevice>>;
+using NeuralnetworksHidlTestParam = NamedDevice;
 
-   public:
-    static NeuralnetworksHidlEnvironment* getInstance();
-    void registerTestServices() override;
-};
-
-// The main test class for NEURALNETWORKS HIDL HAL.
-class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
-
-   public:
-    NeuralnetworksHidlTest();
-    ~NeuralnetworksHidlTest() override;
+class NeuralnetworksHidlTest : public testing::TestWithParam<NeuralnetworksHidlTestParam> {
+  protected:
     void SetUp() override;
-    void TearDown() override;
-
-   protected:
-    sp<IDevice> device;
+    const sp<IDevice> kDevice = getData(GetParam());
 };
 
-// Tag for the validation tests
-class ValidationTest : public NeuralnetworksHidlTest {
-   protected:
-     void validateEverything(const Model& model, const std::vector<Request>& request);
+const std::vector<NamedDevice>& getNamedDevices();
 
-   private:
-     void validateModel(const Model& model);
-     void validateRequests(const sp<IPreparedModel>& preparedModel,
-                           const std::vector<Request>& requests);
-};
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info);
 
-// Tag for the generated tests
-class GeneratedTest : public NeuralnetworksHidlTest {};
+#define INSTANTIATE_DEVICE_TEST(TestSuite)                                                 \
+    INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \
+                             printNeuralnetworksHidlTest)
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_0
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+// Create an IPreparedModel object. If the model cannot be prepared,
+// "preparedModel" will be nullptr instead.
+void createPreparedModel(const sp<IDevice>& device, const Model& model,
+                         sp<IPreparedModel>* preparedModel);
 
-namespace android::hardware::neuralnetworks::V1_0 {
+}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
 
-// pretty-print values for error messages
-::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
-::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus);
-
-}  // namespace android::hardware::neuralnetworks::V1_0
-
-#endif  // VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H
diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h b/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h
new file mode 100644
index 0000000..820bb10
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <hidl/Status.h>
+#include <condition_variable>
+#include <mutex>
+
+/*
+ * The Callback classes are used internally by the NeuralNetworks runtime to
+ * synchronize between different threads. An asynchronous task is launched
+ * paired with a callback object. When a client thread requires the output being
+ * generated by the asynchronous task, the client thread can wait for the result
+ * and be blocked until it has completed. Any wait may safely be called
+ * concurrently, even on the same callback object. When the asynchronous task
+ * has finished its workload, it must immediately call "notify". If the
+ * asynchronous task has failed to launch, the function that tried to launch the
+ * asynchronous task must immediately call "notify". This "notify" call
+ * awakens any client threads waiting on the callback object.
+ *
+ * These classes exist to enable synchronization across HIDL. When
+ * synchronization is only required in the same process, consider using
+ * std::future, std::mutex, std::condition_variable, or std::experimental::latch
+ * instead.
+ */
+
+namespace android::hardware::neuralnetworks::V1_0::implementation {
+
+/**
+ * The PreparedModelCallback class is used to receive the error status of
+ * preparing a model as well as the prepared model from a task executing
+ * asynchronously with respect to the runtime. If a calling thread calls wait
+ * or get* on a PreparedModelCallback object and the corresponding asynchronous
+ * task has not finished preparing the model, the calling thread will block
+ * until the asynchronous task has called notify.
+ *
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IDevice::prepareModel*.
+ */
+class PreparedModelCallback : public IPreparedModelCallback {
+  public:
+    /**
+     * IPreparedModelCallback::notify marks the callback object with the return
+     * status of the asynchronous model preparation along with the prepared
+     * model, and allows all prior and future wait calls on the
+     * PreparedModelCallback object to proceed.
+     *
+     * IPreparedModelCallback::notify must be called on a given
+     * PreparedModelCallback object.
+     *
+     * If the callback object is notified more than once, only the results of
+     * the first call to notify are used, and the results from subsequent calls
+     * are discarded.
+     *
+     * @param status Error status returned from asynchronously preparing the
+     *     model; will be:
+     *     - NONE if the asynchronous preparation was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if the input model is invalid
+     * @param preparedModel Returned model that has been prepared for execution,
+     *     nullptr if the model was unable to be prepared.
+     */
+    Return<void> notify(ErrorStatus status, const sp<IPreparedModel>& preparedModel) override;
+
+    /**
+     * PreparedModelCallback::wait blocks until notify has been called on the
+     * callback object.
+     */
+    void wait() const;
+
+    /**
+     * Retrieves the error status returned from the asynchronous task launched
+     * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished
+     * asynchronously preparing the model, this call will block until the
+     * asynchronous task notifies the object.
+     *
+     * @return status Error status returned from asynchronously preparing the
+     *     model; will be:
+     *     - NONE if the asynchronous preparation was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if the input model is invalid
+     */
+    ErrorStatus getStatus() const;
+
+    /**
+     * Retrieves the model that has been prepared for execution from the
+     * asynchronous task launched by IDevice::prepareModel*. If
+     * IDevice::prepareModel* has not finished asynchronously preparing the
+     * model, this call will block until the asynchronous task notifies the
+     * object.
+     *
+     * @return preparedModel Returned model that has been prepared for
+     *     execution, nullptr if the model was unable to be prepared.
+     */
+    sp<IPreparedModel> getPreparedModel() const;
+
+  private:
+    mutable std::mutex mMutex;
+    mutable std::condition_variable mCondition;
+    bool mNotified GUARDED_BY(mMutex) = false;
+    ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
+    sp<IPreparedModel> mPreparedModel;
+};
+
+/**
+ * The ExecutionCallback class is used to receive the results of the execution
+ * from a task executing asynchronously with respect to the runtime. If a
+ * calling thread calls wait or get* on a ExecutionCallback object and the
+ * corresponding asynchronous task has not finished the execution, the calling
+ * thread will block until the asynchronous task has called notify.
+ *
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IPreparedModel::execute*.
+ */
+class ExecutionCallback : public IExecutionCallback {
+  public:
+    /**
+     * IExecutionCallback::notify marks the callback object with the return
+     * status of the asynchronous execution that held this callback and enables
+     * all prior and future wait calls on the ExecutionCallback object to
+     * proceed.
+     *
+     * IExecutionCallback::notify must be called on a given ExecutionCallback
+     * object.
+     *
+     * If the callback object is notified more than once, only the results of
+     * the first call to notify are used, and the results from subsequent calls
+     * are discarded.
+     *
+     * @param status Error status returned from launching the asynchronous task
+     *     (if the launch fails) or from the asynchronous task itself (if the
+     *     launch succeeds). Must be:
+     *     - NONE if the asynchronous execution was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large
+     *         enough to store the resultant values
+     *     - INVALID_ARGUMENT if the input request is invalid
+     */
+    Return<void> notify(ErrorStatus status) override;
+
+    /**
+     * ExecutionCallback::wait blocks until notify has been called on the
+     * callback object.
+     */
+    void wait() const;
+
+    /**
+     * Retrieves the error status returned from the asynchronous task launched
+     * by IPreparedModel::execute. If IPreparedModel::execute has not finished
+     * asynchronously executing, this call will block until the asynchronous
+     * task notifies the object.
+     *
+     * @return status Error status returned from launching the asynchronous task
+     *     (if the launch fails) or from the asynchronous task itself (if the
+     *     launch succeeds). Must be:
+     *     - NONE if the asynchronous execution was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if the asynchronous task resulted in an unspecified
+     *         error
+     *     - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+     *         not large enough to store the corresponding output
+     *     - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+     *         invalid
+     */
+    ErrorStatus getStatus() const;
+
+  private:
+    mutable std::mutex mMutex;
+    mutable std::condition_variable mCondition;
+    bool mNotified GUARDED_BY(mMutex) = false;
+    ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_0::implementation
+
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
new file mode 100644
index 0000000..6d4534c
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <algorithm>
+#include <iosfwd>
+#include <string>
+#include <utility>
+#include <vector>
+#include "TestHarness.h"
+
+namespace android::hardware::neuralnetworks {
+
+// Create HIDL Request from the TestModel struct.
+V1_0::Request createRequest(const test_helper::TestModel& testModel);
+
+// After execution, copy out output results from the output memory pool.
+std::vector<::test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request);
+
+// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
+// so this is efficiently accomplished by moving the element to the end and
+// resizing the hidl_vec to one less.
+template <typename Type>
+inline void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
+    CHECK(vec != nullptr);
+    std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
+    vec->resize(vec->size() - 1);
+}
+
+template <typename Type>
+inline uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
+    CHECK(vec != nullptr);
+    const uint32_t index = vec->size();
+    vec->resize(index + 1);
+    (*vec)[index] = value;
+    return index;
+}
+
+template <typename Type>
+using Named = std::pair<std::string, Type>;
+
+template <typename Type>
+const std::string& getName(const Named<Type>& namedData) {
+    return namedData.first;
+}
+
+template <typename Type>
+const Type& getData(const Named<Type>& namedData) {
+    return namedData.second;
+}
+
+std::string gtestCompliantName(std::string name);
+
+}  // namespace android::hardware::neuralnetworks
+
+namespace android::hardware::neuralnetworks::V1_0 {
+
+// pretty-print values for error messages
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus);
+
+}  // namespace android::hardware::neuralnetworks::V1_0
+
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H
diff --git a/neuralnetworks/1.1/Android.bp b/neuralnetworks/1.1/Android.bp
index 1158a90..bef21c0 100644
--- a/neuralnetworks/1.1/Android.bp
+++ b/neuralnetworks/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/neuralnetworks/1.1/types.hal b/neuralnetworks/1.1/types.hal
index 73705bb..da7ba78 100644
--- a/neuralnetworks/1.1/types.hal
+++ b/neuralnetworks/1.1/types.hal
@@ -26,7 +26,6 @@
  * The type of an operation in a model.
  */
 enum OperationType : @1.0::OperationType {
-
     /**
      * BatchToSpace for N-dimensional tensors.
      *
@@ -41,7 +40,8 @@
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
-     * Supported tensor rank: 4
+     * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width,
+     * and Channels) data layout.
      *
      * Inputs:
      * * 0: An n-D tensor, specifying the tensor to be reshaped
@@ -51,8 +51,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     BATCH_TO_SPACE_ND = 29,
 
@@ -91,8 +91,6 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
      */
     DIV = 30,
 
@@ -126,8 +124,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     MEAN = 31,
 
@@ -138,7 +136,8 @@
      *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (the pad value is undefined)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (the pad value is undefined)
      *
      * Supported tensor rank: up to 4
      *
@@ -160,11 +159,8 @@
      *      of the padding:
      *          output0.dimension[i] =
      *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
-     *
-     *      NOTE: The pad value for {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
-     *      is undefined.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     PAD = 32,
 
@@ -182,8 +178,10 @@
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (the pad value is undefined)
      *
-     * Supported tensor rank: 4
+     * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width,
+     * and Channels) data layout.
      *
      * Inputs:
      * * 0: An n-D tensor, specifying the input.
@@ -201,8 +199,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     SPACE_TO_BATCH_ND = 33,
 
@@ -232,8 +230,8 @@
      * * 0: A tensor of the same {@link OperandType} as input0. Contains the
      *      same data as input, but has one or more dimensions of size 1
      *      removed.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     SQUEEZE = 34,
 
@@ -278,8 +276,8 @@
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0 and rank (n - k),
      *      where k is the number of bits set in shrink_axis_mask.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     STRIDED_SLICE = 35,
 
@@ -318,8 +316,6 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
      */
     SUB = 36,
 
@@ -345,11 +341,10 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     TRANSPOSE = 37,
-
 };
 
 /**
diff --git a/neuralnetworks/1.1/types.t b/neuralnetworks/1.1/types.t
new file mode 100644
index 0000000..75ac2e7
--- /dev/null
+++ b/neuralnetworks/1.1/types.t
@@ -0,0 +1,158 @@
+%% template file for generating types.hal.
+%% see frameworks/ml/nn/tools/api/README.md.
+/*
+ * Copyright (C) 2018 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.neuralnetworks@1.1;
+
+import @1.0::Operand;
+import @1.0::OperationType;
+import @1.0::PerformanceInfo;
+
+/**
+ * Operation types.
+ *
+ * The type of an operation in a model.
+ */
+enum OperationType : @1.0::OperationType {
+%insert Operation_1.1
+};
+
+/**
+ * The capabilities of a driver.
+ */
+struct Capabilities {
+    /**
+     * Driver performance when operating on float32 data.
+     */
+    PerformanceInfo float32Performance;
+
+    /**
+     * Driver performance when operating on asymmetric 8-bit quantized data.
+     */
+    PerformanceInfo quantized8Performance;
+
+    /**
+     * Driver performance when operating on float32 data but performing
+     * calculations with range and/or precision as low as that of the IEEE
+     * 754 16-bit floating-point format.
+     */
+    PerformanceInfo relaxedFloat32toFloat16Performance;
+};
+
+/**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+    /**
+     * The operation type.
+     */
+    OperationType type;
+
+    /**
+     * Describes the table that contains the indexes of the inputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> inputs;
+
+    /**
+     * Describes the table that contains the indexes of the outputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> outputs;
+};
+
+/**
+ * A Neural Network Model.
+ *
+ * This includes not only the execution graph, but also constant data such as
+ * weights or scalars added at construction time. The only information that
+ * may not be known is the shape of the input tensors.
+ */
+struct Model {
+    /**
+     * All operands included in the model.
+     */
+    vec<Operand> operands;
+
+    /**
+     * All operations included in the model.
+     *
+     * The operations are sorted into execution order. Every operand
+     * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
+     * written before it is read.
+     */
+    vec<Operation> operations;
+
+    /**
+     * Input indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> inputIndexes;
+
+    /**
+     * Output indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> outputIndexes;
+
+    /**
+     * A byte buffer containing operand data that were copied into the model.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_COPY.
+     */
+    vec<uint8_t> operandValues;
+
+    /**
+     * A collection of shared memory pools containing operand values.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_REFERENCE.
+     */
+    vec<memory> pools;
+
+    /**
+     * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or
+     * precision as low as that of the IEEE 754 16-bit floating-point format.
+     * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the
+     * range and precision of the IEEE 754 32-bit floating-point format.
+     */
+    bool relaxComputationFloat32toFloat16;
+};
+
+/**
+ * Execution preferences.
+ */
+enum ExecutionPreference : int32_t {
+    /**
+     * Prefer executing in a way that minimizes battery drain.
+     * This is desirable for compilations that will be executed often.
+     */
+    LOW_POWER = 0,
+    /**
+     * Prefer returning a single answer as fast as possible, even if this causes
+     * more power consumption.
+     */
+    FAST_SINGLE_ANSWER = 1,
+    /**
+     * Prefer maximizing the throughput of successive frames, for example when
+     * processing successive frames coming from the camera.
+     */
+    SUSTAINED_SPEED = 2,
+};
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 4fbeac9..69e1761 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -14,33 +14,38 @@
 // limitations under the License.
 //
 
-// Tests for V1_0 models using the V1_1 HAL.
-cc_test {
-    name: "VtsHalNeuralnetworksV1_1CompatV1_0TargetTest",
-    defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
-    srcs: [
-        "GeneratedTestsV1_0.cpp",
-    ],
-}
-
-// Tests for V1_1 models.
 cc_test {
     name: "VtsHalNeuralnetworksV1_1TargetTest",
-    defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+    defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "BasicTests.cpp",
-        "GeneratedTests.cpp",
+        "TestAssertions.cpp",
+        "ValidateModel.cpp",
+        "ValidateRequest.cpp",
+        "VtsHalNeuralnetworks.cpp",
+        "GeneratedTestHarness.cpp",
     ],
-}
-
-cc_test {
-    name: "PresubmitHalNeuralnetworksV1_1TargetTest",
-    defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
-    srcs: [
-        "BasicTests.cpp",
-        "GeneratedTests.cpp",
+    shared_libs: [
+        "libfmq",
+        "libnativewindow",
     ],
-    cflags: [
-        "-DPRESUBMIT_NOT_VTS",
+    static_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libgmock",
+        "libhidlmemory",
+        "libneuralnetworks_generated_test_harness",
+        "libneuralnetworks_utils",
+        "VtsHalNeuralNetworksV1_0_utils",
     ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+        "neuralnetworks_generated_V1_1_example",
+    ],
+    header_libs: [
+        "libneuralnetworks_headers",
+    ],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/neuralnetworks/1.1/vts/functional/BasicTests.cpp b/neuralnetworks/1.1/vts/functional/BasicTests.cpp
index ed59a2d..44836f0 100644
--- a/neuralnetworks/1.1/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.1/vts/functional/BasicTests.cpp
@@ -18,41 +18,34 @@
 
 #include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
+
+using V1_0::DeviceStatus;
+using V1_0::ErrorStatus;
 
 // create device test
-TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
+TEST_P(NeuralnetworksHidlTest, CreateDevice) {}
 
 // status test
-TEST_F(NeuralnetworksHidlTest, StatusTest) {
-    Return<DeviceStatus> status = device->getStatus();
+TEST_P(NeuralnetworksHidlTest, StatusTest) {
+    Return<DeviceStatus> status = kDevice->getStatus();
     ASSERT_TRUE(status.isOk());
     EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
 }
 
 // initialization
-TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) {
     Return<void> ret =
-        device->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) {
-            EXPECT_EQ(ErrorStatus::NONE, status);
-            EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
-            EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
-            EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
-            EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
-            EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.execTime);
-            EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.powerUsage);
-        });
+            kDevice->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) {
+                EXPECT_EQ(ErrorStatus::NONE, status);
+                EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
+                EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
+                EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
+                EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
+                EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.execTime);
+                EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.powerUsage);
+            });
     EXPECT_TRUE(ret.isOk());
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
new file mode 100644
index 0000000..7a929d6
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GeneratedTestHarness.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+#include <gtest/gtest.h>
+#include <iostream>
+
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
+
+using namespace test_helper;
+using hidl::memory::V1_0::IMemory;
+using V1_0::DataLocation;
+using V1_0::ErrorStatus;
+using V1_0::IPreparedModel;
+using V1_0::Operand;
+using V1_0::OperandLifeTime;
+using V1_0::OperandType;
+using V1_0::Request;
+using V1_0::implementation::ExecutionCallback;
+using V1_0::implementation::PreparedModelCallback;
+
+Model createModel(const TestModel& testModel) {
+    // Model operands.
+    hidl_vec<Operand> operands(testModel.operands.size());
+    size_t constCopySize = 0, constRefSize = 0;
+    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+        const auto& op = testModel.operands[i];
+
+        DataLocation loc = {};
+        if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+            loc = {.poolIndex = 0,
+                   .offset = static_cast<uint32_t>(constCopySize),
+                   .length = static_cast<uint32_t>(op.data.size())};
+            constCopySize += op.data.alignedSize();
+        } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+            loc = {.poolIndex = 0,
+                   .offset = static_cast<uint32_t>(constRefSize),
+                   .length = static_cast<uint32_t>(op.data.size())};
+            constRefSize += op.data.alignedSize();
+        }
+
+        operands[i] = {.type = static_cast<OperandType>(op.type),
+                       .dimensions = op.dimensions,
+                       .numberOfConsumers = op.numberOfConsumers,
+                       .scale = op.scale,
+                       .zeroPoint = op.zeroPoint,
+                       .lifetime = static_cast<OperandLifeTime>(op.lifetime),
+                       .location = loc};
+    }
+
+    // Model operations.
+    hidl_vec<Operation> operations(testModel.operations.size());
+    std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
+                   [](const TestOperation& op) -> Operation {
+                       return {.type = static_cast<OperationType>(op.type),
+                               .inputs = op.inputs,
+                               .outputs = op.outputs};
+                   });
+
+    // Constant copies.
+    hidl_vec<uint8_t> operandValues(constCopySize);
+    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+        const auto& op = testModel.operands[i];
+        if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+            const uint8_t* begin = op.data.get<uint8_t>();
+            const uint8_t* end = begin + op.data.size();
+            std::copy(begin, end, operandValues.data() + operands[i].location.offset);
+        }
+    }
+
+    // Shared memory.
+    hidl_vec<hidl_memory> pools;
+    if (constRefSize > 0) {
+        hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize));
+        CHECK_NE(pools[0].size(), 0u);
+
+        // load data
+        sp<IMemory> mappedMemory = mapMemory(pools[0]);
+        CHECK(mappedMemory.get() != nullptr);
+        uint8_t* mappedPtr =
+                reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
+        CHECK(mappedPtr != nullptr);
+
+        for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+            const auto& op = testModel.operands[i];
+            if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+                const uint8_t* begin = op.data.get<uint8_t>();
+                const uint8_t* end = begin + op.data.size();
+                std::copy(begin, end, mappedPtr + operands[i].location.offset);
+            }
+        }
+    }
+
+    return {.operands = std::move(operands),
+            .operations = std::move(operations),
+            .inputIndexes = testModel.inputIndexes,
+            .outputIndexes = testModel.outputIndexes,
+            .operandValues = std::move(operandValues),
+            .pools = std::move(pools),
+            .relaxComputationFloat32toFloat16 = testModel.isRelaxed};
+}
+
+// Top level driver for models and examples generated by test_generator.py
+// Test driver for those generated from ml/nn/runtime/test/spec
+void Execute(const sp<IDevice>& device, const TestModel& testModel) {
+    const Model model = createModel(testModel);
+    const Request request = createRequest(testModel);
+
+    // Create IPreparedModel.
+    sp<IPreparedModel> preparedModel;
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
+
+    // Launch execution.
+    sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+    Return<ErrorStatus> executionLaunchStatus = preparedModel->execute(request, executionCallback);
+    ASSERT_TRUE(executionLaunchStatus.isOk());
+    EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
+
+    // Retrieve execution status.
+    executionCallback->wait();
+    ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
+
+    // Retrieve execution results.
+    const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+
+    // We want "close-enough" results.
+    checkResults(testModel, outputs);
+}
+
+void GeneratedTestBase::SetUp() {
+    testing::TestWithParam<GeneratedTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
+}
+
+std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
+}
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
+    const auto& [namedDevice, namedModel] = info.param;
+    return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
+}
+
+// Tag for the generated tests
+class GeneratedTest : public GeneratedTestBase {};
+
+TEST_P(GeneratedTest, Test) {
+    Execute(kDevice, kTestModel);
+}
+
+INSTANTIATE_GENERATED_TEST(GeneratedTest,
+                           [](const TestModel& testModel) { return !testModel.expectFailure; });
+
+}  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
new file mode 100644
index 0000000..cf449ea
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H
+
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include "1.0/Utils.h"
+#include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
+
+using NamedModel = Named<const test_helper::TestModel*>;
+using GeneratedTestParam = std::tuple<NamedDevice, NamedModel>;
+
+class GeneratedTestBase : public testing::TestWithParam<GeneratedTestParam> {
+  protected:
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(std::get<NamedDevice>(GetParam()));
+    const test_helper::TestModel& kTestModel = *getData(std::get<NamedModel>(GetParam()));
+};
+
+using FilterFn = std::function<bool(const test_helper::TestModel&)>;
+std::vector<NamedModel> getNamedModels(const FilterFn& filter);
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
+
+#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
+    INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite,                                    \
+                             testing::Combine(testing::ValuesIn(getNamedDevices()),       \
+                                              testing::ValuesIn(getNamedModels(filter))), \
+                             printGeneratedTest)
+
+// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp.
+// TODO: Clean up the hierarchy for ValidationTest.
+class ValidationTest : public GeneratedTestBase {};
+
+Model createModel(const test_helper::TestModel& testModel);
+
+}  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
+
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
deleted file mode 100644
index 4db1276..0000000
--- a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_1_vts_tests.cpp"
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp
deleted file mode 100644
index e67ef8e..0000000
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_0_vts_tests.cpp"
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/TestAssertions.cpp b/neuralnetworks/1.1/vts/functional/TestAssertions.cpp
new file mode 100644
index 0000000..f4a49bc
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/TestAssertions.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 <android/hardware/neuralnetworks/1.1/types.h>
+#include "TestHarness.h"
+
+namespace android::hardware::neuralnetworks::V1_1 {
+
+// Make sure that the HIDL enums are compatible with the values defined in
+// frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h.
+using namespace test_helper;
+#define CHECK_TEST_ENUM(EnumType, enumValue) \
+    static_assert(static_cast<EnumType>(Test##EnumType::enumValue) == EnumType::enumValue)
+
+CHECK_TEST_ENUM(OperationType, ADD);
+CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D);
+CHECK_TEST_ENUM(OperationType, CONCATENATION);
+CHECK_TEST_ENUM(OperationType, CONV_2D);
+CHECK_TEST_ENUM(OperationType, DEPTHWISE_CONV_2D);
+CHECK_TEST_ENUM(OperationType, DEPTH_TO_SPACE);
+CHECK_TEST_ENUM(OperationType, DEQUANTIZE);
+CHECK_TEST_ENUM(OperationType, EMBEDDING_LOOKUP);
+CHECK_TEST_ENUM(OperationType, FLOOR);
+CHECK_TEST_ENUM(OperationType, FULLY_CONNECTED);
+CHECK_TEST_ENUM(OperationType, HASHTABLE_LOOKUP);
+CHECK_TEST_ENUM(OperationType, L2_NORMALIZATION);
+CHECK_TEST_ENUM(OperationType, L2_POOL_2D);
+CHECK_TEST_ENUM(OperationType, LOCAL_RESPONSE_NORMALIZATION);
+CHECK_TEST_ENUM(OperationType, LOGISTIC);
+CHECK_TEST_ENUM(OperationType, LSH_PROJECTION);
+CHECK_TEST_ENUM(OperationType, LSTM);
+CHECK_TEST_ENUM(OperationType, MAX_POOL_2D);
+CHECK_TEST_ENUM(OperationType, MUL);
+CHECK_TEST_ENUM(OperationType, RELU);
+CHECK_TEST_ENUM(OperationType, RELU1);
+CHECK_TEST_ENUM(OperationType, RELU6);
+CHECK_TEST_ENUM(OperationType, RESHAPE);
+CHECK_TEST_ENUM(OperationType, RESIZE_BILINEAR);
+CHECK_TEST_ENUM(OperationType, RNN);
+CHECK_TEST_ENUM(OperationType, SOFTMAX);
+CHECK_TEST_ENUM(OperationType, SPACE_TO_DEPTH);
+CHECK_TEST_ENUM(OperationType, SVDF);
+CHECK_TEST_ENUM(OperationType, TANH);
+CHECK_TEST_ENUM(OperationType, BATCH_TO_SPACE_ND);
+CHECK_TEST_ENUM(OperationType, DIV);
+CHECK_TEST_ENUM(OperationType, MEAN);
+CHECK_TEST_ENUM(OperationType, PAD);
+CHECK_TEST_ENUM(OperationType, SPACE_TO_BATCH_ND);
+CHECK_TEST_ENUM(OperationType, SQUEEZE);
+CHECK_TEST_ENUM(OperationType, STRIDED_SLICE);
+CHECK_TEST_ENUM(OperationType, SUB);
+CHECK_TEST_ENUM(OperationType, TRANSPOSE);
+
+#undef CHECK_TEST_ENUM
+
+}  // namespace android::hardware::neuralnetworks::V1_1
diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
index b35a901..0629a1e 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
@@ -16,47 +16,40 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "GeneratedTestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
-#include "Callbacks.h"
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-
+using V1_0::ErrorStatus;
 using V1_0::IPreparedModel;
 using V1_0::Operand;
 using V1_0::OperandLifeTime;
 using V1_0::OperandType;
-
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using V1_0::implementation::PreparedModelCallback;
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
 static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
-                                           const V1_1::Model& model) {
+                                           const Model& model) {
     SCOPED_TRACE(message + " [getSupportedOperations_1_1]");
 
-    Return<void> ret =
-        device->getSupportedOperations_1_1(model, [&](ErrorStatus status, const hidl_vec<bool>&) {
-            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
-        });
+    Return<void> ret = device->getSupportedOperations_1_1(
+            model, [&](ErrorStatus status, const hidl_vec<bool>&) {
+                EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+            });
     EXPECT_TRUE(ret.isOk());
 }
 
 static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
-                                 const V1_1::Model& model, ExecutionPreference preference) {
+                                 const Model& model, ExecutionPreference preference) {
     SCOPED_TRACE(message + " [prepareModel_1_1]");
 
     sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
     Return<ErrorStatus> prepareLaunchStatus =
-        device->prepareModel_1_1(model, preference, preparedModelCallback);
+            device->prepareModel_1_1(model, preference, preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
 
@@ -77,7 +70,7 @@
 // mutation to it to invalidate the model, then pass it to interface calls that
 // use the model. Note that the model here is passed by value, and any mutation
 // to the model does not leave this function.
-static void validate(const sp<IDevice>& device, const std::string& message, V1_1::Model model,
+static void validate(const sp<IDevice>& device, const std::string& message, Model model,
                      const std::function<void(Model*)>& mutation,
                      ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
     mutation(&model);
@@ -87,36 +80,16 @@
     validatePrepareModel(device, message, model, preference);
 }
 
-// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
-// so this is efficiently accomplished by moving the element to the end and
-// resizing the hidl_vec to one less.
-template <typename Type>
-static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
-    if (vec) {
-        std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
-        vec->resize(vec->size() - 1);
-    }
-}
-
-template <typename Type>
-static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
-    // assume vec is valid
-    const uint32_t index = vec->size();
-    vec->resize(index + 1);
-    (*vec)[index] = value;
-    return index;
-}
-
 static uint32_t addOperand(Model* model) {
     return hidl_vec_push_back(&model->operands,
                               {
-                                  .type = OperandType::INT32,
-                                  .dimensions = {},
-                                  .numberOfConsumers = 0,
-                                  .scale = 0.0f,
-                                  .zeroPoint = 0,
-                                  .lifetime = OperandLifeTime::MODEL_INPUT,
-                                  .location = {.poolIndex = 0, .offset = 0, .length = 0},
+                                      .type = OperandType::INT32,
+                                      .dimensions = {},
+                                      .numberOfConsumers = 0,
+                                      .scale = 0.0f,
+                                      .zeroPoint = 0,
+                                      .lifetime = OperandLifeTime::MODEL_INPUT,
+                                      .location = {.poolIndex = 0, .offset = 0, .length = 0},
                               });
 }
 
@@ -130,13 +103,13 @@
 ///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
 
 static const int32_t invalidOperandTypes[] = {
-    static_cast<int32_t>(OperandType::FLOAT32) - 1,              // lower bound fundamental
-    static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1,  // upper bound fundamental
-    static_cast<int32_t>(OperandType::OEM) - 1,                  // lower bound OEM
-    static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1,      // upper bound OEM
+        static_cast<int32_t>(OperandType::FLOAT32) - 1,              // lower bound fundamental
+        static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1,  // upper bound fundamental
+        static_cast<int32_t>(OperandType::OEM) - 1,                  // lower bound OEM
+        static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1,      // upper bound OEM
 };
 
-static void mutateOperandTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         for (int32_t invalidOperandType : invalidOperandTypes) {
             const std::string message = "mutateOperandTypeTest: operand " +
@@ -166,7 +139,7 @@
     }
 }
 
-static void mutateOperandRankTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void mutateOperandRankTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
         const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
@@ -195,7 +168,7 @@
     }
 }
 
-static void mutateOperandScaleTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void mutateOperandScaleTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         const float invalidScale = getInvalidScale(model.operands[operand].type);
         const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
@@ -223,10 +196,10 @@
     }
 }
 
-static void mutateOperandZeroPointTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void mutateOperandZeroPointTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         const std::vector<int32_t> invalidZeroPoints =
-            getInvalidZeroPoints(model.operands[operand].type);
+                getInvalidZeroPoints(model.operands[operand].type);
         for (int32_t invalidZeroPoint : invalidZeroPoints) {
             const std::string message = "mutateOperandZeroPointTest: operand " +
                                         std::to_string(operand) + " has zero point of " +
@@ -258,18 +231,18 @@
             break;
         case OperandType::TENSOR_FLOAT32:
             newOperand.dimensions =
-                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.scale = 0.0f;
             newOperand.zeroPoint = 0;
             break;
         case OperandType::TENSOR_INT32:
             newOperand.dimensions =
-                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.zeroPoint = 0;
             break;
         case OperandType::TENSOR_QUANT8_ASYMM:
             newOperand.dimensions =
-                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
             break;
         case OperandType::OEM:
@@ -280,7 +253,7 @@
     *operand = newOperand;
 }
 
-static bool mutateOperationOperandTypeSkip(size_t operand, const V1_1::Model& model) {
+static bool mutateOperationOperandTypeSkip(size_t operand, const Model& model) {
     // LSH_PROJECTION's second argument is allowed to have any type. This is the
     // only operation that currently has a type that can be anything independent
     // from any other type. Changing the operand type to any other type will
@@ -294,7 +267,7 @@
     return false;
 }
 
-static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         if (mutateOperationOperandTypeSkip(operand, model)) {
             continue;
@@ -319,13 +292,13 @@
 ///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
 
 static const int32_t invalidOperationTypes[] = {
-    static_cast<int32_t>(OperationType::ADD) - 1,            // lower bound fundamental
-    static_cast<int32_t>(OperationType::TRANSPOSE) + 1,      // upper bound fundamental
-    static_cast<int32_t>(OperationType::OEM_OPERATION) - 1,  // lower bound OEM
-    static_cast<int32_t>(OperationType::OEM_OPERATION) + 1,  // upper bound OEM
+        static_cast<int32_t>(OperationType::ADD) - 1,            // lower bound fundamental
+        static_cast<int32_t>(OperationType::TRANSPOSE) + 1,      // upper bound fundamental
+        static_cast<int32_t>(OperationType::OEM_OPERATION) - 1,  // lower bound OEM
+        static_cast<int32_t>(OperationType::OEM_OPERATION) + 1,  // upper bound OEM
 };
 
-static void mutateOperationTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         for (int32_t invalidOperationType : invalidOperationTypes) {
             const std::string message = "mutateOperationTypeTest: operation " +
@@ -333,7 +306,7 @@
                                         std::to_string(invalidOperationType);
             validate(device, message, model, [operation, invalidOperationType](Model* model) {
                 model->operations[operation].type =
-                    static_cast<OperationType>(invalidOperationType);
+                        static_cast<OperationType>(invalidOperationType);
             });
         }
     }
@@ -341,8 +314,7 @@
 
 ///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
 
-static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device,
-                                                 const V1_1::Model& model) {
+static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const uint32_t invalidOperand = model.operands.size();
         for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
@@ -358,8 +330,7 @@
 
 ///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
 
-static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device,
-                                                  const V1_1::Model& model) {
+static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const uint32_t invalidOperand = model.operands.size();
         for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
@@ -397,7 +368,7 @@
     removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
 }
 
-static void removeOperandTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void removeOperandTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         const std::string message = "removeOperandTest: operand " + std::to_string(operand);
         validate(device, message, model,
@@ -414,7 +385,7 @@
     hidl_vec_removeAt(&model->operations, index);
 }
 
-static void removeOperationTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message = "removeOperationTest: operation " + std::to_string(operation);
         validate(device, message, model,
@@ -424,14 +395,14 @@
 
 ///////////////////////// REMOVE OPERATION INPUT /////////////////////////
 
-static void removeOperationInputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void removeOperationInputTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
-            const V1_1::Operation& op = model.operations[operation];
+            const Operation& op = model.operations[operation];
             // CONCATENATION has at least 2 inputs, with the last element being
             // INT32. Skip this test if removing one of CONCATENATION's
             // inputs still produces a valid model.
-            if (op.type == V1_1::OperationType::CONCATENATION && op.inputs.size() > 2 &&
+            if (op.type == OperationType::CONCATENATION && op.inputs.size() > 2 &&
                 input != op.inputs.size() - 1) {
                 continue;
             }
@@ -449,7 +420,7 @@
 
 ///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
 
-static void removeOperationOutputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void removeOperationOutputTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
             const std::string message = "removeOperationOutputTest: operation " +
@@ -470,7 +441,7 @@
 
 ///////////////////////// ADD OPERATION INPUT /////////////////////////
 
-static void addOperationInputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
         validate(device, message, model, [operation](Model* model) {
@@ -483,10 +454,10 @@
 
 ///////////////////////// ADD OPERATION OUTPUT /////////////////////////
 
-static void addOperationOutputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void addOperationOutputTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message =
-            "addOperationOutputTest: operation " + std::to_string(operation);
+                "addOperationOutputTest: operation " + std::to_string(operation);
         validate(device, message, model, [operation](Model* model) {
             uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
             hidl_vec_push_back(&model->operations[operation].outputs, index);
@@ -498,22 +469,23 @@
 ///////////////////////// VALIDATE EXECUTION PREFERENCE /////////////////////////
 
 static const int32_t invalidExecutionPreferences[] = {
-    static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1,        // lower bound
-    static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1,  // upper bound
+        static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1,        // lower bound
+        static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1,  // upper bound
 };
 
-static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const V1_1::Model& model) {
+static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
     for (int32_t preference : invalidExecutionPreferences) {
         const std::string message =
-            "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
-        validate(device, message, model, [](Model*) {},
-                 static_cast<ExecutionPreference>(preference));
+                "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
+        validate(
+                device, message, model, [](Model*) {},
+                static_cast<ExecutionPreference>(preference));
     }
 }
 
 ////////////////////////// ENTRY POINT //////////////////////////////
 
-void ValidationTest::validateModel(const V1_1::Model& model) {
+void validateModel(const sp<IDevice>& device, const Model& model) {
     mutateOperandTypeTest(device, model);
     mutateOperandRankTest(device, model);
     mutateOperandScaleTest(device, model);
@@ -531,9 +503,4 @@
     mutateExecutionPreferenceTest(device, model);
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
index f4adbab..9684eb2 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
@@ -16,28 +16,17 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "GeneratedTestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
-#include "Callbacks.h"
-#include "TestHarness.h"
-#include "Utils.h"
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
 
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hidl::memory::V1_0::IMemory;
-using test_helper::for_all;
-using test_helper::MixedTyped;
-using test_helper::MixedTypedExample;
+using V1_0::ErrorStatus;
+using V1_0::IPreparedModel;
+using V1_0::Request;
+using V1_0::implementation::ExecutionCallback;
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
@@ -51,7 +40,6 @@
     SCOPED_TRACE(message + " [execute]");
 
     sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-    ASSERT_NE(nullptr, executionCallback.get());
     Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
     ASSERT_TRUE(executeLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
@@ -61,26 +49,6 @@
     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
 }
 
-// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
-// so this is efficiently accomplished by moving the element to the end and
-// resizing the hidl_vec to one less.
-template <typename Type>
-static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
-    if (vec) {
-        std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
-        vec->resize(vec->size() - 1);
-    }
-}
-
-template <typename Type>
-static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
-    // assume vec is valid
-    const uint32_t index = vec->size();
-    vec->resize(index + 1);
-    (*vec)[index] = value;
-    return index;
-}
-
 ///////////////////////// REMOVE INPUT ////////////////////////////////////
 
 static void removeInputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
@@ -103,104 +71,9 @@
 
 ///////////////////////////// ENTRY POINT //////////////////////////////////
 
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples) {
-    const uint32_t INPUT = 0;
-    const uint32_t OUTPUT = 1;
-
-    std::vector<Request> requests;
-
-    for (auto& example : examples) {
-        const MixedTyped& inputs = example.operands.first;
-        const MixedTyped& outputs = example.operands.second;
-
-        std::vector<RequestArgument> inputs_info, outputs_info;
-        uint32_t inputSize = 0, outputSize = 0;
-
-        // This function only partially specifies the metadata (vector of RequestArguments).
-        // The contents are copied over below.
-        for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
-            if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
-            RequestArgument arg = {
-                .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
-                .dimensions = {},
-            };
-            RequestArgument arg_empty = {
-                .hasNoValue = true,
-            };
-            inputs_info[index] = s ? arg : arg_empty;
-            inputSize += s;
-        });
-        // Compute offset for inputs 1 and so on
-        {
-            size_t offset = 0;
-            for (auto& i : inputs_info) {
-                if (!i.hasNoValue) i.location.offset = offset;
-                offset += i.location.length;
-            }
-        }
-
-        // Go through all outputs, initialize RequestArgument descriptors
-        for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
-            if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
-            RequestArgument arg = {
-                .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
-                .dimensions = {},
-            };
-            outputs_info[index] = arg;
-            outputSize += s;
-        });
-        // Compute offset for outputs 1 and so on
-        {
-            size_t offset = 0;
-            for (auto& i : outputs_info) {
-                i.location.offset = offset;
-                offset += i.location.length;
-            }
-        }
-        std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
-                                          nn::allocateSharedMemory(outputSize)};
-        if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
-            return {};
-        }
-
-        // map pool
-        sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
-        if (inputMemory == nullptr) {
-            return {};
-        }
-        char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
-        if (inputPtr == nullptr) {
-            return {};
-        }
-
-        // initialize pool
-        inputMemory->update();
-        for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
-            char* begin = (char*)p;
-            char* end = begin + s;
-            // TODO: handle more than one input
-            std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
-        });
-        inputMemory->commit();
-
-        requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
-    }
-
-    return requests;
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    removeInputTest(preparedModel, request);
+    removeOutputTest(preparedModel, request);
 }
 
-void ValidationTest::validateRequests(const sp<IPreparedModel>& preparedModel,
-                                      const std::vector<Request>& requests) {
-    // validate each request
-    for (const Request& request : requests) {
-        removeInputTest(preparedModel, request);
-        removeOutputTest(preparedModel, request);
-    }
-}
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
index 08069f2..d56d40b 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
@@ -17,46 +17,48 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include "VtsHalNeuralnetworks.h"
-
 #include <android-base/logging.h>
+#include <hidl/ServiceManagement.h>
+#include <string>
+#include <utility>
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "GeneratedTestHarness.h"
+#include "TestHarness.h"
 
-#include "Callbacks.h"
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
+using V1_0::ErrorStatus;
+using V1_0::IPreparedModel;
+using V1_0::Request;
+using V1_0::implementation::PreparedModelCallback;
 
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-
-static void createPreparedModel(const sp<IDevice>& device, const V1_1::Model& model,
-                                sp<IPreparedModel>* preparedModel) {
+void createPreparedModel(const sp<IDevice>& device, const Model& model,
+                         sp<IPreparedModel>* preparedModel) {
     ASSERT_NE(nullptr, preparedModel);
+    *preparedModel = nullptr;
 
     // see if service can handle model
     bool fullySupportsModel = false;
-    Return<void> supportedOpsLaunchStatus = device->getSupportedOperations_1_1(
+    const Return<void> supportedCall = device->getSupportedOperations_1_1(
             model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
                 ASSERT_EQ(ErrorStatus::NONE, status);
                 ASSERT_NE(0ul, supported.size());
                 fullySupportsModel = std::all_of(supported.begin(), supported.end(),
                                                  [](bool valid) { return valid; });
             });
-    ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
+    ASSERT_TRUE(supportedCall.isOk());
 
     // launch prepare model
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
+    const sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+    const Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
             model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
 
     // retrieve prepared model
     preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
     *preparedModel = preparedModelCallback->getPreparedModel();
 
     // The getSupportedOperations_1_1 call returns a list of operations that are
@@ -68,99 +70,73 @@
     // can continue.
     if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
         ASSERT_EQ(nullptr, preparedModel->get());
-        LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
-                     "prepare model that it does not support.";
-        std::cout << "[          ]   Unable to test Request validation because vendor service "
-                     "cannot prepare model that it does not support."
+        LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare "
+                     "model that it does not support.";
+        std::cout << "[          ]   Early termination of test because vendor service cannot "
+                     "prepare model that it does not support."
                   << std::endl;
-        return;
+        GTEST_SKIP();
     }
     ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
     ASSERT_NE(nullptr, preparedModel->get());
 }
 
-// A class for test environment setup
-NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
-
-NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {}
-
-NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
-    // This has to return a "new" object because it is freed inside
-    // ::testing::AddGlobalTestEnvironment when the gtest is being torn down
-    static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
-    return instance;
-}
-
-void NeuralnetworksHidlEnvironment::registerTestServices() {
-    registerTestService<IDevice>();
-}
-
-// The main test class for NEURALNETWORK HIDL HAL.
-NeuralnetworksHidlTest::NeuralnetworksHidlTest() {}
-
-NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
-
 void NeuralnetworksHidlTest::SetUp() {
-    ::testing::VtsHalHidlTargetTestBase::SetUp();
-    device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
-            NeuralnetworksHidlEnvironment::getInstance());
-
-#ifdef PRESUBMIT_NOT_VTS
-    const std::string name =
-            NeuralnetworksHidlEnvironment::getInstance()->getServiceName<IDevice>();
-    const std::string sampleDriver = "sample-";
-    if (device == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) {
-        GTEST_SKIP();
-    }
-#endif  // PRESUBMIT_NOT_VTS
-
-    ASSERT_NE(nullptr, device.get());
+    testing::TestWithParam<NeuralnetworksHidlTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
 }
 
-void NeuralnetworksHidlTest::TearDown() {
-    device = nullptr;
-    ::testing::VtsHalHidlTargetTestBase::TearDown();
+static NamedDevice makeNamedDevice(const std::string& name) {
+    return {name, IDevice::getService(name)};
 }
 
-void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
-    validateModel(model);
+static std::vector<NamedDevice> getNamedDevicesImpl() {
+    // Retrieves the name of all service instances that implement IDevice,
+    // including any Lazy HAL instances.
+    const std::vector<std::string> names = hardware::getAllHalInstanceNames(IDevice::descriptor);
 
-    // create IPreparedModel
+    // Get a handle to each device and pair it with its name.
+    std::vector<NamedDevice> namedDevices;
+    namedDevices.reserve(names.size());
+    std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice);
+    return namedDevices;
+}
+
+const std::vector<NamedDevice>& getNamedDevices() {
+    const static std::vector<NamedDevice> devices = getNamedDevicesImpl();
+    return devices;
+}
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info) {
+    return gtestCompliantName(getName(info.param));
+}
+
+INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest);
+
+// Forward declaration from ValidateModel.cpp
+void validateModel(const sp<IDevice>& device, const Model& model);
+// Forward declaration from ValidateRequest.cpp
+void validateRequest(const sp<V1_0::IPreparedModel>& preparedModel, const V1_0::Request& request);
+
+void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request) {
+    validateModel(device, model);
+
+    // Create IPreparedModel.
     sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
 
-    validateRequests(preparedModel, requests);
+    validateRequest(preparedModel, request);
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
-
-namespace android::hardware::neuralnetworks::V1_0 {
-
-::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) {
-    return os << toString(errorStatus);
+TEST_P(ValidationTest, Test) {
+    const Model model = createModel(kTestModel);
+    const Request request = createRequest(kTestModel);
+    ASSERT_FALSE(kTestModel.expectFailure);
+    validateEverything(kDevice, model, request);
 }
 
-::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) {
-    return os << toString(deviceStatus);
-}
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
 
-}  // namespace android::hardware::neuralnetworks::V1_0
-
-using android::hardware::neuralnetworks::V1_1::vts::functional::NeuralnetworksHidlEnvironment;
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
-    ::testing::InitGoogleTest(&argc, argv);
-    NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
-
-    int status = RUN_ALL_TESTS();
-    return status;
-}
+}  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index f3f587b..e879d84 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
@@ -14,88 +14,41 @@
  * limitations under the License.
  */
 
-#ifndef VTS_HAL_NEURALNETWORKS_V1_1_H
-#define VTS_HAL_NEURALNETWORKS_V1_1_H
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H
 
-#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
 #include <android/hardware/neuralnetworks/1.1/IDevice.h>
 #include <android/hardware/neuralnetworks/1.1/types.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
-#include <android-base/macros.h>
 #include <gtest/gtest.h>
-#include <iostream>
 #include <vector>
+#include "1.0/Utils.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
 
-using V1_0::DeviceStatus;
-using V1_0::ErrorStatus;
-using V1_0::IPreparedModel;
-using V1_0::Operand;
-using V1_0::OperandType;
-using V1_0::Request;
+using NamedDevice = Named<sp<IDevice>>;
+using NeuralnetworksHidlTestParam = NamedDevice;
 
-namespace vts {
-namespace functional {
-
-// A class for test environment setup
-class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
-    NeuralnetworksHidlEnvironment();
-    ~NeuralnetworksHidlEnvironment() override;
-
-   public:
-    static NeuralnetworksHidlEnvironment* getInstance();
-    void registerTestServices() override;
-};
-
-// The main test class for NEURALNETWORKS HIDL HAL.
-class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
-
-   public:
-    NeuralnetworksHidlTest();
-    ~NeuralnetworksHidlTest() override;
+class NeuralnetworksHidlTest : public testing::TestWithParam<NeuralnetworksHidlTestParam> {
+  protected:
     void SetUp() override;
-    void TearDown() override;
-
-   protected:
-    sp<IDevice> device;
+    const sp<IDevice> kDevice = getData(GetParam());
 };
 
-// Tag for the validation tests
-class ValidationTest : public NeuralnetworksHidlTest {
-   protected:
-     void validateEverything(const Model& model, const std::vector<Request>& request);
+const std::vector<NamedDevice>& getNamedDevices();
 
-   private:
-     void validateModel(const Model& model);
-     void validateRequests(const sp<IPreparedModel>& preparedModel,
-                           const std::vector<Request>& requests);
-};
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info);
 
-// Tag for the generated tests
-class GeneratedTest : public NeuralnetworksHidlTest {};
+#define INSTANTIATE_DEVICE_TEST(TestSuite)                                                 \
+    INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \
+                             printNeuralnetworksHidlTest)
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+// Create an IPreparedModel object. If the model cannot be prepared,
+// "preparedModel" will be nullptr instead.
+void createPreparedModel(const sp<IDevice>& device, const Model& model,
+                         sp<V1_0::IPreparedModel>* preparedModel);
 
-namespace android::hardware::neuralnetworks::V1_0 {
+}  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
 
-// pretty-print values for error messages
-::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
-::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus);
-
-}  // namespace android::hardware::neuralnetworks::V1_0
-
-#endif  // VTS_HAL_NEURALNETWORKS_V1_1_H
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H
diff --git a/neuralnetworks/1.2/Android.bp b/neuralnetworks/1.2/Android.bp
index 085bda1..4aa90aa 100644
--- a/neuralnetworks/1.2/Android.bp
+++ b/neuralnetworks/1.2/Android.bp
@@ -23,4 +23,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/neuralnetworks/1.2/IDevice.hal b/neuralnetworks/1.2/IDevice.hal
index d83f9e6..ff20c12 100644
--- a/neuralnetworks/1.2/IDevice.hal
+++ b/neuralnetworks/1.2/IDevice.hal
@@ -64,14 +64,14 @@
      * results, the developer could choose an ACCELERATOR type device for ML
      * workloads, and reserve GPU for graphical rendering.
      *
-     * @param status Error status returned from querying the device type. Must be:
-     *               - NONE if the query was successful
-     *               - DEVICE_UNAVAILABLE if driver is offline or busy
-     *               - GENERAL_FAILURE if the query resulted in an
-     *                 unspecified error
-     * @param type The DeviceType of the device. Please note, this is not a
-     *             bitfield of DeviceTypes. Each device must only be of a
-     *             single DeviceType.
+     * @return status Error status returned from querying the device type. Must be:
+     *                - NONE if the query was successful
+     *                - DEVICE_UNAVAILABLE if driver is offline or busy
+     *                - GENERAL_FAILURE if the query resulted in an
+     *                  unspecified error
+     * @return type The DeviceType of the device. Please note, this is not a
+     *              bitfield of DeviceTypes. Each device must only be of a
+     *              single DeviceType.
      */
     getType() generates (ErrorStatus status, DeviceType type);
 
diff --git a/neuralnetworks/1.2/IPreparedModel.hal b/neuralnetworks/1.2/IPreparedModel.hal
index 5d2d80f..1445f18 100644
--- a/neuralnetworks/1.2/IPreparedModel.hal
+++ b/neuralnetworks/1.2/IPreparedModel.hal
@@ -47,11 +47,21 @@
      * execute_1_2 function. This callback must be provided with the ErrorStatus of
      * the execution.
      *
-     * If the prepared model was prepared from a model wherein all
-     * tensor operands have fully specified dimensions, and the inputs
-     * to the function are valid, then the execution should launch
-     * and complete successfully (ErrorStatus::NONE). There must be
-     * no failure unless the device itself is in a bad state.
+     * If the launch is successful, the caller must not change the content of
+     * any data object referenced by 'request' (described by the
+     * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}) until the
+     * asynchronous task has invoked the callback object. The asynchronous task
+     * must not change the content of any of the data objects corresponding to
+     * 'request' inputs.
+     *
+     * If the prepared model was prepared from a model wherein all tensor
+     * operands have fully specified dimensions, and the inputs to the function
+     * are valid, then:
+     * - the execution should launch successfully (ErrorStatus::NONE): There
+     *   must be no failure unless the device itself is in a bad state.
+     * - if at execution time every operation's input operands have legal
+     *   values, the execution should complete successfully (ErrorStatus::NONE):
+     *   There must be no failure unless the device itself is in a bad state.
      *
      * Any number of calls to the execute, execute_1_2, and executeSynchronously
      * functions, in any combination, may be made concurrently, even on the same
@@ -90,10 +100,17 @@
      * perform the execution, and must not return until the execution is
      * complete.
      *
+     * The caller must not change the content of any data object referenced by
+     * 'request' (described by the {@link @1.0::DataLocation} of a
+     * {@link @1.0::RequestArgument}) until executeSynchronously
+     * returns. executeSynchronously must not change the content of any of the
+     * data objects corresponding to 'request' inputs.
+     *
      * If the prepared model was prepared from a model wherein all tensor
      * operands have fully specified dimensions, and the inputs to the function
-     * are valid, then the execution should complete successfully
-     * (ErrorStatus::NONE). There must be no failure unless the device itself is
+     * are valid, and at execution time every operation's input operands have
+     * legal values, then the execution should complete successfully
+     * (ErrorStatus::NONE): There must be no failure unless the device itself is
      * in a bad state.
      *
      * Any number of calls to the execute, execute_1_2, and executeSynchronously
@@ -132,17 +149,52 @@
      * Configure a Burst object used to execute multiple inferences on a
      * prepared model in rapid succession.
      *
+     * If the prepared model was prepared from a model wherein all tensor
+     * operands have fully specified dimensions, and a valid serialized Request
+     * is sent to the Burst for execution, and at execution time every
+     * operation's input operands have legal values, then the execution should
+     * complete successfully (ErrorStatus::NONE): There must be no failure
+     * unless the device itself is in a bad state.
+     *
      * @param callback A callback object used to retrieve memory resources
-     *                 corresponding to a unique identifiers ("slots").
-     * @param requestChannel Used by the client to send a serialized Request to
-     *                       the Burst for execution. requestChannel must not be
-     *                       used to pass a second Request object until a result
-     *                       has been received from resultChannel.
-     * @param resultChannel Used by the service to return the results of an
-     *                      execution to the client: the status of the execution
-     *                      and OutputShape of all output tensors. resultChannel
-     *                      must be used to return the results if a Request was
-     *                      sent through the requestChannel.
+     *                 corresponding to unique identifiers ("slots").
+     * @param requestChannel FMQ used by the client to send a serialized Request
+     *                       to the Burst for execution. The client must not
+     *                       change the content of any data object referenced by
+     *                       the Request (described by the
+     *                       {@link @1.0::DataLocation} of an
+     *                       {@link OperandInformation}) until a result has been
+     *                       received from resultChannel. Execution must not
+     *                       change the content of any of the data objects
+     *                       corresponding to Request inputs. requestChannel
+     *                       must not be used to pass a second Request object
+     *                       until a result has been received from
+     *                       resultChannel. The client must send the request
+     *                       messages to the consumer atomically by using
+     *                       MessageQueue::writeBlocking if the queue is
+     *                       blocking, or by using MessageQueue::write if the
+     *                       queue is non-blocking. When the service receives a
+     *                       packet, it must dequeue the entire packet from the
+     *                       requestChannel. The client must not send a request
+     *                       packet that exceeds the length of the FMQ.
+     * @param resultChannel FMQ used by the service to return the results of an
+     *                      execution to the client: the status of the
+     *                      execution, OutputShape of all output tensors, and
+     *                      timing information. resultChannel must be used to
+     *                      return the results if a Request was sent through the
+     *                      requestChannel. The service must send the result
+     *                      messages to the consumer atomically by using
+     *                      MessageQueue::writeBlocking if the queue is
+     *                      blocking, or by using MessageQueue::write if the
+     *                      queue is non-blocking. When the client receives a
+     *                      packet, it must dequeue the entire packet from the
+     *                      resultChannel. If the packet's length exceeds the
+     *                      size of the FMQ, the service must not send this
+     *                      result packet; instead, the service must send a
+     *                      packet consisting of the error code
+     *                      ErrorStatus::GENERAL_FAILURE, no information for the
+     *                      outputShapes, and an indication that timing
+     *                      information is unavailable.
      * @return status Error status of configuring the execution burst, must be:
      *                - NONE if the burst is successfully configured
      *                - DEVICE_UNAVAILABLE if driver is offline or busy
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index f368ce2..b111d96 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -43,8 +43,6 @@
      *
      * Values of this operand type are either true or false. A zero value
      * represents false; any other value represents true.
-     *
-     * Available since API level 29.
      */
     BOOL = 6,
     /**
@@ -55,14 +53,10 @@
      * realValue = integerValue * scale.
      *
      * scale is a 32 bit floating point with value greater than zero.
-     *
-     * Available since API level 29.
      */
     TENSOR_QUANT16_SYMM = 7,
     /**
      * A tensor of IEEE 754 16 bit floating point values.
-     *
-     * Available since API level 29.
      */
     TENSOR_FLOAT16 = 8,
     /**
@@ -70,14 +64,10 @@
      *
      * Values of this operand type are either true or false. A zero value
      * represents false; any other value represents true.
-     *
-     * Available since API level 29.
      */
     TENSOR_BOOL8 = 9,
     /**
      * An IEEE 754 16 bit floating point scalar value.
-     *
-     * Available since API level 29.
      */
     FLOAT16 = 10,
     /**
@@ -90,14 +80,13 @@
      * - scales: an array of positive 32 bit floating point values.
      * The size of the scales array must be equal to dimensions[channelDim].
      *
+     *{@link SymmPerChannelQuantParams} must hold the parameters for an Operand of this type.
      * The channel dimension of this tensor must not be unknown (dimensions[channelDim] != 0).
      *
      * The formula is:
      * realValue[..., C, ...] =
      *     integerValue[..., C, ...] * scales[C]
      * where C is an index in the Channel dimension.
-     *
-     * Available since API level 29.
      */
     TENSOR_QUANT8_SYMM_PER_CHANNEL = 11,
     /**
@@ -110,8 +99,6 @@
      *
      * The formula is:
      * real_value = (integer_value - zeroPoint) * scale.
-     *
-     * Available since API level 29.
      */
     TENSOR_QUANT16_ASYMM = 12,
     /**
@@ -122,20 +109,19 @@
      * realValue = integerValue * scale.
      *
      * scale is a 32 bit floating point with value greater than zero.
-     *
-     * Available since API level 29.
      */
     TENSOR_QUANT8_SYMM = 13,
+
     /*
-     * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
-     * OEM operation and data types.
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
      *
      * OEM specific scalar value.
      * OEM                 = 10000,
      */
     /*
-     * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
-     * OEM operation and data types.
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
      *
      * A tensor of OEM specific values.
      * TENSOR_OEM_BYTE     = 10001,
@@ -166,6 +152,7 @@
  * The type of an operation in a model.
  */
 enum OperationType : int32_t {
+
     /**
      * Adds two tensors, element-wise.
      *
@@ -187,12 +174,12 @@
      *     input2.dimension = {5, 4, 3, 1}
      *     output.dimension = {5, 4, 3, 2}
      *
-     * Since API level 29, generic zero-sized input tensor is supported. Zero
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
      * dimension is only compatible with 0 or 1. The size of the output
      * dimension is zero if either of corresponding input dimension is zero.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -202,14 +189,16 @@
      * * 0: A tensor.
      * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
      *      as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
      * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
      *      {@link FusedActivationFunc} values. Specifies the activation to
      *      invoke on the result.
      *
      * Outputs:
      * * 0: The sum, a tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
      */
     ADD = @1.1::OperationType:ADD,
 
@@ -227,7 +216,7 @@
      *         ) / sum(1)
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -235,13 +224,14 @@
      * With the default data layout NHWC, the data is stored in the order of:
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
      *
      * Both explicit padding and implicit padding are supported.
      *
      * Inputs (explicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input. Since API level 29, zero batches is supported for this
-     *      tensor.
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
      *      the left, in the ‘width’ dimension.
      * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -263,12 +253,12 @@
      *      invoke on the result.
      * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
      *       Set to true to specify NCHW data layout for input0 and output0.
-     *       Available since API level 29.
+     *       Available since HAL version 1.2.
      *
      * Inputs (implicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input. Since API level 29, zero batches is supported for this
-     *      tensor.
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
      *      padding scheme, has to be one of the
      *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
@@ -285,13 +275,13 @@
      *      invoke on the result.
      * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth].
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     AVERAGE_POOL_2D = @1.1::OperationType:AVERAGE_POOL_2D,
 
@@ -302,33 +292,34 @@
      * dimensions except the dimension along the concatenation axis.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (full support since API
-     *   level 29, see the input section)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (full support since HAL version 1.2, see the input section)
      *
      * Supported tensor rank: up to 4
      *
      * Inputs:
      * * 0 ~ n-1: The list of n input tensors, of shape
      *            [D0, D1, ..., Daxis(i), ..., Dm].
-     *            Before API level 29, all input tensors of
+     *            Before HAL version 1.2, all input tensors of
      *            {@link OperandType::TENSOR_QUANT8_ASYMM}
      *            must have the same scale and zeroPoint as the output tensor.
-     *            Since API level 29, zero-sized tensors are supported.
+     *            Since HAL version 1.2, zero-sized tensors are supported.
      * * n: An {@link OperandType::INT32} scalar, specifying the
      *      concatenation axis.
      *
      * Outputs:
      * * 0: The output, a tensor of the same {@link OperandType} as the input
      *      tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm].
-     *
-     * Available since API level 27.
+     *      Since HAL version 1.2, for a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint values can be different from
+     *      input tensors. Before HAL version 1.2 they have to be the same as for the input tensors.
      */
     CONCATENATION = @1.1::OperationType:CONCATENATION,
 
     /**
-     * Performs an 2-D convolution operation.
+     * Performs a 2-D convolution operation.
      *
      * The CONV_2D op sweeps a 2-D filter that can mix channels together over a
      * batch of images, applying the filter to each window of each image of the
@@ -354,7 +345,7 @@
      * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
      * * * input.scale * filter.scale).
      *
-     * Available since API level 29:
+     * Available since HAL version 1.2:
      * * 16 bit floating point:
      * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
      *
@@ -368,27 +359,29 @@
      * With the default data layout NHWC, the data is stored in the order of:
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
      *
      * Both explicit padding and implicit padding are supported.
      *
      * Inputs (explicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
-     *      specifying the input. Since API level 29, zero batches is supported
-     *      for this tensor.
+     *      specifying the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
      * * 1: A 4-D tensor, of shape
      *      [depth_out, filter_height, filter_width, depth_in], specifying the
-     *      filter. For tensor of type
-     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
-     *      dimension (extraParams.channelQuant.channelDim) must be set to 0.
+     *      filter.
+     *      For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 0.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
-     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
-     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
      *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
-     *      of 0 and bias_scale == input_scale * filter_scale. For filter tensor
-     *      of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
-     *      should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
-     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
      *      bias_scale[i] = input_scale * filter_scale[i].
      * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
      *      the left, in the ‘width’ dimension.
@@ -407,36 +400,37 @@
      *      invoke on the result.
      * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      * * 11: An optional {@link OperandType::INT32} scalar, specifying the dilation
      *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
      *      cells between each filter element on width dimension. If this input is set,
      *      input 12 (dilation factor for height) must be specified as well.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      * * 12: An optional {@link OperandType::INT32} scalar, specifying the dilation
      *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
      *      cells between each filter element on height dimension. If this input is set,
      *      input 11 (dilation factor for width) must be specified as well.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Inputs (implicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
-     *      specifying the input. Since API level 29, zero batches is supported
-     *      for this tensor.
+     *      specifying the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
      * * 1: A 4-D tensor, of shape
      *      [depth_out, filter_height, filter_width, depth_in], specifying the
-     *      filter. For tensor of type
-     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
-     *      dimension (extraParams.channelQuant.channelDim) must be set to 0.
+     *      filter.
+     *      For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 0.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
-     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
-     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
      *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
-     *      of 0 and bias_scale == input_scale * filter_scale. For filter tensor
-     *      of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
-     *      should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
-     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
      *      bias_scale[i] = input_scale * filter_scale[i].
      * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
      *      padding scheme, has to be one of the
@@ -450,26 +444,23 @@
      *      invoke on the result.
      * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      * * 8: An optional {@link OperandType::INT32} scalar, specifying the dilation
      *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
      *      cells between each filter element on width dimension. If this input is set,
      *      input 9 (dilation factor for height) must be specified as well.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      * * 9: An optional {@link OperandType::INT32} scalar, specifying the dilation
      *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
      *      cells between each filter element on height dimension. If this input is set,
      *      input 8 (dilation factor for width) must be specified as well.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
-     *      [batches, out_height, out_width, depth_out]. Before API level 29,
-     *      for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the
-     *      following condition must be satisfied:
-     *      output_scale > input_scale * filter_scale
-     *
-     * Available since API level 27.
+     *      [batches, out_height, out_width, depth_out].
+     *      Before HAL version 1.2, for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the following condition must be satisfied: output_scale > input_scale * filter_scale
      */
     CONV_2D = @1.1::OperationType:CONV_2D,
 
@@ -504,7 +495,7 @@
      * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
      * * * input.scale * filter.scale).
      *
-     * Available since API level 29:
+     * Available since HAL version 1.2:
      * * 16 bit floating point:
      * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
      *
@@ -518,6 +509,7 @@
      * With the default data layout NHWC, the data is stored in the order of:
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
      *
      * Both explicit padding and implicit padding are supported.
      *
@@ -525,18 +517,19 @@
      * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
      *      specifying the input.
      * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
-     *      specifying the filter. For tensor of type
-     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
-     *      dimension (extraParams.channelQuant.channelDim) must be set to 3.
+     *      specifying the filter.
+     *      For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 3.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
-     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
-     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
      *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
-     *      of 0 and bias_scale == input_scale * filter_scale. For filter tensor
-     *      of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
-     *      should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
-     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
      *      bias_scale[i] = input_scale * filter_scale[i].
      * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
      *      the left, in the ‘width’ dimension.
@@ -557,17 +550,17 @@
      *       invoke on the result.
      * * 11: An optional {@link OperandType::BOOL} scalar, default to false.
      *       Set to true to specify NCHW data layout for input0 and output0.
-     *       Available since API level 29.
+     *       Available since HAL version 1.2.
      * * 12: An optional {@link OperandType::INT32} scalar, specifying the dilation
      *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
      *      cells between each filter element on width dimension. If this input is set,
      *      input 13 (dilation factor for height) must be specified as well.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      * * 13: An optional {@link OperandType::INT32} scalar, specifying the dilation
      *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
      *      cells between each filter element on height dimension. If this input is set,
      *      input 12 (dilation factor for width) must be specified as well.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Inputs (implicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
@@ -575,14 +568,14 @@
      * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
      *      specifying the filter.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
-     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
-     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
      *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
-     *      of 0 and bias_scale == input_scale * filter_scale. For filter tensor
-     *      of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
-     *      should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
-     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
      *      bias_scale[i] = input_scale * filter_scale[i].
      * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
      *      padding scheme, has to be one of the
@@ -598,27 +591,24 @@
      *      invoke on the result.
      * * 8: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      * * 9: An optional {@link OperandType::INT32} scalar, specifying the dilation
      *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
      *      cells between each filter element on width dimension. If this input is set,
      *      input 10 (dilation factor for height) must be specified as well.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      * * 10: An optional {@link OperandType::INT32} scalar, specifying the dilation
      *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
      *      cells between each filter element on height dimension. If this input is set,
      *      input 9 (dilation factor for width) must be specified as well.
-     *      Available since API level 29.
-
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
-     *      [batches, out_height, out_width, depth_out]. Before API level 29,
-     *      for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the
-     *      following condition must be satisfied:
+     *      [batches, out_height, out_width, depth_out]. Before HAL version 1.2, for
+     *      output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the following condition must be satisfied:
      *      output_scale > input_scale * filter_scale
-     *
-     * Available since API level 27.
      */
     DEPTHWISE_CONV_2D = @1.1::OperationType:DEPTHWISE_CONV_2D,
 
@@ -638,7 +628,7 @@
      * be divisible by block_size * block_size
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -646,6 +636,7 @@
      * With the default data layout NHWC, the data is stored in the order of:
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
      *
      * Inputs:
      * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
@@ -655,13 +646,13 @@
      *      of the input depth.
      * * 2: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape [batch, height*block_size,
      *      width*block_size, depth/(block_size*block_size)].
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     DEPTH_TO_SPACE = @1.1::OperationType:DEPTH_TO_SPACE,
 
@@ -674,22 +665,21 @@
      *
      * Supported input tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
-     * * {@link OperandType::TENSOR_QUANT8_SYMM} (since API level 29)
-     * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} (since API level 29)
+     * * {@link OperandType::TENSOR_QUANT8_SYMM} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} (since HAL version 1.2)
      *
      * Supported output tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}.
      *
      * Supported tensor rank: up to 4
      *
      * Inputs:
-     * * 0: A tensor. Since API level 29, this tensor may be zero-sized.
+     * * 0: A tensor.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
      *
      * Outputs:
      * * 0: A tensor with the same shape as input0.
-     *
-     * Available since API level 27.
      */
     DEQUANTIZE = @1.1::OperationType:DEQUANTIZE,
 
@@ -730,8 +720,8 @@
      * * 0: A n-D tensor with the same rank and shape as the Values
      *      tensor, except for the first dimension which has the same size
      *      as Lookups' only dimension.
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input1.
      */
     EMBEDDING_LOOKUP = @1.1::OperationType:EMBEDDING_LOOKUP,
 
@@ -739,7 +729,7 @@
      * Computes element-wise floor() on the input tensor.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      *
      * Supported tensor rank: up to 4
@@ -750,8 +740,6 @@
      * Outputs:
      * * 0: The output tensor, of the same {@link OperandType} and dimensions as
      *      the input tensor.
-     *
-     * Available since API level 27.
      */
     FLOOR = @1.1::OperationType:FLOOR,
 
@@ -764,7 +752,7 @@
      *     outputs = activation(inputs * weights’ + bias)
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -777,8 +765,8 @@
      *      [batch_size, input_size], where "input_size" corresponds to the
      *      number of inputs to the layer, matching the second dimension of
      *      weights, and "batch_size" is calculated by dividing the number of
-     *      elements by "input_size". Since API level 29, zero batch_size is
-     *      supported for this tensor.
+     *      elements by "input_size".
+     *      Since HAL version 1.2, zero batch_size is supported for this tensor.
      * * 1: A 2-D tensor, specifying the weights, of shape
      *      [num_units, input_size], where "num_units" corresponds to the number
      *      of output nodes.
@@ -793,12 +781,9 @@
      *      invoke on the result.
      *
      * Outputs:
-     * * 0: The output tensor, of shape [batch_size, num_units]. Before API
-     *      level 29, For output tensor of {@link
-     *      OperandType::TENSOR_QUANT8_ASYMM}, the following condition must be
-     *      satisfied: output_scale > input_scale * filter_scale.
-     *
-     * Available since API level 27.
+     * * 0: The output tensor, of shape [batch_size, num_units]. Before HAL version 1.2, for
+     *      output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following
+     *      condition must be satisfied: output_scale > input_scale * filter_scale.
      */
     FULLY_CONNECTED = @1.1::OperationType:FULLY_CONNECTED,
 
@@ -849,13 +834,13 @@
      *
      * Outputs:
      * * 0: Output. A tensor with shape [ k …].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input2.
      * * 1: Hits. A boolean tensor with shape [ k ] indicates whether the lookup
      *      hits (True) or not (False).
      *      Stored as {@link OperandType::TENSOR_QUANT8_ASYMM} with offset 0
      *      and scale 1.0f.
      *      A non-zero byte represents True, a hit. A zero indicates otherwise.
-     *
-     * Available since API level 27.
      */
     HASHTABLE_LOOKUP = @1.1::OperationType:HASHTABLE_LOOKUP,
 
@@ -872,12 +857,12 @@
      * 1-D slice along dimension dim.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since API level 29)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
      *
      * Supported tensor rank: up to 4
-     * Tensors with rank less than 4 are only supported since API level 29.
+     * Tensors with rank less than 4 are only supported since HAL version 1.2.
      *
      * Inputs:
      * * 0: An n-D tensor, specifying the tensor to be normalized.
@@ -885,14 +870,12 @@
      *      specifying the dimension normalization would be performed on.
      *      Negative index is used to specify axis from the end (e.g. -1 for
      *      the last axis). Must be in the range [-n, n).
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} and same shape as input0.
      *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the scale must be 1.f / 128 and the zeroPoint must be 128.
-     *
-     * Available since API level 27.
      */
     L2_NORMALIZATION = @1.1::OperationType:L2_NORMALIZATION,
 
@@ -909,20 +892,21 @@
      *              sum(1))
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
      *
      * Both explicit padding and implicit padding are supported.
      *
      * Inputs (explicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input. Since API level 29, zero batches is supported for this
-     *      tensor.
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
      *      the left, in the ‘width’ dimension.
      * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -944,12 +928,12 @@
      *      invoke on the result.
      * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
      *       Set to true to specify NCHW data layout for input0 and output0.
-     *       Available since API level 29.
+     *       Available since HAL version 1.2.
      *
      * Inputs (implicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input. Since API level 29, zero batches is supported for this
-     *      tensor.
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
      *      padding scheme, has to be one of the
      *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
@@ -966,13 +950,11 @@
      *      invoke on the result.
      * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth].
-     *
-     * Available since API level 27.
      */
     L2_POOL_2D = @1.1::OperationType:L2_POOL_2D,
 
@@ -994,11 +976,11 @@
      * 1-D slice along specified dimension.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      *
      * Supported tensor rank: up to 4
-     * Tensors with rank less than 4 are only supported since API level 29.
+     * Tensors with rank less than 4 are only supported since HAL version 1.2.
      *
      * Inputs:
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
@@ -1011,10 +993,10 @@
      *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias
      *      value must be of {@link OperandType::FLOAT32}.
      * * 3: A scalar, specifying the scale factor, alpha.
-     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the alpha
-     *      value must be of {@link OperandType::FLOAT16}.
-     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the alpha
-     *      value must be of {@link OperandType::FLOAT32}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the
+     *      alpha value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the
+     *      alpha value must be of {@link OperandType::FLOAT32}.
      * * 4: A scalar, specifying the exponent, beta.
      *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the beta
      *      value must be of {@link OperandType::FLOAT16}.
@@ -1024,12 +1006,10 @@
      *      specifying the dimension normalization would be performed on.
      *      Negative index is used to specify axis from the end (e.g. -1 for
      *      the last axis). Must be in the range [-n, n).
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 27.
      */
     LOCAL_RESPONSE_NORMALIZATION = @1.1::OperationType:LOCAL_RESPONSE_NORMALIZATION,
 
@@ -1041,22 +1021,20 @@
      *     output = 1 / (1 + exp(-input))
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
      * Supported tensor rank: up to 4.
      *
      * Inputs:
-     * * 0: A tensor, specifying the input. Since API level 29, this tensor may
-     *      be zero-sized.
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
      *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the scale must be 1.f / 256 and the zeroPoint must be 0.
-     *
-     * Available since API level 27.
      */
     LOGISTIC = @1.1::OperationType:LOGISTIC,
 
@@ -1064,7 +1042,7 @@
      * Projects an input to a bit vector via locality senstive hashing.
      *
      * Supported input tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_INT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
@@ -1086,7 +1064,7 @@
      *      Tensor[1].Dim[0] == Tensor[2].Dim[0]
      * * 3: Type:
      *        Sparse:
-     *          Value LSHProjectionType_SPARSE(=3) (since API level 29).
+     *          Value LSHProjectionType_SPARSE(=3) (since HAL version 1.2).
      *          Computed bit vector is considered to be sparse.
      *          Each output element is an int32 made up of multiple bits
      *          computed from hash functions.
@@ -1107,14 +1085,12 @@
      * Outputs:
      * * 0: If the projection type is Sparse:
      *      Output.Dim == { Tensor[0].Dim[0] }
-     *      A tensor of int32 that represents hash signatures,
+     *      A tensor of int32 that represents hash signatures.
      *
      *      If the projection type is Dense:
      *      Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] }
      *      A flattened tensor that represents projected bit vectors.
-     *
-     * Available since API level 27.
-     * The offset value for sparse projections was added in API level 29.
+     * The offset value for sparse projections was added in HAL version 1.2.
      */
     LSH_PROJECTION = @1.1::OperationType:LSH_PROJECTION,
 
@@ -1170,7 +1146,7 @@
      *   matrix, each element of which is the product of the corresponding
      *   elements of the input matrices.
      *
-     * Since API level 29 LSTM supports layer normalization.
+     * Since HAL version 1.2 LSTM supports layer normalization.
      * In case layer normalization is used, the inputs to internal activation
      * functions (sigmoid and \f$g\f$) are normalized, rescaled and recentered
      * following an approach from section 3.1 from
@@ -1197,7 +1173,7 @@
      * * The projection bias (\f$b_{proj}\f$) may (but not required to) have a
      *   value if the recurrent projection layer exists, and should otherwise
      *   have no value.
-     * * (API level >= 29) The four layer normalization weights either all have
+     * * (HAL version 1.2 or later) The four layer normalization weights either all have
      *   values or none of them have values. Additionally, if CIFG is used,
      *   input layer normalization weights tensor is omitted and the other layer
      *   normalization weights either all have values or none of them have
@@ -1228,7 +1204,7 @@
      * Jimmy Ba et al. "Layer Normalization"
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      *
      * All input and output tensors must be of the same type.
@@ -1291,24 +1267,24 @@
      * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such
      *      that values are bound within [-cell_clip, cell_clip]. If set to 0.0
      *      then clipping is disabled.
-     *      Until API level 29 this scalar must be of type {@link
-     *      FLOAT32}. Since API level 29, if all the input
+     *      Until HAL version 1.2 this scalar must be of type {@link
+     *      OperandType::FLOAT32}. Since HAL version 1.2, if all the input
      *      tensors have type {@link OperandType::TENSOR_FLOAT32}, this
      *      scalar must be of the type {@link OperandType::FLOAT32},
      *      otherwise if all the input tensors have the type {@link
-     *      TENSOR_FLOAT16}, this scalar must be of type {@link
-     *      FLOAT16}.
+     *      OperandType::TENSOR_FLOAT16}, this scalar must be of type {@link
+     *      OperandType::FLOAT16}.
      * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the
      *      projection layer, such that values are bound within
      *      [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
-     *      Until API level 29 this scalar must be of type {@link
-     *      FLOAT32}. Since API level 29, if all the input
+     *      Until HAL version 1.2 this scalar must be of type {@link
+     *      OperandType::FLOAT32}. Since HAL version 1.2, if all the input
      *      tensors have type {@link OperandType::TENSOR_FLOAT32}, this
      *      scalar must be of the type {@link OperandType::FLOAT32},
      *      otherwise if all the input tensors have the type {@link
-     *      TENSOR_FLOAT16}, this scalar must be of type {@link
-     *      FLOAT16}.
-     * Since API level 29 there are additional inputs to this op:
+     *      OperandType::TENSOR_FLOAT16}, this scalar must be of type {@link
+     *      OperandType::FLOAT16}.
+     * Since HAL version 1.2 there are additional inputs to this op:
      * * 23:The input layer normalization weights.
      *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
      *      to activation at input gate.
@@ -1333,8 +1309,6 @@
      * * 3: The output (\f$o_t\f$).
      *      A 2-D tensor of shape [batch_size, output_size]. This is effectively
      *      the same as the current “output state (out)” value.
-     *
-     * Available since API level 27.
      */
     LSTM = @1.1::OperationType:LSTM,
 
@@ -1352,7 +1326,7 @@
      *         )
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -1360,13 +1334,14 @@
      * With the default data layout NHWC, the data is stored in the order of:
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
      *
      * Both explicit padding and implicit padding are supported.
      *
      * Inputs (explicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input. Since API level 29, zero batches is supported for this
-     *      tensor.
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
      *      the left, in the ‘width’ dimension.
      * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -1388,12 +1363,12 @@
      *      invoke on the result.
      * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
      *       Set to true to specify NCHW data layout for input0 and output0.
-     *       Available since API level 29.
+     *       Available since HAL version 1.2.
      *
      * Inputs (implicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input. Since API level 29, zero batches is supported for this
-     *      tensor.
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
      *      padding scheme, has to be one of the
      *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
@@ -1410,13 +1385,13 @@
      *      invoke on the result.
      * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth].
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     MAX_POOL_2D = @1.1::OperationType:MAX_POOL_2D,
 
@@ -1435,15 +1410,15 @@
      * of the input operands. It starts with the trailing dimensions, and works
      * its way forward.
      *
-     * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
-     * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
-     *
-     * Since API level 29, generic zero-sized input tensor is supported. Zero
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
      * dimension is only compatible with 0 or 1. The size of the output
      * dimension is zero if either of corresponding input dimension is zero.
      *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
      * Supported tensor rank: up to 4
      *
      * Inputs:
@@ -1459,8 +1434,6 @@
      *      For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the following condition must be satisfied:
      *      output_scale > input1_scale * input2_scale.
-     *
-     * Available since API level 27.
      */
     MUL = @1.1::OperationType:MUL,
 
@@ -1472,20 +1445,20 @@
      *     output = max(0, input)
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
      * Supported tensor rank: up to 4.
      *
      * Inputs:
-     * * 0: A tensor, specifying the input. Since API level 29, this tensor may
-     *      be zero-sized.
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     RELU = @1.1::OperationType:RELU,
 
@@ -1497,20 +1470,20 @@
      *     output = min(1.f, max(-1.f, input))
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
      * Supported tensor rank: up to 4.
      *
      * Inputs:
-     * * 0: A tensor, specifying the input. Since API level 29, this tensor may
-     *      be zero-sized.
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
      *
      * Outputs:
-     * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 27.
+     * * 0: The output tensor of the same shape as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     RELU1 = @1.1::OperationType:RELU1,
 
@@ -1522,20 +1495,20 @@
      *     output = min(6, max(0, input))
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
      * Supported tensor rank: up to 4.
      *
      * Inputs:
-     * * 0: A tensor, specifying the input. Since API level 29, this tensor may
-     *      be zero-sized.
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     RELU6 = @1.1::OperationType:RELU6,
 
@@ -1546,7 +1519,7 @@
      * tensor, but with a newly specified shape.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -1565,8 +1538,8 @@
      *
      * Outputs:
      * * 0: The output tensor, of shape specified by the input shape.
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     RESHAPE = @1.1::OperationType:RESHAPE,
 
@@ -1578,30 +1551,31 @@
      * same as corner pixels of input.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since API level 29)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
      *
      * Both resizing by shape and resizing by scale are supported.
      *
      * Inputs (resizing by shape):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input. Since API level 29, zero batches is supported for this
-     *      tensor.
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the output
      *      width of the output tensor.
      * * 2: An {@link OperandType::INT32} scalar, specifying the output
      *      height of the output tensor.
      * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
-     * Inputs (resizing by scale, since API level 29):
+     * Inputs (resizing by scale, since HAL version 1.2):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
      *      the input. Zero batches is supported for this tensor.
      * * 1: A scalar, specifying width_scale, the scaling factor of the width
@@ -1622,8 +1596,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, new_height, new_width, depth].
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     RESIZE_BILINEAR = @1.1::OperationType:RESIZE_BILINEAR,
 
@@ -1644,7 +1618,7 @@
      *   argument (if not “NONE”).
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      *
      * The input tensors must all be the same type.
@@ -1676,8 +1650,6 @@
      * * 1: output.
      *      A 2-D tensor of shape [batch_size, num_units]. This is effectively
      *      the same as the current state value.
-     *
-     * Available since API level 27.
      */
     RNN = @1.1::OperationType:RNN,
 
@@ -1696,34 +1668,32 @@
      * independently on each 1-D slice along specified dimension.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
      * Supported tensor rank: up to 4.
-     * Tensors with rank other than 2 or 4 are only supported since API level 29.
+     * Tensors with rank other than 2 or 4 are only supported since HAL version 1.2.
      *
      * Inputs:
-     * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped. Since
-     *      API level 29, this tensor may be zero-sized.
+     * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
      * * 1: A scalar, specifying the positive scaling factor for the exponent,
      *      beta. If input0 is of {@link OperandType::TENSOR_FLOAT32} or
      *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the scalar must be of
-     *      {@link OperandType::FLOAT32}. If input0 is of {@link
-     *      OperandType::TENSOR_FLOAT16}, then the scalar must be of {@link
-     *      OperandType::FLOAT16}.
+     *      {@link OperandType::FLOAT32}.
+     *      If input0 is of {@link OperandType::TENSOR_FLOAT16}, then the
+     *      scalar must be of {@link OperandType::FLOAT16}.
      * * 2: An optional {@link OperandType::INT32} scalar, default to -1,
      *      specifying the dimension the activation would be performed on.
      *      Negative index is used to specify axis from the end (e.g. -1 for
      *      the last axis). Must be in the range [-n, n).
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
      *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the scale must be 1.f / 256 and the zeroPoint must be 0.
-     *
-     * Available since API level 27.
      */
     SOFTMAX = @1.1::OperationType:SOFTMAX,
 
@@ -1742,7 +1712,7 @@
      * The input tensor's height and width must be divisible by block_size.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -1750,6 +1720,7 @@
      * With the default data layout NHWC, the data is stored in the order of:
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
      *
      * Inputs:
      * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
@@ -1759,13 +1730,13 @@
      *      input height and width.
      * * 2: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape [batches, height/block_size,
      *      width/block_size, depth_in*block_size*block_size].
-     *
-     * Available since API level 27.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     SPACE_TO_DEPTH = @1.1::OperationType:SPACE_TO_DEPTH,
 
@@ -1809,7 +1780,7 @@
      * the filters.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      *
      * All input tensors must be the same type.
@@ -1843,8 +1814,6 @@
      * * 1: output.
      *      A 2-D tensor of the same {@link OperandType} as the inputs, with shape
      *      [batch_size, num_units].
-     *
-     * Available since API level 27.
      */
     SVDF = @1.1::OperationType:SVDF,
 
@@ -1856,22 +1825,20 @@
      *     output = tanh(input)
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since API level 29)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
      *
      * Supported tensor rank: up to 4.
      *
      * Inputs:
-     * * 0: A tensor, specifying the input. Since API level 29, this tensor may
-     *      be zero-sized.
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
      *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the scale must be 1.f / 128 and the zeroPoint must be 128.
-     *
-     * Available since API level 27.
      */
     TANH = @1.1::OperationType:TANH,
 
@@ -1886,7 +1853,7 @@
      * This is the reverse of SpaceToBatch.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -1894,6 +1861,7 @@
      * With the default data layout NHWC, the data is stored in the order of:
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
      *
      * Inputs:
      * * 0: An n-D tensor, specifying the tensor to be reshaped
@@ -1906,8 +1874,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     BATCH_TO_SPACE_ND = @1.1::OperationType:BATCH_TO_SPACE_ND,
 
@@ -1931,12 +1899,12 @@
      *     input2.dimension = {5, 4, 3, 1}
      *     output.dimension = {5, 4, 3, 2}
      *
-     * Since API level 29, generic zero-sized input tensor is supported. Zero
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
      * dimension is only compatible with 0 or 1. The size of the output
      * dimension is zero if either of corresponding input dimension is zero.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      *
      * Supported tensor rank: up to 4
@@ -1951,8 +1919,6 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
      */
     DIV = @1.1::OperationType:DIV,
 
@@ -1965,7 +1931,7 @@
      * length 1.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -1987,21 +1953,21 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     MEAN = @1.1::OperationType:MEAN,
 
     /**
-     * Pads a tensor with zeros.
+     * Pads a tensor.
      *
      * This operation pads a tensor according to the specified paddings.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (full support since API
-     *   level 29, see the output section)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (full support since HAL version 1.2, see the output section)
      *
      * Supported tensor rank: up to 4
      *
@@ -2023,12 +1989,12 @@
      *      of the padding:
      *          output0.dimension[i] =
      *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      *
-     *      NOTE: Before API level 29, the pad value for
-     *      {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} is undefined.
-     *      Since API level 29, the pad value is always the logical zero.
-     *
-     * Available since API level 28.
+     *      NOTE: Before HAL version 1.2, the pad value for
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} is undefined.
+     *      Since HAL version 1.2, the pad value is always the logical zero.
      */
     PAD = @1.1::OperationType:PAD,
 
@@ -2044,14 +2010,16 @@
      * dimensions of the input are optionally zero padded according to paddings.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (full support since HAL version 1.2, see the output section)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
      *
      * Inputs:
      * * 0: An n-D tensor, specifying the input.
@@ -2068,12 +2036,16 @@
      *      end of dimension i.
      * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
-     *      Available since API level 29.
+     *      Available since HAL version 1.2.
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      *
-     * Available since API level 28.
+     *      NOTE: Before HAL version 1.2, the pad value for
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} is undefined.
+     *      Since HAL version 1.2, the pad value is always the logical zero.
      */
     SPACE_TO_BATCH_ND = @1.1::OperationType:SPACE_TO_BATCH_ND,
 
@@ -2086,7 +2058,7 @@
      * dimensions by specifying the axes (input1).
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -2104,8 +2076,8 @@
      * * 0: A tensor of the same {@link OperandType} as input0. Contains the
      *      same data as input, but has one or more dimensions of size 1
      *      removed.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     SQUEEZE = @1.1::OperationType:SQUEEZE,
 
@@ -2119,7 +2091,7 @@
      * reverse slice.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -2151,8 +2123,8 @@
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0 and rank (n - k),
      *      where k is the number of bits set in shrink_axis_mask.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     STRIDED_SLICE = @1.1::OperationType:STRIDED_SLICE,
 
@@ -2176,14 +2148,14 @@
      *     input2.dimension = {5, 4, 3, 1}
      *     output.dimension = {5, 4, 3, 2}
      *
-     * Since API level 29, generic zero-sized input tensor is supported. Zero
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
      * dimension is only compatible with 0 or 1. The size of the output
      * dimension is zero if either of corresponding input dimension is zero.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since API level 29)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
      *
      * Supported tensor rank: up to 4
      *
@@ -2197,8 +2169,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
      */
     SUB = @1.1::OperationType:SUB,
 
@@ -2212,7 +2184,7 @@
      * regular matrix transpose on 2-D input Tensors.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -2220,14 +2192,14 @@
      *
      * Inputs:
      * * 0: An n-D tensor, specifying the tensor to be transposed.
-     *      Since API level 29, this tensor may be zero-sized.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
      * * 1: An optional 1-D Tensor of {@link OperandType::TENSOR_INT32},
      *      the permutation of the dimensions of the input tensor.
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 28.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     TRANSPOSE = @1.1::OperationType:TRANSPOSE,
 
@@ -2245,8 +2217,6 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 29.
      */
     ABS = 38,
 
@@ -2269,8 +2239,6 @@
      *
      * Outputs:
      * * 0: An (n - 1)-D {@link OperandType::TENSOR_INT32} tensor.
-     *
-     * Available since API level 29.
      */
     // There is no underscore in ARG_MAX to avoid name conflict with
     // the macro defined in libc/kernel/uapi/linux/limits.h.
@@ -2295,8 +2263,6 @@
      *
      * Outputs:
      * * 0: An (n - 1)-D {@link OperandType::TENSOR_INT32} tensor.
-     *
-     * Available since API level 29.
      */
     ARGMIN = 40,  // See ARGMAX for naming discussion.
 
@@ -2341,8 +2307,8 @@
      * * 0: A tensor of the same {@link OperandType} as input0, with shape
      *      [num_rois, num_classes * 4], specifying the coordinates of each
      *      output bounding box for each class, with format [x1, y1, x2, y2].
-     *
-     * Available since API level 29.
+     *      For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the
+     *      scale must be 0.125 and the zero point must be 0.
      */
     AXIS_ALIGNED_BBOX_TRANSFORM = 41,
 
@@ -2482,17 +2448,17 @@
      *       then clipping is disabled.
      *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
      *       this scalar must be of the type {@link OperandType::FLOAT32},
-     *       otherwise if all the input tensors have the type {@link
-     *       TENSOR_FLOAT16}, this scalar must be of type {@link
-     *       FLOAT16}.
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
      * * 50: The clipping threshold for the output from the
      *       projection layer, such that values are bound within
      *       [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
      *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
      *       this scalar must be of the type {@link OperandType::FLOAT32},
-     *       otherwise if all the input tensors have the type {@link
-     *       TENSOR_FLOAT16}, this scalar must be of type {@link
-     *       FLOAT16}.
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
      * * 51: merge_outputs
      *       An {@link OperandType::BOOL} scalar specifying if the outputs
      *       from forward and backward cells should be merged.
@@ -2539,8 +2505,6 @@
      *      A 3-D tensor of shape:
      *        If time-major: [max_time, batch_size, bw_output_size]
      *        If batch-major: [batch_size, max_time, bw_output_size]
-     *
-     * Available since API level 29.
      */
     BIDIRECTIONAL_SEQUENCE_LSTM = 42,
 
@@ -2658,8 +2622,6 @@
      *      (timeMajor). If it is set to true, then the shape is set to
      *      [maxTime, batchSize, bwNumUnits], otherwise the shape is set to
      *      [batchSize, maxTime, bwNumUnits].
-     *
-     * Available since API level 29.
      */
     BIDIRECTIONAL_SEQUENCE_RNN = 43,
 
@@ -2737,8 +2699,6 @@
      * * 3: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
      *      [num_output_rois], specifying the batch index of each box. Boxes
      *      with the same batch index are grouped together.
-     *
-     * Available since API level 29.
      */
     BOX_WITH_NMS_LIMIT = 44,
 
@@ -2762,8 +2722,6 @@
      *
      * Outputs:
      * * 0: A tensor with the same shape as input0.
-     *
-     * Available since API level 29.
      */
     CAST = 45,
 
@@ -2800,8 +2758,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} and same shape as input0.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     CHANNEL_SHUFFLE = 46,
 
@@ -2856,14 +2814,14 @@
      * * 11: A scalar, score_threshold. Boxes with scores lower than the
      *       threshold are filtered before sending to the NMS algorithm. The
      *       scalar must be of {@link OperandType::FLOAT16} if input0 is of
-     *       {@link OperandType::TENSOR_FLOAT16} and of {@link
-     *       OperandType::FLOAT32} if input0 is of {@link
-     *       OperandType::TENSOR_FLOAT32}.
+     *       {@link OperandType::TENSOR_FLOAT16} and of
+     *       {@link OperandType::FLOAT32} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT32}.
      * * 12: A scalar, specifying the IoU threshold for hard NMS. The scalar
-     *       must be of {@link OperandType::FLOAT16} if input0 is of {@link
-     *       OperandType::TENSOR_FLOAT16} and of {@link
-     *       OperandType::FLOAT32} if input0 is of {@link
-     *       OperandType::TENSOR_FLOAT32}.
+     *       must be of {@link OperandType::FLOAT16} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT16} and of
+     *       {@link OperandType::FLOAT32} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT32}.
      * * 13: An {@link OperandType::BOOL} scalar, set to true to include
      *       background class in the list of label map for the output, set
      *       to false to not include the background. When the background
@@ -2882,8 +2840,6 @@
      *      output detection.
      * * 3: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape [batches],
      *      specifying the number of valid output detections for each batch.
-     *
-     * Available since API level 29.
      */
     DETECTION_POSTPROCESSING = 47,
 
@@ -2908,8 +2864,6 @@
      *
      * Outputs:
      * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
-     *
-     * Available since API level 29.
      */
     EQUAL = 48,
 
@@ -2927,8 +2881,6 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 29.
      */
     EXP = 49,
 
@@ -2956,8 +2908,8 @@
      * Outputs:
      * * 0: An (n + 1)-D tensor with the same {@link OperandType} and data as
      *      input0.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     EXPAND_DIMS = 50,
 
@@ -2994,8 +2946,8 @@
      *
      * Outputs:
      * * 0: An (n + k - 1)-D tensor with the same {@link OperandType} as input0.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     GATHER = 51,
 
@@ -3074,8 +3026,6 @@
      * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
      *      [num_output_rois], specifying the batch index of each box. Boxes
      *      with the same batch index are grouped together.
-     *
-     * Available since API level 29.
      */
     GENERATE_PROPOSALS = 52,
 
@@ -3100,8 +3050,6 @@
      *
      * Outputs:
      * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
-     *
-     * Available since API level 29.
      */
     GREATER = 53,
     /**
@@ -3125,8 +3073,6 @@
      *
      * Outputs:
      * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
-     *
-     * Available since API level 29.
      */
     GREATER_EQUAL = 54,
 
@@ -3191,7 +3137,8 @@
      *      [depth_out, filter_height, filter_width, depth_group], specifying
      *      the filter, where depth_out must be divisible by num_groups.  For
      *      tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
-     *      the channel dimension must be set to 0.
+     *      the channel dimension (channelDim at
+     *      {@link SymmPerChannelQuantParams}) must be set to 0.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
      *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
      *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
@@ -3229,7 +3176,8 @@
      *      [depth_out, filter_height, filter_width, depth_group], specifying
      *      the filter, where depth_out must be divisible by num_groups.  For
      *      tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
-     *      the channel dimension must be set to 0.
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 0.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
      *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
      *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
@@ -3258,8 +3206,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth_out].
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
      */
     GROUPED_CONV_2D = 55,
 
@@ -3300,12 +3248,14 @@
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0, with shape
      *      [num_boxes, num_keypoints], specifying score of the keypoints.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from input0 scale and zeroPoint.
      * * 1: A tensor of the same {@link OperandType} as input1, with shape
      *      [num_boxes, num_keypoints, 2], specifying the location of
      *      the keypoints, the second dimension is organized as
      *      [keypoint_x, keypoint_y].
-     *
-     * Available since API level 29.
+     *      For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the
+     *      scale must be 0.125 and the zero point must be 0.
      */
     HEATMAP_MAX_KEYPOINT = 56,
 
@@ -3339,26 +3289,24 @@
      * * 0: An n-D tensor, specifying the tensor to be normalized.
      * * 1: A scalar, specifying gamma, the scale applied to the normalized
      *      tensor. The scalar must be of {@link OperandType::FLOAT16} if
-     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of {@link
-     *      OperandType::FLOAT32} if input0 is of {@link
-     *      OperandType::TENSOR_FLOAT32}.
+     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} if input0 is of
+     *      {@link OperandType::TENSOR_FLOAT32}.
      * * 2: A scalar, specifying beta, the offset applied to the normalized
      *      tensor. The scalar must be of {@link OperandType::FLOAT16} if
-     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of {@link
-     *      OperandType::FLOAT32} if input0 is of {@link
-     *      OperandType::TENSOR_FLOAT32}.
+     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} if input0 is of
+     *      {@link OperandType::TENSOR_FLOAT32}.
      * * 3: A scalar, specifying epsilon, the small value added to variance to
      *      avoid dividing by zero. The scalar must be of {@link OperandType::FLOAT16} if
-     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of {@link
-     *      OperandType::FLOAT32} if input0 is of {@link
-     *      OperandType::TENSOR_FLOAT32}.
+     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} if input0 is of
+     *      {@link OperandType::TENSOR_FLOAT32}.
      * * 4: An {@link OperandType::BOOL} scalar, set to true to specify
      *      NCHW data layout for input0 and output0. Set to false for NHWC.
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} and same shape as input0.
-     *
-     * Available since API level 29.
      */
     INSTANCE_NORMALIZATION = 57,
 
@@ -3383,8 +3331,6 @@
      *
      * Outputs:
      * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
-     *
-     * Available since API level 29.
      */
     LESS = 58,
 
@@ -3409,8 +3355,6 @@
      *
      * Outputs:
      * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
-     *
-     * Available since API level 29.
      */
     LESS_EQUAL = 59,
 
@@ -3428,8 +3372,6 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 29.
      */
     LOG = 60,
 
@@ -3450,8 +3392,6 @@
      *
      * Outputs:
      * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
-     *
-     * Available since API level 29.
      */
     LOGICAL_AND = 61,
 
@@ -3468,8 +3408,6 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 29.
      */
     LOGICAL_NOT = 62,
 
@@ -3490,8 +3428,6 @@
      *
      * Outputs:
      * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
-     *
-     * Available since API level 29.
      */
     LOGICAL_OR = 63,
 
@@ -3523,8 +3459,6 @@
      * Outputs:
      * * 0: The output tensor of the same {@link OperandType} and shape as
      *      input0.
-     *
-     * Available since API level 29.
      */
     LOG_SOFTMAX = 64,
 
@@ -3543,11 +3477,13 @@
      * * 0: A tensor.
      * * 1: A tensor of the same {@link OperandType} and compatible dimensions
      *      with input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
      */
     MAXIMUM = 65,
 
@@ -3566,11 +3502,13 @@
      * * 0: A tensor.
      * * 1: A tensor of the same {@link OperandType} and compatible dimensions
      *      with input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
      */
     MINIMUM = 66,
 
@@ -3589,8 +3527,6 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 29.
      */
     NEG = 67,
 
@@ -3615,8 +3551,6 @@
      *
      * Outputs:
      * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
-     *
-     * Available since API level 29.
      */
     NOT_EQUAL = 68,
 
@@ -3657,8 +3591,8 @@
      *      of the padding:
      *          output0.dimension[i] =
      *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     PAD_V2 = 69,
 
@@ -3689,8 +3623,6 @@
      *
      * Outputs:
      * * 0: An output tensor.
-     *
-     * Available since API level 29.
      */
     POW = 70,
 
@@ -3728,8 +3660,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be diffent from the input0 scale and zeroPoint.
      */
     PRELU = 71,
 
@@ -3752,8 +3684,6 @@
      * Outputs:
      * * 0: The output tensor of same shape as input0, but with
      *      {@link OperandType::TENSOR_QUANT8_ASYMM}.
-     *
-     * Available since API level 29.
      */
     QUANTIZE = 72,
 
@@ -3879,8 +3809,6 @@
      * Outputs:
      * * 0: A 2-D {@link OperandType::TENSOR_INT32} tensor with shape
      *      [batches, samples], containing the drawn samples.
-     *
-     * Available since API level 29.
      */
     RANDOM_MULTINOMIAL = 74,
 
@@ -3906,8 +3834,6 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 29.
      */
     REDUCE_ALL = 75,
 
@@ -3933,8 +3859,6 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 29.
      */
     REDUCE_ANY = 76,
 
@@ -3962,8 +3886,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     REDUCE_MAX = 77,
 
@@ -3991,8 +3915,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     REDUCE_MIN = 78,
 
@@ -4018,8 +3942,6 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 29.
      */
     REDUCE_PROD = 79,
 
@@ -4045,8 +3967,6 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *
-     * Available since API level 29.
      */
     REDUCE_SUM = 80,
 
@@ -4064,7 +3984,7 @@
      * interpolation.
      *
      * Supported tensor {@link OperandType}:
-     * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
+     * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
@@ -4105,8 +4025,8 @@
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0. The output
      *      shape is [num_rois, out_height, out_width, depth].
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from the input0 scale and zeroPoint.
      */
     ROI_ALIGN = 81,
 
@@ -4156,8 +4076,8 @@
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0. The output
      *      shape is [num_rois, out_height, out_width, depth].
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     ROI_POOLING = 82,
 
@@ -4175,8 +4095,6 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 29.
      */
     RSQRT = 83,
 
@@ -4201,10 +4119,13 @@
      *      true) or input2 (if false).
      * * 1: An input tensor of the same shape as input0.
      * * 2: An input tensor of the same shape and type as input1.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scales and zeroPoint can be different from input1 scale and zeroPoint.
      *
      * Outputs:
      * * 0: A tensor of the same type and shape as input1 and input2.
-     *
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
      */
     SELECT = 84,
 
@@ -4222,8 +4143,6 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 29.
      */
     SIN = 85,
 
@@ -4235,7 +4154,6 @@
      * for each dimension. The size is specified as a 1-D tensor containing
      * either size of a slice along corresponding dimension or -1. In the latter
      * case, all the remaining elements in dimension are included in the slice.
-     * Slice size in each dimension cannot be zero.
      *
      * A sum of begin offset and a size of a slice must not exceed size of a
      * corresponding dimension.
@@ -4257,8 +4175,8 @@
      *
      * Outputs:
      * * 0: An n-D tensor of the same type as the input containing the slice.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      its scale and zeroPoint has to be same as the input0 scale and zeroPoint.
      */
     SLICE = 86,
 
@@ -4282,8 +4200,8 @@
      *
      * Outputs:
      * * 0 ~ (num_splits - 1): Resulting subtensors.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     SPLIT = 87,
 
@@ -4301,8 +4219,6 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
-     *
-     * Available since API level 29.
      */
     SQRT = 88,
 
@@ -4330,8 +4246,8 @@
      *
      * Outputs:
      * * 0: A tiled tensor of the same {@link OperandType} and rank as `input`.
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     TILE = 89,
 
@@ -4357,10 +4273,10 @@
      * Outputs:
      * * 0: An n-D tensor of the same type as the input, containing the k
      *      largest elements along each last dimensional slice.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      * * 1: An n-D tensor of type {@link OperandType::TENSOR_INT32}
      *      containing the indices of values within the last dimension of input.
-     *
-     * Available since API level 29.
      */
     TOPK_V2 = 90,
 
@@ -4374,7 +4290,7 @@
      * The output dimensions are functions of the filter dimensions, stride, and
      * padding.
      *
-     * Supported tensor {@link OperandCode} configurations:
+     * Supported tensor {@link OperandType} configurations:
      * * 16 bit floating point:
      * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
      *
@@ -4406,7 +4322,7 @@
      *      [depth_out, filter_height, filter_width, depth_in], specifying the
      *      filter. For tensor of type
      *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
-     *      dimension (extraParams.channelQuant.channelDim) must be set to 0.
+     *      dimension (SymmPerChannelQuantParams::channelDim) must be set to 0.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
      *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
      *      {@link OperandType::TENSOR_FLOAT16}, the bias should be of the
@@ -4443,7 +4359,7 @@
      *      [depth_out, filter_height, filter_width, depth_in], specifying the
      *      filter. For tensor of type
      *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
-     *      dimension (extraParams.channelQuant.channelDim) must be set to 0.
+     *      dimension (SymmPerChannelQuantParams::channelDim) must be set to 0.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
      *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
      *      {@link OperandType::TENSOR_FLOAT16}, the bias should be of the
@@ -4473,8 +4389,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth_out].
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
      */
     TRANSPOSE_CONV_2D = 91,
 
@@ -4584,8 +4500,6 @@
      *      A 3-D tensor of shape:
      *        If time-major: [max_time, batch_size, output_size]
      *        If batch-major: [batch_size, max_time, output_size]
-     *
-     * Available since API level 29.
      */
     UNIDIRECTIONAL_SEQUENCE_LSTM = 92,
 
@@ -4641,8 +4555,6 @@
      *      it is set to 1, then the output has a shape [maxTime, batchSize,
      *      numUnits], otherwise the output has a shape [batchSize, maxTime,
      *      numUnits].
-     *
-     * Available since API level 29.
      */
     UNIDIRECTIONAL_SEQUENCE_RNN = 93,
 
@@ -4696,8 +4608,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, new_height, new_width, depth].
-     *
-     * Available since API level 29.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
      */
     RESIZE_NEAREST_NEIGHBOR = 94,
 
diff --git a/neuralnetworks/1.2/types.t b/neuralnetworks/1.2/types.t
new file mode 100644
index 0000000..d197f6b
--- /dev/null
+++ b/neuralnetworks/1.2/types.t
@@ -0,0 +1,725 @@
+%% template file for generating types.hal.
+%% see frameworks/ml/nn/tools/api/README.md.
+/*
+ * Copyright (C) 2018 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.neuralnetworks@1.2;
+
+import @1.0::DataLocation;
+import @1.0::ErrorStatus;
+import @1.0::OperandLifeTime;
+import @1.0::OperandType;
+import @1.0::PerformanceInfo;
+import @1.1::OperationType;
+
+import android.hidl.safe_union@1.0::Monostate;
+
+enum Constant : uint32_t {
+    /**
+     * The byte size of the cache token.
+     */
+    BYTE_SIZE_OF_CACHE_TOKEN = 32,
+
+    /**
+     * The maximum number of files for each type of cache in compilation caching.
+     */
+    MAX_NUMBER_OF_CACHE_FILES = 32,
+};
+
+enum OperandType : @1.0::OperandType {
+%insert Operand_1.2
+%insert OEMDeprecationAndOperandTypeRangeMaxComment
+};
+
+/**
+ * The range of operand values in the OperandType enum.
+ */
+enum OperandTypeRange : uint32_t {
+    BASE_MIN        = 0,
+    FUNDAMENTAL_MIN = 0,
+%insert Operand_1.2_MAX
+    OEM_MIN         = 10000,
+    OEM_MAX         = 10001,
+    BASE_MAX        = 0xFFFF,
+};
+
+/**
+ * Operation types.
+ *
+ * The type of an operation in a model.
+ */
+enum OperationType : int32_t {
+
+%insert Operation_1.0
+
+%insert Operation_1.1
+
+%insert Operation_1.2
+
+    /**
+     * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
+     * OEM operation and data types.
+     *
+     * This operation is OEM specific. It should only be used for OEM
+     * applications.
+     */
+    OEM_OPERATION = @1.1::OperationType:OEM_OPERATION,
+    /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF
+     * OperationTypeRange::FUNDAMENTAL_MAX.
+     */
+    /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF
+     * OperationTypeRange::OEM_MAX.
+     */
+};
+
+/**
+ * The range of values in the OperationType enum.
+ */
+enum OperationTypeRange : uint32_t {
+    BASE_MIN        = 0,
+    FUNDAMENTAL_MIN = 0,
+%insert Operation_1.2_MAX
+    OEM_MIN         = 10000,
+    OEM_MAX         = 10000,
+    BASE_MAX        = 0xFFFF,
+};
+
+/**
+ * Device types.
+ *
+ * The type of NNAPI device.
+ */
+enum DeviceType : int32_t {
+    // Leaving 0 unused as it means unknown type in NDK NNAPI. There is no
+    // HAL equivalent of unknown type and a 1.2 HAL implementation must belong
+    // to one of the categories below.
+    /** The device does not fall into any category below. */
+    OTHER             = 1,
+    /** The device runs NNAPI models on single or multi-core CPU. */
+    CPU               = 2,
+    /** The device can run NNAPI models and also accelerate graphics APIs such
+      * as OpenGL ES and Vulkan. */
+    GPU               = 3,
+    /** Dedicated accelerator for Machine Learning workloads. */
+    ACCELERATOR       = 4,
+};
+
+/**
+ * The capabilities of a driver.
+ *
+ * Performance of an operation comes from the type of its first operand.
+ * This represents performance for non extension operand types.
+ */
+struct Capabilities {
+    /**
+     * Driver performance when operating on float32 data but performing
+     * calculations with range and/or precision as low as that of the IEEE
+     * 754 16-bit floating-point format.
+     */
+    PerformanceInfo relaxedFloat32toFloat16PerformanceScalar;
+    PerformanceInfo relaxedFloat32toFloat16PerformanceTensor;
+
+    /**
+     * Driver performance when operating on a particular data type.
+     * In the case of float32 data, this is used when the calculations
+     * are not relaxed.
+     */
+    struct OperandPerformance {
+        OperandType type;
+        PerformanceInfo info;
+    };
+
+    /**
+     * Performance by operand type. Must be sorted by OperandType.
+     * If a particular OperandType is not present in operandPerformance,
+     * its performance is treated as { .execTime = FLT_MAX, .powerUsage = FLT_MAX }.
+     */
+    vec<OperandPerformance> operandPerformance;
+};
+
+/**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+    /**
+     * The operation type.
+     *
+     * Besides the values listed in {@link OperationType}, any value above
+     * {@link OperationTypeRange::BASE_MAX} is possible and should be interpreted
+     * as an extension type according to {@link Model::extensionNameToPrefix}.
+     */
+    OperationType type;
+
+    /**
+     * Describes the table that contains the indexes of the inputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> inputs;
+
+    /**
+     * Describes the table that contains the indexes of the outputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> outputs;
+};
+
+/**
+ * Parameters for TENSOR_QUANT8_SYMM_PER_CHANNEL operand.
+ */
+struct SymmPerChannelQuantParams {
+    /** Array of scaling values for each channel. Each value must be greater than zero. */
+    vec<float> scales;
+    /** Index of the channel dimension */
+    uint32_t channelDim;
+};
+
+/**
+ * Describes one operand of the model's graph.
+ */
+struct Operand {
+    /**
+     * The data type.
+     *
+     * Besides the values listed in {@link OperandType}, any value above
+     * {@link OperandTypeRange::BASE_MAX} is possible and should be interpreted
+     * as an extension type according to {@link Model::extensionNameToPrefix}.
+     */
+    OperandType type;
+
+    /**
+     * Dimensions of the operand.
+     *
+     * For a scalar operand, dimensions.size() must be 0.
+     *
+     * A tensor operand with all dimensions specified has "fully
+     * specified" dimensions. Whenever possible (i.e., whenever the
+     * dimensions are known at model construction time), a tensor
+     * operand should have (but is not required to have) fully
+     * specified dimensions, in order to enable the best possible
+     * performance.
+     *
+     * If a tensor operand's dimensions are not fully specified, the
+     * dimensions of the operand are deduced from the operand
+     * dimensions and values of the operation for which that operand
+     * is an output.
+     *
+     * In the following situations, a tensor operand's dimensions must
+     * be fully specified:
+     *
+     *     . The operand has lifetime CONSTANT_COPY or
+     *       CONSTANT_REFERENCE.
+     *
+     *     . The operand has lifetime MODEL_INPUT. Fully
+     *       specified dimensions must either be present in the
+     *       Operand or they must be provided in the corresponding
+     *       RequestArgument.
+     *       EXCEPTION: If the input is optional and omitted
+     *       (by setting the hasNoValue field of the corresponding
+     *       RequestArgument to true) then it need not have fully
+     *       specified dimensions.
+     *
+     * A tensor operand with some number of unspecified dimensions is
+     * represented by setting each unspecified dimension to 0.
+     *
+     * A tensor operand with unspecified rank is represented by providing
+     * an empty dimensions vector.
+     */
+    vec<uint32_t> dimensions;
+
+    /**
+     * The number of times this operand appears as an operation input.
+     *
+     * (For example, if this operand appears once in one operation's
+     * input list, and three times in another operation's input list,
+     * then numberOfConsumers = 4.)
+     */
+    uint32_t numberOfConsumers;
+
+    /**
+     * Quantized scale of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or
+     * TENSOR_INT32.
+     */
+    float scale;
+
+    /**
+     * Quantized zero-point offset of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM.
+     */
+    int32_t zeroPoint;
+
+    /**
+     * How the operand is used.
+     */
+    OperandLifeTime lifetime;
+
+    /**
+     * Where to find the data for this operand.
+     * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
+     * NO_VALUE:
+     * - All the fields must be 0.
+     * If the lifetime is CONSTANT_COPY:
+     * - location.poolIndex is 0.
+     * - location.offset is the offset in bytes into Model.operandValues.
+     * - location.length is set.
+     * If the lifetime is CONSTANT_REFERENCE:
+     * - location.poolIndex is set.
+     * - location.offset is the offset in bytes into the specified pool.
+     * - location.length is set.
+     */
+    DataLocation location;
+
+    /**
+     * Additional parameters specific to a particular operand type.
+     */
+    safe_union ExtraParams {
+       /**
+        * No additional parameters.
+        */
+       Monostate none;
+
+       /**
+        * Symmetric per-channel quantization parameters.
+        *
+        * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL.
+        */
+       SymmPerChannelQuantParams channelQuant;
+
+       /**
+        * Extension operand parameters.
+        *
+        * The framework treats this as an opaque data blob.
+        * The format is up to individual extensions.
+        */
+       vec<uint8_t> extension;
+    } extraParams;
+};
+
+/**
+ * A Neural Network Model.
+ *
+ * This includes not only the execution graph, but also constant data such as
+ * weights or scalars added at construction time. The only information that
+ * may not be known is the shape of the input tensors.
+ */
+struct Model {
+    /**
+     * All operands included in the model.
+     */
+    vec<Operand> operands;
+
+    /**
+     * All operations included in the model.
+     *
+     * The operations are sorted into execution order. Every operand
+     * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
+     * written before it is read.
+     */
+    vec<Operation> operations;
+
+    /**
+     * Input indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> inputIndexes;
+
+    /**
+     * Output indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> outputIndexes;
+
+    /**
+     * A byte buffer containing operand data that were copied into the model.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_COPY.
+     */
+    vec<uint8_t> operandValues;
+
+    /**
+     * A collection of shared memory pools containing operand values.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_REFERENCE.
+     */
+    vec<memory> pools;
+
+    /**
+     * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or
+     * precision as low as that of the IEEE 754 16-bit floating-point format.
+     * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the
+     * range and precision of the IEEE 754 32-bit floating-point format.
+     */
+    bool relaxComputationFloat32toFloat16;
+
+    /**
+     * The mapping between extension names and prefixes of operand and
+     * operation type values.
+     *
+     * An operand or operation whose numeric type value is above
+     * {@link OperandTypeRange::BASE_MAX} or
+     * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
+     * as an extension operand. The low
+     * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
+     * correspond to the type ID within the extension and the high
+     * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+     * the "prefix", which maps uniquely to the extension name.
+     *
+     * For example, if a model contains an operation whose value is
+     * 0xAAAABBBB and extensionNameToPrefix contains an entry with
+     * prefix=0xAAAA and name="vendor.test.test_extension", then
+     * the operation should be interpreted as the operation 0xBBBB
+     * of the extension named vendor.test.test_extension.
+     *
+     * This is a one-to-one correspondence. That is, there must be at most one
+     * prefix corresponding to each extension name and at most one extension
+     * name corresponding to each prefix.
+     */
+    vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+
+    /**
+     * A correspondence between an extension name and a prefix of operand and
+     * operation type values.
+     */
+    struct ExtensionNameAndPrefix {
+        /**
+         * The extension name.
+         *
+         * See {@link Extension::name} for the format specification.
+         */
+        string name;
+
+        /**
+         * The unique extension identifier within the model.
+         *
+         * See {@link Model::extensionNameToPrefix}.
+         */
+        uint16_t prefix;
+    };
+
+    /**
+     * Numeric values of extension operand and operation types have the
+     * following structure:
+     * - 16 high bits represent the "prefix", which corresponds uniquely to the
+     *   extension name.
+     * - 16 low bits represent the type ID within the extension.
+     */
+    enum ExtensionTypeEncoding : uint8_t {
+        HIGH_BITS_PREFIX = 16,
+        LOW_BITS_TYPE = 16,
+    };
+};
+
+/**
+ * Describes the shape information of an output operand after execution.
+ */
+struct OutputShape {
+    /**
+     * Dimensions of the operand.
+     */
+    vec<uint32_t> dimensions;
+
+    /**
+     * Whether the provided buffer size is sufficient for the output.
+     */
+    bool isSufficient;
+};
+
+/**
+ * Specifies whether or not to measure timing information during execution.
+ */
+enum MeasureTiming : int32_t {
+    NO  = 0,
+    YES = 1,
+};
+
+/**
+
+ * Timing information measured during execution. Each time is a duration from
+ * the beginning of some task to the end of that task, including time when that
+ * task is not active (for example, preempted by some other task, or
+ * waiting for some resource to become available).
+ *
+ * Times are measured in microseconds.
+ * When a time is not available, it must be reported as UINT64_MAX.
+ */
+struct Timing {
+    /** Execution time on device (not driver, which runs on host processor). */
+    uint64_t timeOnDevice;
+    /** Execution time in driver (including time on device). */
+    uint64_t timeInDriver;
+};
+
+/**
+ * FmqRequestDatum is a single element of a serialized representation of an
+ * execution request (a {@link @1.0::Request} object and a {@link MeasureTiming}
+ * value) which is sent across FastMessageQueue.
+ *
+ * The serialized representation for a particular execution is referred to later
+ * in these descriptions as a 'packet'.
+ *
+ * FastMessageQueue can only pass HIDL-defined types that do not involve nested
+ * buffers, handles, or interfaces.
+ *
+ * The request is serialized as follows:
+ * 1) 'packetInformation'
+ * 2) For each input operand:
+ *    2.1) 'inputOperandInformation'
+ *    2.2) For each dimension element of the operand:
+ *         2.2.1) 'inputOperandDimensionValue'
+ * 3) For each output operand:
+ *    3.1) 'outputOperandInformation'
+ *    3.2) For each dimension element of the operand:
+ *         3.2.1) 'outputOperandDimensionValue'
+ * 4) For each pool:
+ *    4.1) 'poolIdentifier'
+ * 5) 'measureTiming'
+ */
+safe_union FmqRequestDatum {
+    /**
+     * Type to describe the high-level layout of the packet.
+     */
+    struct PacketInformation {
+        /**
+         * How many elements the packet contains, including the
+         * "packetInformation" datum.
+         */
+        uint32_t packetSize;
+
+        /**
+         * Number of input operands.
+         */
+        uint32_t numberOfInputOperands;
+
+        /**
+         * Number of output operands.
+         */
+        uint32_t numberOfOutputOperands;
+
+        /**
+         * Number of pool identifiers.
+         */
+        uint32_t numberOfPools;
+    };
+
+    /**
+     * Type representing the information for each operand.
+     */
+    struct OperandInformation {
+        /**
+         * If true, the argument does not have a value. This can be used for
+         * operations that take optional arguments. If true, the fields of
+         * 'location' are set to 0, 'numberOfDimensions' is set to 0,  and the
+         * dimensions information is omitted from the serialization.
+         */
+        bool hasNoValue;
+
+        /**
+         * The location within one of the memory pools passed in the Request.
+         */
+        DataLocation location;
+
+        /**
+         * Number of subsequent elements that belong to the dimensions vector.
+         */
+        uint32_t numberOfDimensions;
+    };
+
+    /**
+     * packetInformation is the first element of the packet and describes the
+     * remainder of the packet.
+     */
+    PacketInformation packetInformation;
+
+    /**
+     * Information for each input operand.
+     */
+    OperandInformation inputOperandInformation;
+
+    /**
+     * Element of the dimensions vector.
+     */
+    uint32_t inputOperandDimensionValue;
+
+    /**
+     * Information for each output operand.
+     */
+    OperandInformation outputOperandInformation;
+
+    /**
+     * Element of the dimensions vector.
+     */
+    uint32_t outputOperandDimensionValue;
+
+    /**
+     * Unique identifier for a pool.
+     *
+     * A {@link @1.0::Request} passes across one or more pools of shared memory
+     * for the inputs and outputs of an execution. However, these memory pools
+     * are not able to be sent across FastMessageQueue directly. Instead, the
+     * producing side of the FMQ represents each different pool with a unique
+     * identifier, and sends this identifier across the FMQ. Whenever the
+     * consuming side of the FMQ needs the memory corresponding to this unique
+     * identifier, it can pass the identifier to
+     * {@link IBurstCallback::getMemories} to retreive the memory. Although this
+     * HIDL Binder call is expensive compared to communication across FMQ, it is
+     * only needed in the cases when the consumer does not recognize the unique
+     * identifier.
+     */
+    int32_t poolIdentifier;
+
+    /**
+     * Specifies whether or not to measure duration of the execution. The
+     * duration runs from the time the driver dequeues the request from a
+     * FastMessageQueue to the time the driver enqueues results to a
+     * FastMessageQueue.
+     */
+    MeasureTiming measureTiming;
+};
+
+/**
+ * FmqResultDatum is a single element of a serialized representation of the
+ * values returned from an execution ({@link @1.0::ErrorStatus},
+ * vec<{@link OutputShape}>, and {@link Timing}) which is returned via
+ * FastMessageQueue.
+ *
+ * The serialized representation for a particular execution is referred to later
+ * in these descriptions as a 'packet'.
+ *
+ * FastMessageQueue can only pass HIDL-defined types that do not involve nested
+ * buffers, handles, or interfaces.
+ *
+ * The execution return values ({@link @1.0::ErrorStatus} and
+ * vec<{@link OutputShape}>) are serialized as follows:
+ * 1) 'packetInformation'
+ * 2) For each returned operand:
+ *    2.1) 'operandInformation'
+ *    2.2) For each dimension element of the operand:
+ *         2.2.1) 'operandDimensionValue'
+ * 3) 'executionTiming'
+ */
+safe_union FmqResultDatum {
+    /**
+     * Type to describe the high-level layout of the packet.
+     */
+    struct PacketInformation {
+        /**
+         * How many elements the packet contains, including the
+         * "packetInformation" datum.
+         */
+        uint32_t packetSize;
+
+        /**
+         * Status of the execution.
+         */
+        ErrorStatus errorStatus;
+
+        /**
+         * Number of returned operands.
+         */
+        uint32_t numberOfOperands;
+    };
+
+    /**
+     * Type representing the information for each operand.
+     */
+    struct OperandInformation {
+        /**
+         * Indicates whether the operand's output buffer is large enough to
+         * store the operand's result data.
+         */
+        bool isSufficient;
+
+        /**
+         * Number of subsequent elements that belong to the dimensions vector.
+         */
+        uint32_t numberOfDimensions;
+    };
+
+    /**
+     * packetInformation is the first element of the packet and describes the
+     * remainder of the packet. It additionally includes the status of the
+     * execution.
+     */
+    PacketInformation packetInformation;
+
+    /**
+     * Information for each returned operand.
+     */
+    OperandInformation operandInformation;
+
+    /**
+     * Element of the dimensions vector.
+     */
+    uint32_t operandDimensionValue;
+
+    /**
+     * Duration of execution. Unless measurement was requested and execution
+     * succeeds, all times must be reported as UINT64_MAX. A driver may choose
+     * to report any time as UINT64_MAX, indicating that measurement is not
+     * available.
+     */
+    Timing executionTiming;
+};
+
+/**
+ * Information about an extension.
+ */
+struct Extension {
+    /**
+     * The extension name.
+     *
+     * The name must consist of lowercase latin letters, numbers, periods, and
+     * underscore signs. The name must contain at least one period.
+     *
+     * The name must start with the reverse domain name of the vendor.
+     *
+     * Example: com.google.test_extension
+     */
+    string name;
+
+    /**
+     * Information about an extension operand type.
+     */
+    struct OperandTypeInformation {
+        /**
+         * The extension operand type.
+         */
+        uint16_t type;
+
+        /**
+         * Indicates whether the extension operand type represents a tensor or
+         * a scalar.
+         */
+        bool isTensor;
+
+        /**
+         * The byte size of the operand (if scalar) or of a single element (if
+         * tensor).
+         */
+        uint32_t byteSize;
+    };
+
+    /**
+     * Information about operand types defined by the extension.
+     */
+    vec<OperandTypeInformation> operandTypes;
+};
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 6c26820..fc727b7 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -14,57 +14,62 @@
 // limitations under the License.
 //
 
-// Tests for V1_0 models using the V1_2 HAL.
-cc_test {
-    name: "VtsHalNeuralnetworksV1_2CompatV1_0TargetTest",
-    defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+cc_library_static {
+    name: "VtsHalNeuralNetworksV1_2Callbacks",
+    defaults: ["VtsHalTargetTestDefaults"],
+    export_include_dirs: ["include"],
     srcs: [
-        "GeneratedTestsV1_0.cpp",
-        "ValidateBurst.cpp",
+        "Callbacks.cpp",
     ],
-    cflags: [
-        "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
+    static_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.2",
     ],
+    header_libs: [
+        "libbase_headers",
+    ]
 }
 
-// Tests for V1_1 models using the V1_2 HAL.
-cc_test {
-    name: "VtsHalNeuralnetworksV1_2CompatV1_1TargetTest",
-    defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
-    srcs: [
-        "GeneratedTestsV1_1.cpp",
-        "ValidateBurst.cpp",
-    ],
-    cflags: [
-        "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
-    ],
-}
-
-// Tests for V1_2 models.
 cc_test {
     name: "VtsHalNeuralnetworksV1_2TargetTest",
-    defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+    defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "BasicTests.cpp",
         "CompilationCachingTests.cpp",
-        "GeneratedTests.cpp",
+        "GeneratedTestHarness.cpp",
+        "TestAssertions.cpp",
+        "ValidateModel.cpp",
+        "ValidateRequest.cpp",
         "ValidateBurst.cpp",
+        "VtsHalNeuralnetworks.cpp",
     ],
-    cflags: [
-        "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
+    local_include_dirs: ["include"],
+    shared_libs: [
+        "libfmq",
+        "libnativewindow",
     ],
-}
-
-cc_test {
-    name: "PresubmitHalNeuralnetworksV1_2TargetTest",
-    defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
-    srcs: [
-        "BasicTests.cpp",
-        "GeneratedTests.cpp",
-        "ValidateBurst.cpp",
+    static_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.2",
+        "android.hardware.neuralnetworks@1.3",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libgmock",
+        "libhidlmemory",
+        "libneuralnetworks_generated_test_harness",
+        "libneuralnetworks_utils",
+        "VtsHalNeuralNetworksV1_0_utils",
+        "VtsHalNeuralNetworksV1_2Callbacks",
     ],
-    cflags: [
-        "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE",
-        "-DPRESUBMIT_NOT_VTS",
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+        "neuralnetworks_generated_V1_1_example",
+        "neuralnetworks_generated_V1_2_example",
     ],
+    header_libs: [
+        "libneuralnetworks_headers",
+    ],
+    test_suites: ["general-tests"],
 }
diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
index 5c269df..8e82c53 100644
--- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
@@ -18,30 +18,27 @@
 
 #include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
+using V1_0::DeviceStatus;
+using V1_0::ErrorStatus;
 using V1_0::PerformanceInfo;
 
 // create device test
-TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
+TEST_P(NeuralnetworksHidlTest, CreateDevice) {}
 
 // status test
-TEST_F(NeuralnetworksHidlTest, StatusTest) {
-    Return<DeviceStatus> status = device->getStatus();
+TEST_P(NeuralnetworksHidlTest, StatusTest) {
+    Return<DeviceStatus> status = kDevice->getStatus();
     ASSERT_TRUE(status.isOk());
     EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
 }
 
 // initialization
-TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) {
     using OperandPerformance = Capabilities::OperandPerformance;
-    Return<void> ret = device->getCapabilities_1_2([](ErrorStatus status,
-                                                      const Capabilities& capabilities) {
+    Return<void> ret = kDevice->getCapabilities_1_2([](ErrorStatus status,
+                                                       const Capabilities& capabilities) {
         EXPECT_EQ(ErrorStatus::NONE, status);
 
         auto isPositive = [](const PerformanceInfo& perf) {
@@ -63,17 +60,18 @@
 }
 
 // device version test
-TEST_F(NeuralnetworksHidlTest, GetDeviceVersionStringTest) {
-    Return<void> ret = device->getVersionString([](ErrorStatus status, const hidl_string& version) {
-        EXPECT_EQ(ErrorStatus::NONE, status);
-        EXPECT_LT(0, version.size());
-    });
+TEST_P(NeuralnetworksHidlTest, GetDeviceVersionStringTest) {
+    Return<void> ret =
+            kDevice->getVersionString([](ErrorStatus status, const hidl_string& version) {
+                EXPECT_EQ(ErrorStatus::NONE, status);
+                EXPECT_LT(0, version.size());
+            });
     EXPECT_TRUE(ret.isOk());
 }
 
 // device type test
-TEST_F(NeuralnetworksHidlTest, GetDeviceTypeTest) {
-    Return<void> ret = device->getType([](ErrorStatus status, DeviceType type) {
+TEST_P(NeuralnetworksHidlTest, GetDeviceTypeTest) {
+    Return<void> ret = kDevice->getType([](ErrorStatus status, DeviceType type) {
         EXPECT_EQ(ErrorStatus::NONE, status);
         EXPECT_TRUE(type == DeviceType::OTHER || type == DeviceType::CPU ||
                     type == DeviceType::GPU || type == DeviceType::ACCELERATOR);
@@ -82,8 +80,8 @@
 }
 
 // device supported extensions test
-TEST_F(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) {
-    Return<void> ret = device->getSupportedExtensions(
+TEST_P(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) {
+    Return<void> ret = kDevice->getSupportedExtensions(
             [](ErrorStatus status, const hidl_vec<Extension>& extensions) {
                 EXPECT_EQ(ErrorStatus::NONE, status);
                 for (auto& extension : extensions) {
@@ -103,8 +101,8 @@
 }
 
 // getNumberOfCacheFilesNeeded test
-TEST_F(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) {
-    Return<void> ret = device->getNumberOfCacheFilesNeeded(
+TEST_P(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) {
+    Return<void> ret = kDevice->getNumberOfCacheFilesNeeded(
             [](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) {
                 EXPECT_EQ(ErrorStatus::NONE, status);
                 EXPECT_LE(numModelCache,
@@ -113,9 +111,4 @@
             });
     EXPECT_TRUE(ret.isOk());
 }
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
diff --git a/neuralnetworks/1.2/vts/functional/Callbacks.cpp b/neuralnetworks/1.2/vts/functional/Callbacks.cpp
new file mode 100644
index 0000000..3972ad6
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/Callbacks.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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 "Callbacks"
+
+#include "1.2/Callbacks.h"
+
+#include <android-base/logging.h>
+
+#include <limits>
+
+namespace android::hardware::neuralnetworks::V1_2::implementation {
+
+using V1_0::ErrorStatus;
+
+constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits<uint64_t>::max(),
+                              .timeInDriver = std::numeric_limits<uint64_t>::max()};
+
+// PreparedModelCallback methods begin here
+
+Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
+                                           const sp<V1_0::IPreparedModel>& preparedModel) {
+    {
+        std::lock_guard<std::mutex> hold(mMutex);
+
+        // quick-return if object has already been notified
+        if (mNotified) {
+            return Void();
+        }
+
+        // store results and mark as notified
+        mErrorStatus = errorStatus;
+        mPreparedModel = preparedModel;
+        mNotified = true;
+    }
+
+    mCondition.notify_all();
+    return Void();
+}
+
+Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus,
+                                               const sp<V1_2::IPreparedModel>& preparedModel) {
+    return notify(errorStatus, preparedModel);
+}
+
+void PreparedModelCallback::wait() const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    mCondition.wait(lock, [this] { return mNotified; });
+}
+
+ErrorStatus PreparedModelCallback::getStatus() const {
+    wait();
+    return mErrorStatus;
+}
+
+sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() const {
+    wait();
+    return mPreparedModel;
+}
+
+// ExecutionCallback methods begin here
+
+Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) {
+    notifyInternal(errorStatus, {}, kNoTiming);
+    return Void();
+}
+
+Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus,
+                                           const hidl_vec<OutputShape>& outputShapes,
+                                           const Timing& timing) {
+    if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
+        // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE.
+        if (outputShapes.size() == 0) {
+            LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE";
+            notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
+            return Void();
+        }
+    } else if (errorStatus != ErrorStatus::NONE) {
+        // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE.
+        if (outputShapes.size() != 0) {
+            LOG(ERROR) << "Notified with non-empty output shape vector when error status is "
+                          "neither NONE nor OUTPUT_INSUFFICIENT_SIZE";
+            notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
+            return Void();
+        }
+    }
+    notifyInternal(errorStatus, outputShapes, timing);
+    return Void();
+}
+
+void ExecutionCallback::wait() const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    mCondition.wait(lock, [this] { return mNotified; });
+}
+
+ErrorStatus ExecutionCallback::getStatus() const {
+    wait();
+    return mErrorStatus;
+}
+
+const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() const {
+    wait();
+    return mOutputShapes;
+}
+
+Timing ExecutionCallback::getTiming() const {
+    wait();
+    return mTiming;
+}
+
+void ExecutionCallback::notifyInternal(ErrorStatus errorStatus,
+                                       const hidl_vec<OutputShape>& outputShapes,
+                                       const Timing& timing) {
+    {
+        std::lock_guard<std::mutex> hold(mMutex);
+
+        // quick-return if object has already been notified
+        if (mNotified) {
+            return;
+        }
+
+        mErrorStatus = errorStatus;
+        mOutputShapes = outputShapes;
+        mTiming = timing;
+        mNotified = true;
+    }
+    mCondition.notify_all();
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_2::implementation
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 4411b90..2130a76 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
+#include <fcntl.h>
 #include <ftw.h>
 #include <gtest/gtest.h>
 #include <hidlmemory/mapping.h>
@@ -26,68 +26,41 @@
 #include <cstdio>
 #include <cstdlib>
 #include <random>
+#include <thread>
 
-#include "Callbacks.h"
+#include "1.2/Callbacks.h"
 #include "GeneratedTestHarness.h"
+#include "MemoryUtils.h"
 #include "TestHarness.h"
 #include "Utils.h"
 #include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
+// Forward declaration of the mobilenet generated test models in
+// frameworks/ml/nn/runtime/test/generated/.
+namespace generated_tests::mobilenet_224_gender_basic_fixed {
+const test_helper::TestModel& get_test_model();
+}  // namespace generated_tests::mobilenet_224_gender_basic_fixed
 
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
+namespace generated_tests::mobilenet_quantized {
+const test_helper::TestModel& get_test_model();
+}  // namespace generated_tests::mobilenet_quantized
+
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
+
+using namespace test_helper;
+using implementation::PreparedModelCallback;
+using V1_0::ErrorStatus;
+using V1_1::ExecutionPreference;
 
 namespace float32_model {
 
-// In frameworks/ml/nn/runtime/test/generated/, creates a hidl model of float32 mobilenet.
-#include "examples/mobilenet_224_gender_basic_fixed.example.cpp"
-#include "vts_models/mobilenet_224_gender_basic_fixed.model.cpp"
-
-// Prevent the compiler from complaining about an otherwise unused function.
-[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape;
-[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape;
-
-// MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h.
-// This function assumes the operation is always ADD.
-std::vector<MixedTypedExample> getLargeModelExamples(uint32_t len) {
-    float outputValue = 1.0f + static_cast<float>(len);
-    return {{.operands = {
-                     // Input
-                     {.operandDimensions = {{0, {1}}}, .float32Operands = {{0, {1.0f}}}},
-                     // Output
-                     {.operandDimensions = {{0, {1}}}, .float32Operands = {{0, {outputValue}}}}}}};
-}
+constexpr auto get_test_model = generated_tests::mobilenet_224_gender_basic_fixed::get_test_model;
 
 }  // namespace float32_model
 
 namespace quant8_model {
 
-// In frameworks/ml/nn/runtime/test/generated/, creates a hidl model of quant8 mobilenet.
-#include "examples/mobilenet_quantized.example.cpp"
-#include "vts_models/mobilenet_quantized.model.cpp"
-
-// Prevent the compiler from complaining about an otherwise unused function.
-[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape;
-[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape;
-
-// MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h.
-// This function assumes the operation is always ADD.
-std::vector<MixedTypedExample> getLargeModelExamples(uint32_t len) {
-    uint8_t outputValue = 1 + static_cast<uint8_t>(len);
-    return {{.operands = {// Input
-                          {.operandDimensions = {{0, {1}}}, .quant8AsymmOperands = {{0, {1}}}},
-                          // Output
-                          {.operandDimensions = {{0, {1}}},
-                           .quant8AsymmOperands = {{0, {outputValue}}}}}}};
-}
+constexpr auto get_test_model = generated_tests::mobilenet_quantized::get_test_model;
 
 }  // namespace quant8_model
 
@@ -140,39 +113,34 @@
 //               [1]    [1]    [1]           [1]
 //
 // This function assumes the operation is either ADD or MUL.
-template <typename CppType, OperandType operandType>
-Model createLargeTestModelImpl(OperationType op, uint32_t len) {
-    EXPECT_TRUE(op == OperationType::ADD || op == OperationType::MUL);
+template <typename CppType, TestOperandType operandType>
+TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) {
+    EXPECT_TRUE(op == TestOperationType::ADD || op == TestOperationType::MUL);
 
     // Model operations and operands.
-    std::vector<Operation> operations(len);
-    std::vector<Operand> operands(len * 2 + 2);
-
-    // The constant buffer pool. This contains the activation scalar, followed by the
-    // per-operation constant operands.
-    std::vector<uint8_t> operandValues(sizeof(int32_t) + len * sizeof(CppType));
+    std::vector<TestOperation> operations(len);
+    std::vector<TestOperand> operands(len * 2 + 2);
 
     // The activation scalar, value = 0.
     operands[0] = {
-            .type = OperandType::INT32,
+            .type = TestOperandType::INT32,
             .dimensions = {},
             .numberOfConsumers = len,
             .scale = 0.0f,
             .zeroPoint = 0,
-            .lifetime = OperandLifeTime::CONSTANT_COPY,
-            .location = {.poolIndex = 0, .offset = 0, .length = sizeof(int32_t)},
+            .lifetime = TestOperandLifeTime::CONSTANT_COPY,
+            .data = TestBuffer::createFromVector<int32_t>({0}),
     };
-    memset(operandValues.data(), 0, sizeof(int32_t));
 
     // The buffer value of the constant second operand. The logical value is always 1.0f.
     CppType bufferValue;
     // The scale of the first and second operand.
     float scale1, scale2;
-    if (operandType == OperandType::TENSOR_FLOAT32) {
+    if (operandType == TestOperandType::TENSOR_FLOAT32) {
         bufferValue = 1.0f;
         scale1 = 0.0f;
         scale2 = 0.0f;
-    } else if (op == OperationType::ADD) {
+    } else if (op == TestOperationType::ADD) {
         bufferValue = 1;
         scale1 = 1.0f;
         scale2 = 1.0f;
@@ -196,9 +164,9 @@
                 .numberOfConsumers = 1,
                 .scale = scale1,
                 .zeroPoint = 0,
-                .lifetime = (i == 0 ? OperandLifeTime::MODEL_INPUT
-                                    : OperandLifeTime::TEMPORARY_VARIABLE),
-                .location = {},
+                .lifetime = (i == 0 ? TestOperandLifeTime::MODEL_INPUT
+                                    : TestOperandLifeTime::TEMPORARY_VARIABLE),
+                .data = (i == 0 ? TestBuffer::createFromVector<CppType>({1}) : TestBuffer()),
         };
 
         // The second operation input, value = 1.
@@ -208,13 +176,9 @@
                 .numberOfConsumers = 1,
                 .scale = scale2,
                 .zeroPoint = 0,
-                .lifetime = OperandLifeTime::CONSTANT_COPY,
-                .location = {.poolIndex = 0,
-                             .offset = static_cast<uint32_t>(i * sizeof(CppType) + sizeof(int32_t)),
-                             .length = sizeof(CppType)},
+                .lifetime = TestOperandLifeTime::CONSTANT_COPY,
+                .data = TestBuffer::createFromVector<CppType>({bufferValue}),
         };
-        memcpy(operandValues.data() + sizeof(int32_t) + i * sizeof(CppType), &bufferValue,
-               sizeof(CppType));
 
         // The operation. All operations share the same activation scalar.
         // The output operand is created as an input in the next iteration of the loop, in the case
@@ -227,6 +191,10 @@
         };
     }
 
+    // For TestOperationType::ADD, output = 1 + 1 * len = len + 1
+    // For TestOperationType::MUL, output = 1 * 1 ^ len = 1
+    CppType outputResult = static_cast<CppType>(op == TestOperationType::ADD ? len + 1u : 1u);
+
     // The model output.
     operands.back() = {
             .type = operandType,
@@ -234,34 +202,30 @@
             .numberOfConsumers = 0,
             .scale = scale1,
             .zeroPoint = 0,
-            .lifetime = OperandLifeTime::MODEL_OUTPUT,
-            .location = {},
+            .lifetime = TestOperandLifeTime::MODEL_OUTPUT,
+            .data = TestBuffer::createFromVector<CppType>({outputResult}),
     };
 
-    const std::vector<uint32_t> inputIndexes = {1};
-    const std::vector<uint32_t> outputIndexes = {len * 2 + 1};
-    const std::vector<hidl_memory> pools = {};
-
     return {
-            .operands = operands,
-            .operations = operations,
-            .inputIndexes = inputIndexes,
-            .outputIndexes = outputIndexes,
-            .operandValues = operandValues,
-            .pools = pools,
+            .operands = std::move(operands),
+            .operations = std::move(operations),
+            .inputIndexes = {1},
+            .outputIndexes = {len * 2 + 1},
+            .isRelaxed = false,
     };
 }
 
 }  // namespace
 
 // Tag for the compilation caching tests.
-class CompilationCachingTestBase : public NeuralnetworksHidlTest {
+class CompilationCachingTestBase : public testing::Test {
   protected:
-    CompilationCachingTestBase(OperandType type) : kOperandType(type) {}
+    CompilationCachingTestBase(sp<IDevice> device, OperandType type)
+        : kDevice(std::move(device)), kOperandType(type) {}
 
     void SetUp() override {
-        NeuralnetworksHidlTest::SetUp();
-        ASSERT_NE(device.get(), nullptr);
+        testing::Test::SetUp();
+        ASSERT_NE(kDevice.get(), nullptr);
 
         // Create cache directory. The cache directory and a temporary cache file is always created
         // to test the behavior of prepareModelFromCache, even when caching is not supported.
@@ -271,7 +235,7 @@
         mCacheDir = cacheDir;
         mCacheDir.push_back('/');
 
-        Return<void> ret = device->getNumberOfCacheFilesNeeded(
+        Return<void> ret = kDevice->getNumberOfCacheFilesNeeded(
                 [this](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) {
                     EXPECT_EQ(ErrorStatus::NONE, status);
                     mNumModelCache = numModelCache;
@@ -305,54 +269,40 @@
 
     void TearDown() override {
         // If the test passes, remove the tmp directory.  Otherwise, keep it for debugging purposes.
-        if (!::testing::Test::HasFailure()) {
+        if (!testing::Test::HasFailure()) {
             // Recursively remove the cache directory specified by mCacheDir.
             auto callback = [](const char* entry, const struct stat*, int, struct FTW*) {
                 return remove(entry);
             };
             nftw(mCacheDir.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
         }
-        NeuralnetworksHidlTest::TearDown();
+        testing::Test::TearDown();
     }
 
     // Model and examples creators. According to kOperandType, the following methods will return
     // either float32 model/examples or the quant8 variant.
-    Model createTestModel() {
+    TestModel createTestModel() {
         if (kOperandType == OperandType::TENSOR_FLOAT32) {
-            return float32_model::createTestModel();
+            return float32_model::get_test_model();
         } else {
-            return quant8_model::createTestModel();
+            return quant8_model::get_test_model();
         }
     }
 
-    std::vector<MixedTypedExample> get_examples() {
+    TestModel createLargeTestModel(OperationType op, uint32_t len) {
         if (kOperandType == OperandType::TENSOR_FLOAT32) {
-            return float32_model::get_examples();
+            return createLargeTestModelImpl<float, TestOperandType::TENSOR_FLOAT32>(
+                    static_cast<TestOperationType>(op), len);
         } else {
-            return quant8_model::get_examples();
-        }
-    }
-
-    Model createLargeTestModel(OperationType op, uint32_t len) {
-        if (kOperandType == OperandType::TENSOR_FLOAT32) {
-            return createLargeTestModelImpl<float, OperandType::TENSOR_FLOAT32>(op, len);
-        } else {
-            return createLargeTestModelImpl<uint8_t, OperandType::TENSOR_QUANT8_ASYMM>(op, len);
-        }
-    }
-
-    std::vector<MixedTypedExample> getLargeModelExamples(uint32_t len) {
-        if (kOperandType == OperandType::TENSOR_FLOAT32) {
-            return float32_model::getLargeModelExamples(len);
-        } else {
-            return quant8_model::getLargeModelExamples(len);
+            return createLargeTestModelImpl<uint8_t, TestOperandType::TENSOR_QUANT8_ASYMM>(
+                    static_cast<TestOperationType>(op), len);
         }
     }
 
     // See if the service can handle the model.
-    bool isModelFullySupported(const V1_2::Model& model) {
+    bool isModelFullySupported(const Model& model) {
         bool fullySupportsModel = false;
-        Return<void> supportedCall = device->getSupportedOperations_1_2(
+        Return<void> supportedCall = kDevice->getSupportedOperations_1_2(
                 model,
                 [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec<bool>& supported) {
                     ASSERT_EQ(ErrorStatus::NONE, status);
@@ -364,18 +314,17 @@
         return fullySupportsModel;
     }
 
-    void saveModelToCache(const V1_2::Model& model, const hidl_vec<hidl_handle>& modelCache,
+    void saveModelToCache(const Model& model, const hidl_vec<hidl_handle>& modelCache,
                           const hidl_vec<hidl_handle>& dataCache,
                           sp<IPreparedModel>* preparedModel = nullptr) {
         if (preparedModel != nullptr) *preparedModel = nullptr;
 
         // Launch prepare model.
         sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-        ASSERT_NE(nullptr, preparedModelCallback.get());
         hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
         Return<ErrorStatus> prepareLaunchStatus =
-                device->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER, modelCache,
-                                         dataCache, cacheToken, preparedModelCallback);
+                kDevice->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER,
+                                          modelCache, dataCache, cacheToken, preparedModelCallback);
         ASSERT_TRUE(prepareLaunchStatus.isOk());
         ASSERT_EQ(static_cast<ErrorStatus>(prepareLaunchStatus), ErrorStatus::NONE);
 
@@ -383,9 +332,8 @@
         preparedModelCallback->wait();
         ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE);
         if (preparedModel != nullptr) {
-            *preparedModel =
-                    V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
-                            .withDefault(nullptr);
+            *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
+                                     .withDefault(nullptr);
         }
     }
 
@@ -401,7 +349,7 @@
         return false;
     }
 
-    bool checkEarlyTermination(const V1_2::Model& model) {
+    bool checkEarlyTermination(const Model& model) {
         if (!isModelFullySupported(model)) {
             LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
                          "prepare model that it does not support.";
@@ -418,9 +366,8 @@
                                sp<IPreparedModel>* preparedModel, ErrorStatus* status) {
         // Launch prepare model from cache.
         sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-        ASSERT_NE(nullptr, preparedModelCallback.get());
         hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
-        Return<ErrorStatus> prepareLaunchStatus = device->prepareModelFromCache(
+        Return<ErrorStatus> prepareLaunchStatus = kDevice->prepareModelFromCache(
                 modelCache, dataCache, cacheToken, preparedModelCallback);
         ASSERT_TRUE(prepareLaunchStatus.isOk());
         if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) {
@@ -432,7 +379,7 @@
         // Retrieve prepared model.
         preparedModelCallback->wait();
         *status = preparedModelCallback->getStatus();
-        *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
+        *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
                                  .withDefault(nullptr);
     }
 
@@ -453,22 +400,28 @@
     uint32_t mNumDataCache;
     uint32_t mIsCachingSupported;
 
+    const sp<IDevice> kDevice;
     // The primary data type of the testModel.
     const OperandType kOperandType;
 };
 
+using CompilationCachingTestParam = std::tuple<NamedDevice, OperandType>;
+
 // A parameterized fixture of CompilationCachingTestBase. Every test will run twice, with the first
 // pass running with float32 models and the second pass running with quant8 models.
 class CompilationCachingTest : public CompilationCachingTestBase,
-                               public ::testing::WithParamInterface<OperandType> {
+                               public testing::WithParamInterface<CompilationCachingTestParam> {
   protected:
-    CompilationCachingTest() : CompilationCachingTestBase(GetParam()) {}
+    CompilationCachingTest()
+        : CompilationCachingTestBase(getData(std::get<NamedDevice>(GetParam())),
+                                     std::get<OperandType>(GetParam())) {}
 };
 
 TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) {
     // Create test HIDL model and compile.
-    const Model testModel = createTestModel();
-    if (checkEarlyTermination(testModel)) return;
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
     sp<IPreparedModel> preparedModel = nullptr;
 
     // Save the compilation to cache.
@@ -476,7 +429,7 @@
         hidl_vec<hidl_handle> modelCache, dataCache;
         createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-        saveModelToCache(testModel, modelCache, dataCache);
+        saveModelToCache(model, modelCache, dataCache);
     }
 
     // Retrieve preparedModel from cache.
@@ -501,15 +454,15 @@
     }
 
     // Execute and verify results.
-    generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
-                                           testModel.relaxComputationFloat32toFloat16,
-                                           /*testDynamicOutputShape=*/false);
+    EvaluatePreparedModel(preparedModel, testModel,
+                          /*testDynamicOutputShape=*/false);
 }
 
 TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
     // Create test HIDL model and compile.
-    const Model testModel = createTestModel();
-    if (checkEarlyTermination(testModel)) return;
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
     sp<IPreparedModel> preparedModel = nullptr;
 
     // Save the compilation to cache.
@@ -530,7 +483,7 @@
                     write(dataCache[i].getNativeHandle()->data[0], &dummyBytes, sizeof(dummyBytes)),
                     sizeof(dummyBytes));
         }
-        saveModelToCache(testModel, modelCache, dataCache);
+        saveModelToCache(model, modelCache, dataCache);
     }
 
     // Retrieve preparedModel from cache.
@@ -564,15 +517,15 @@
     }
 
     // Execute and verify results.
-    generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
-                                           testModel.relaxComputationFloat32toFloat16,
-                                           /*testDynamicOutputShape=*/false);
+    EvaluatePreparedModel(preparedModel, testModel,
+                          /*testDynamicOutputShape=*/false);
 }
 
 TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) {
     // Create test HIDL model and compile.
-    const Model testModel = createTestModel();
-    if (checkEarlyTermination(testModel)) return;
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
 
     // Test with number of model cache files greater than mNumModelCache.
     {
@@ -583,13 +536,11 @@
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mModelCache.pop_back();
         sp<IPreparedModel> preparedModel = nullptr;
-        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
-                                               get_examples(),
-                                               testModel.relaxComputationFloat32toFloat16,
-                                               /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel,
+                              /*testDynamicOutputShape=*/false);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -610,13 +561,11 @@
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mModelCache.push_back(tmp);
         sp<IPreparedModel> preparedModel = nullptr;
-        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
-                                               get_examples(),
-                                               testModel.relaxComputationFloat32toFloat16,
-                                               /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel,
+                              /*testDynamicOutputShape=*/false);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -636,13 +585,11 @@
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mDataCache.pop_back();
         sp<IPreparedModel> preparedModel = nullptr;
-        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
-                                               get_examples(),
-                                               testModel.relaxComputationFloat32toFloat16,
-                                               /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel,
+                              /*testDynamicOutputShape=*/false);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -663,13 +610,11 @@
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mDataCache.push_back(tmp);
         sp<IPreparedModel> preparedModel = nullptr;
-        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
-                                               get_examples(),
-                                               testModel.relaxComputationFloat32toFloat16,
-                                               /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel,
+                              /*testDynamicOutputShape=*/false);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -683,15 +628,16 @@
 
 TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumCache) {
     // Create test HIDL model and compile.
-    const Model testModel = createTestModel();
-    if (checkEarlyTermination(testModel)) return;
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
 
     // Save the compilation to cache.
     {
         hidl_vec<hidl_handle> modelCache, dataCache;
         createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-        saveModelToCache(testModel, modelCache, dataCache);
+        saveModelToCache(model, modelCache, dataCache);
     }
 
     // Test with number of model cache files greater than mNumModelCache.
@@ -763,8 +709,9 @@
 
 TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) {
     // Create test HIDL model and compile.
-    const Model testModel = createTestModel();
-    if (checkEarlyTermination(testModel)) return;
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
 
     // Go through each handle in model cache, test with NumFd greater than 1.
     for (uint32_t i = 0; i < mNumModelCache; i++) {
@@ -775,13 +722,11 @@
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mModelCache[i].pop_back();
         sp<IPreparedModel> preparedModel = nullptr;
-        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
-                                               get_examples(),
-                                               testModel.relaxComputationFloat32toFloat16,
-                                               /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel,
+                              /*testDynamicOutputShape=*/false);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -802,13 +747,11 @@
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mModelCache[i].push_back(tmp);
         sp<IPreparedModel> preparedModel = nullptr;
-        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
-                                               get_examples(),
-                                               testModel.relaxComputationFloat32toFloat16,
-                                               /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel,
+                              /*testDynamicOutputShape=*/false);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -828,13 +771,11 @@
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mDataCache[i].pop_back();
         sp<IPreparedModel> preparedModel = nullptr;
-        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
-                                               get_examples(),
-                                               testModel.relaxComputationFloat32toFloat16,
-                                               /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel,
+                              /*testDynamicOutputShape=*/false);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -855,13 +796,11 @@
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mDataCache[i].push_back(tmp);
         sp<IPreparedModel> preparedModel = nullptr;
-        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
-                                               get_examples(),
-                                               testModel.relaxComputationFloat32toFloat16,
-                                               /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel,
+                              /*testDynamicOutputShape=*/false);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -875,15 +814,16 @@
 
 TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) {
     // Create test HIDL model and compile.
-    const Model testModel = createTestModel();
-    if (checkEarlyTermination(testModel)) return;
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
 
     // Save the compilation to cache.
     {
         hidl_vec<hidl_handle> modelCache, dataCache;
         createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-        saveModelToCache(testModel, modelCache, dataCache);
+        saveModelToCache(model, modelCache, dataCache);
     }
 
     // Go through each handle in model cache, test with NumFd greater than 1.
@@ -955,8 +895,9 @@
 
 TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) {
     // Create test HIDL model and compile.
-    const Model testModel = createTestModel();
-    if (checkEarlyTermination(testModel)) return;
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
     std::vector<AccessMode> modelCacheMode(mNumModelCache, AccessMode::READ_WRITE);
     std::vector<AccessMode> dataCacheMode(mNumDataCache, AccessMode::READ_WRITE);
 
@@ -968,13 +909,11 @@
         createCacheHandles(mDataCache, dataCacheMode, &dataCache);
         modelCacheMode[i] = AccessMode::READ_WRITE;
         sp<IPreparedModel> preparedModel = nullptr;
-        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
-                                               get_examples(),
-                                               testModel.relaxComputationFloat32toFloat16,
-                                               /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel,
+                              /*testDynamicOutputShape=*/false);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -993,13 +932,11 @@
         createCacheHandles(mDataCache, dataCacheMode, &dataCache);
         dataCacheMode[i] = AccessMode::READ_WRITE;
         sp<IPreparedModel> preparedModel = nullptr;
-        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
-                                               get_examples(),
-                                               testModel.relaxComputationFloat32toFloat16,
-                                               /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel,
+                              /*testDynamicOutputShape=*/false);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -1013,8 +950,9 @@
 
 TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) {
     // Create test HIDL model and compile.
-    const Model testModel = createTestModel();
-    if (checkEarlyTermination(testModel)) return;
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
     std::vector<AccessMode> modelCacheMode(mNumModelCache, AccessMode::READ_WRITE);
     std::vector<AccessMode> dataCacheMode(mNumDataCache, AccessMode::READ_WRITE);
 
@@ -1023,7 +961,7 @@
         hidl_vec<hidl_handle> modelCache, dataCache;
         createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-        saveModelToCache(testModel, modelCache, dataCache);
+        saveModelToCache(model, modelCache, dataCache);
     }
 
     // Go through each handle in model cache, test with invalid access mode.
@@ -1091,12 +1029,14 @@
     if (!mIsCachingSupported) return;
 
     // Create test models and check if fully supported by the service.
-    const Model testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
-    if (checkEarlyTermination(testModelMul)) return;
-    const Model testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
-    if (checkEarlyTermination(testModelAdd)) return;
+    const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
+    const Model modelMul = createModel(testModelMul);
+    if (checkEarlyTermination(modelMul)) return;
+    const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
+    const Model modelAdd = createModel(testModelAdd);
+    if (checkEarlyTermination(modelAdd)) return;
 
-    // Save the testModelMul compilation to cache.
+    // Save the modelMul compilation to cache.
     auto modelCacheMul = mModelCache;
     for (auto& cache : modelCacheMul) {
         cache[0].append("_mul");
@@ -1105,15 +1045,15 @@
         hidl_vec<hidl_handle> modelCache, dataCache;
         createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-        saveModelToCache(testModelMul, modelCache, dataCache);
+        saveModelToCache(modelMul, modelCache, dataCache);
     }
 
-    // Use a different token for testModelAdd.
+    // Use a different token for modelAdd.
     mToken[0]++;
 
     // This test is probabilistic, so we run it multiple times.
     for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
-        // Save the testModelAdd compilation to cache.
+        // Save the modelAdd compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
@@ -1121,7 +1061,7 @@
 
             // Spawn a thread to copy the cache content concurrently while saving to cache.
             std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
-            saveModelToCache(testModelAdd, modelCache, dataCache);
+            saveModelToCache(modelAdd, modelCache, dataCache);
             thread.join();
         }
 
@@ -1140,11 +1080,8 @@
                 ASSERT_EQ(preparedModel, nullptr);
             } else {
                 ASSERT_NE(preparedModel, nullptr);
-                generated_tests::EvaluatePreparedModel(
-                        preparedModel, [](int) { return false; },
-                        getLargeModelExamples(kLargeModelSize),
-                        testModelAdd.relaxComputationFloat32toFloat16,
-                        /*testDynamicOutputShape=*/false);
+                EvaluatePreparedModel(preparedModel, testModelAdd,
+                                      /*testDynamicOutputShape=*/false);
             }
         }
     }
@@ -1154,12 +1091,14 @@
     if (!mIsCachingSupported) return;
 
     // Create test models and check if fully supported by the service.
-    const Model testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
-    if (checkEarlyTermination(testModelMul)) return;
-    const Model testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
-    if (checkEarlyTermination(testModelAdd)) return;
+    const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
+    const Model modelMul = createModel(testModelMul);
+    if (checkEarlyTermination(modelMul)) return;
+    const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
+    const Model modelAdd = createModel(testModelAdd);
+    if (checkEarlyTermination(modelAdd)) return;
 
-    // Save the testModelMul compilation to cache.
+    // Save the modelMul compilation to cache.
     auto modelCacheMul = mModelCache;
     for (auto& cache : modelCacheMul) {
         cache[0].append("_mul");
@@ -1168,20 +1107,20 @@
         hidl_vec<hidl_handle> modelCache, dataCache;
         createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-        saveModelToCache(testModelMul, modelCache, dataCache);
+        saveModelToCache(modelMul, modelCache, dataCache);
     }
 
-    // Use a different token for testModelAdd.
+    // Use a different token for modelAdd.
     mToken[0]++;
 
     // This test is probabilistic, so we run it multiple times.
     for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
-        // Save the testModelAdd compilation to cache.
+        // Save the modelAdd compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-            saveModelToCache(testModelAdd, modelCache, dataCache);
+            saveModelToCache(modelAdd, modelCache, dataCache);
         }
 
         // Retrieve preparedModel from cache.
@@ -1203,11 +1142,8 @@
                 ASSERT_EQ(preparedModel, nullptr);
             } else {
                 ASSERT_NE(preparedModel, nullptr);
-                generated_tests::EvaluatePreparedModel(
-                        preparedModel, [](int) { return false; },
-                        getLargeModelExamples(kLargeModelSize),
-                        testModelAdd.relaxComputationFloat32toFloat16,
-                        /*testDynamicOutputShape=*/false);
+                EvaluatePreparedModel(preparedModel, testModelAdd,
+                                      /*testDynamicOutputShape=*/false);
             }
         }
     }
@@ -1217,12 +1153,14 @@
     if (!mIsCachingSupported) return;
 
     // Create test models and check if fully supported by the service.
-    const Model testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
-    if (checkEarlyTermination(testModelMul)) return;
-    const Model testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
-    if (checkEarlyTermination(testModelAdd)) return;
+    const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
+    const Model modelMul = createModel(testModelMul);
+    if (checkEarlyTermination(modelMul)) return;
+    const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
+    const Model modelAdd = createModel(testModelAdd);
+    if (checkEarlyTermination(modelAdd)) return;
 
-    // Save the testModelMul compilation to cache.
+    // Save the modelMul compilation to cache.
     auto modelCacheMul = mModelCache;
     for (auto& cache : modelCacheMul) {
         cache[0].append("_mul");
@@ -1231,21 +1169,21 @@
         hidl_vec<hidl_handle> modelCache, dataCache;
         createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-        saveModelToCache(testModelMul, modelCache, dataCache);
+        saveModelToCache(modelMul, modelCache, dataCache);
     }
 
-    // Use a different token for testModelAdd.
+    // Use a different token for modelAdd.
     mToken[0]++;
 
-    // Save the testModelAdd compilation to cache.
+    // Save the modelAdd compilation to cache.
     {
         hidl_vec<hidl_handle> modelCache, dataCache;
         createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
         createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-        saveModelToCache(testModelAdd, modelCache, dataCache);
+        saveModelToCache(modelAdd, modelCache, dataCache);
     }
 
-    // Replace the model cache of testModelAdd with testModelMul.
+    // Replace the model cache of modelAdd with modelMul.
     copyCacheFiles(modelCacheMul, mModelCache);
 
     // Retrieve the preparedModel from cache, expect failure.
@@ -1261,16 +1199,30 @@
     }
 }
 
+static const auto kNamedDeviceChoices = testing::ValuesIn(getNamedDevices());
 static const auto kOperandTypeChoices =
-        ::testing::Values(OperandType::TENSOR_FLOAT32, OperandType::TENSOR_QUANT8_ASYMM);
+        testing::Values(OperandType::TENSOR_FLOAT32, OperandType::TENSOR_QUANT8_ASYMM);
 
-INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest, kOperandTypeChoices);
+std::string printCompilationCachingTest(
+        const testing::TestParamInfo<CompilationCachingTestParam>& info) {
+    const auto& [namedDevice, operandType] = info.param;
+    const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8");
+    return gtestCompliantName(getName(namedDevice) + "_" + type);
+}
+
+INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest,
+                        testing::Combine(kNamedDeviceChoices, kOperandTypeChoices),
+                        printCompilationCachingTest);
+
+using CompilationCachingSecurityTestParam = std::tuple<NamedDevice, OperandType, uint32_t>;
 
 class CompilationCachingSecurityTest
     : public CompilationCachingTestBase,
-      public ::testing::WithParamInterface<std::tuple<OperandType, uint32_t>> {
+      public testing::WithParamInterface<CompilationCachingSecurityTestParam> {
   protected:
-    CompilationCachingSecurityTest() : CompilationCachingTestBase(std::get<0>(GetParam())) {}
+    CompilationCachingSecurityTest()
+        : CompilationCachingTestBase(getData(std::get<NamedDevice>(GetParam())),
+                                     std::get<OperandType>(GetParam())) {}
 
     void SetUp() {
         CompilationCachingTestBase::SetUp();
@@ -1321,15 +1273,16 @@
     // The modifier accepts one pointer argument "skip" as the returning value, indicating
     // whether the test should be skipped or not.
     void testCorruptedCache(ExpectedResult expected, std::function<void(bool*)> modifier) {
-        const Model testModel = createTestModel();
-        if (checkEarlyTermination(testModel)) return;
+        const TestModel& testModel = createTestModel();
+        const Model model = createModel(testModel);
+        if (checkEarlyTermination(model)) return;
 
         // Save the compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-            saveModelToCache(testModel, modelCache, dataCache);
+            saveModelToCache(model, modelCache, dataCache);
         }
 
         bool skip = false;
@@ -1359,7 +1312,7 @@
         }
     }
 
-    const uint32_t kSeed = std::get<1>(GetParam());
+    const uint32_t kSeed = std::get<uint32_t>(GetParam());
     std::mt19937 generator;
 };
 
@@ -1406,12 +1359,16 @@
     });
 }
 
-INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest,
-                        ::testing::Combine(kOperandTypeChoices, ::testing::Range(0U, 10U)));
+std::string printCompilationCachingSecurityTest(
+        const testing::TestParamInfo<CompilationCachingSecurityTestParam>& info) {
+    const auto& [namedDevice, operandType, seed] = info.param;
+    const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8");
+    return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + std::to_string(seed));
+}
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest,
+                        testing::Combine(kNamedDeviceChoices, kOperandTypeChoices,
+                                         testing::Range(0U, 10U)),
+                        printCompilationCachingSecurityTest);
+
+}  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
new file mode 100644
index 0000000..4909214
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -0,0 +1,410 @@
+/*
+ * 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 "GeneratedTestHarness.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <gtest/gtest.h>
+#include <hidlmemory/mapping.h>
+
+#include <algorithm>
+#include <chrono>
+#include <iostream>
+#include <numeric>
+#include <vector>
+
+#include "1.0/Utils.h"
+#include "1.2/Callbacks.h"
+#include "ExecutionBurstController.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
+
+using namespace test_helper;
+using hidl::memory::V1_0::IMemory;
+using implementation::ExecutionCallback;
+using implementation::PreparedModelCallback;
+using V1_0::DataLocation;
+using V1_0::ErrorStatus;
+using V1_0::OperandLifeTime;
+using V1_0::Request;
+using V1_1::ExecutionPreference;
+using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+
+namespace {
+
+enum class Executor { ASYNC, SYNC, BURST };
+
+enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
+
+struct TestConfig {
+    Executor executor;
+    MeasureTiming measureTiming;
+    OutputType outputType;
+};
+
+}  // namespace
+
+Model createModel(const TestModel& testModel) {
+    // Model operands.
+    hidl_vec<Operand> operands(testModel.operands.size());
+    size_t constCopySize = 0, constRefSize = 0;
+    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+        const auto& op = testModel.operands[i];
+
+        DataLocation loc = {};
+        if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+            loc = {.poolIndex = 0,
+                   .offset = static_cast<uint32_t>(constCopySize),
+                   .length = static_cast<uint32_t>(op.data.size())};
+            constCopySize += op.data.alignedSize();
+        } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+            loc = {.poolIndex = 0,
+                   .offset = static_cast<uint32_t>(constRefSize),
+                   .length = static_cast<uint32_t>(op.data.size())};
+            constRefSize += op.data.alignedSize();
+        }
+
+        Operand::ExtraParams extraParams;
+        if (op.type == TestOperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) {
+            extraParams.channelQuant(SymmPerChannelQuantParams{
+                    .scales = op.channelQuant.scales, .channelDim = op.channelQuant.channelDim});
+        }
+
+        operands[i] = {.type = static_cast<OperandType>(op.type),
+                       .dimensions = op.dimensions,
+                       .numberOfConsumers = op.numberOfConsumers,
+                       .scale = op.scale,
+                       .zeroPoint = op.zeroPoint,
+                       .lifetime = static_cast<OperandLifeTime>(op.lifetime),
+                       .location = loc,
+                       .extraParams = std::move(extraParams)};
+    }
+
+    // Model operations.
+    hidl_vec<Operation> operations(testModel.operations.size());
+    std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
+                   [](const TestOperation& op) -> Operation {
+                       return {.type = static_cast<OperationType>(op.type),
+                               .inputs = op.inputs,
+                               .outputs = op.outputs};
+                   });
+
+    // Constant copies.
+    hidl_vec<uint8_t> operandValues(constCopySize);
+    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+        const auto& op = testModel.operands[i];
+        if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+            const uint8_t* begin = op.data.get<uint8_t>();
+            const uint8_t* end = begin + op.data.size();
+            std::copy(begin, end, operandValues.data() + operands[i].location.offset);
+        }
+    }
+
+    // Shared memory.
+    hidl_vec<hidl_memory> pools = {};
+    if (constRefSize > 0) {
+        hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize));
+        CHECK_NE(pools[0].size(), 0u);
+
+        // load data
+        sp<IMemory> mappedMemory = mapMemory(pools[0]);
+        CHECK(mappedMemory.get() != nullptr);
+        uint8_t* mappedPtr =
+                reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
+        CHECK(mappedPtr != nullptr);
+
+        for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+            const auto& op = testModel.operands[i];
+            if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+                const uint8_t* begin = op.data.get<uint8_t>();
+                const uint8_t* end = begin + op.data.size();
+                std::copy(begin, end, mappedPtr + operands[i].location.offset);
+            }
+        }
+    }
+
+    return {.operands = std::move(operands),
+            .operations = std::move(operations),
+            .inputIndexes = testModel.inputIndexes,
+            .outputIndexes = testModel.outputIndexes,
+            .operandValues = std::move(operandValues),
+            .pools = std::move(pools),
+            .relaxComputationFloat32toFloat16 = testModel.isRelaxed};
+}
+
+static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) {
+    const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size();
+    return byteSize > 1u;
+}
+
+static void makeOutputInsufficientSize(uint32_t outputIndex, Request* request) {
+    auto& length = request->outputs[outputIndex].location.length;
+    ASSERT_GT(length, 1u);
+    length -= 1u;
+}
+
+static void makeOutputDimensionsUnspecified(Model* model) {
+    for (auto i : model->outputIndexes) {
+        auto& dims = model->operands[i].dimensions;
+        std::fill(dims.begin(), dims.end(), 0);
+    }
+}
+
+static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
+                                                const Request& request, MeasureTiming measure,
+                                                sp<ExecutionCallback>& callback) {
+    return preparedModel->execute_1_2(request, measure, callback);
+}
+static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
+                                                const Request& request, MeasureTiming measure,
+                                                hidl_vec<OutputShape>* outputShapes,
+                                                Timing* timing) {
+    ErrorStatus result;
+    Return<void> ret = preparedModel->executeSynchronously(
+            request, measure,
+            [&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
+                                            const Timing& time) {
+                result = error;
+                *outputShapes = shapes;
+                *timing = time;
+            });
+    if (!ret.isOk()) {
+        return ErrorStatus::GENERAL_FAILURE;
+    }
+    return result;
+}
+static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst(
+        const sp<IPreparedModel>& preparedModel) {
+    return android::nn::ExecutionBurstController::create(preparedModel,
+                                                         std::chrono::microseconds{0});
+}
+
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
+                           const TestConfig& testConfig) {
+    // If output0 does not have size larger than one byte, we can not test with insufficient buffer.
+    if (testConfig.outputType == OutputType::INSUFFICIENT &&
+        !isOutputSizeGreaterThanOne(testModel, 0)) {
+        return;
+    }
+
+    Request request = createRequest(testModel);
+    if (testConfig.outputType == OutputType::INSUFFICIENT) {
+        makeOutputInsufficientSize(/*outputIndex=*/0, &request);
+    }
+
+    ErrorStatus executionStatus;
+    hidl_vec<OutputShape> outputShapes;
+    Timing timing;
+    switch (testConfig.executor) {
+        case Executor::ASYNC: {
+            SCOPED_TRACE("asynchronous");
+
+            // launch execution
+            sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+            Return<ErrorStatus> executionLaunchStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, executionCallback);
+            ASSERT_TRUE(executionLaunchStatus.isOk());
+            EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
+
+            // retrieve execution status
+            executionCallback->wait();
+            executionStatus = executionCallback->getStatus();
+            outputShapes = executionCallback->getOutputShapes();
+            timing = executionCallback->getTiming();
+
+            break;
+        }
+        case Executor::SYNC: {
+            SCOPED_TRACE("synchronous");
+
+            // execute
+            Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, &outputShapes, &timing);
+            ASSERT_TRUE(executionReturnStatus.isOk());
+            executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
+
+            break;
+        }
+        case Executor::BURST: {
+            SCOPED_TRACE("burst");
+
+            // create burst
+            const std::shared_ptr<::android::nn::ExecutionBurstController> controller =
+                    CreateBurst(preparedModel);
+            ASSERT_NE(nullptr, controller.get());
+
+            // create memory keys
+            std::vector<intptr_t> keys(request.pools.size());
+            for (size_t i = 0; i < keys.size(); ++i) {
+                keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
+            }
+
+            // execute burst
+            int n;
+            std::tie(n, outputShapes, timing, std::ignore) =
+                    controller->compute(request, testConfig.measureTiming, keys);
+            executionStatus = nn::convertResultCodeToErrorStatus(n);
+
+            break;
+        }
+    }
+
+    if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
+        executionStatus == ErrorStatus::GENERAL_FAILURE) {
+        LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                     "execute model that it does not support.";
+        std::cout << "[          ]   Early termination of test because vendor service cannot "
+                     "execute model that it does not support."
+                  << std::endl;
+        GTEST_SKIP();
+    }
+    if (testConfig.measureTiming == MeasureTiming::NO) {
+        EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
+        EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
+    } else {
+        if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) {
+            EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
+        }
+    }
+
+    switch (testConfig.outputType) {
+        case OutputType::FULLY_SPECIFIED:
+            // If the model output operands are fully specified, outputShapes must be either
+            // either empty, or have the same number of elements as the number of outputs.
+            ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+            ASSERT_TRUE(outputShapes.size() == 0 ||
+                        outputShapes.size() == testModel.outputIndexes.size());
+            break;
+        case OutputType::UNSPECIFIED:
+            // If the model output operands are not fully specified, outputShapes must have
+            // the same number of elements as the number of outputs.
+            ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+            ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
+            break;
+        case OutputType::INSUFFICIENT:
+            ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
+            ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
+            ASSERT_FALSE(outputShapes[0].isSufficient);
+            return;
+    }
+
+    // Go through all outputs, check returned output shapes.
+    for (uint32_t i = 0; i < outputShapes.size(); i++) {
+        EXPECT_TRUE(outputShapes[i].isSufficient);
+        const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions;
+        const std::vector<uint32_t> actual = outputShapes[i].dimensions;
+        EXPECT_EQ(expect, actual);
+    }
+
+    // Retrieve execution results.
+    const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+
+    // We want "close-enough" results.
+    checkResults(testModel, outputs);
+}
+
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
+                           bool testDynamicOutputShape) {
+    std::vector<OutputType> outputTypesList;
+    std::vector<MeasureTiming> measureTimingList;
+    std::vector<Executor> executorList;
+
+    if (testDynamicOutputShape) {
+        outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
+        measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+        executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+    } else {
+        outputTypesList = {OutputType::FULLY_SPECIFIED};
+        measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+        executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+    }
+
+    for (const OutputType outputType : outputTypesList) {
+        for (const MeasureTiming measureTiming : measureTimingList) {
+            for (const Executor executor : executorList) {
+                const TestConfig testConfig = {.executor = executor,
+                                               .measureTiming = measureTiming,
+                                               .outputType = outputType};
+                EvaluatePreparedModel(preparedModel, testModel, testConfig);
+            }
+        }
+    }
+}
+
+void Execute(const sp<IDevice>& device, const TestModel& testModel, bool testDynamicOutputShape) {
+    Model model = createModel(testModel);
+    if (testDynamicOutputShape) {
+        makeOutputDimensionsUnspecified(&model);
+    }
+
+    sp<IPreparedModel> preparedModel;
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
+
+    EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape);
+}
+
+void GeneratedTestBase::SetUp() {
+    testing::TestWithParam<GeneratedTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
+}
+
+std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
+}
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
+    const auto& [namedDevice, namedModel] = info.param;
+    return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
+}
+
+// Tag for the generated tests
+class GeneratedTest : public GeneratedTestBase {};
+
+// Tag for the dynamic output shape tests
+class DynamicOutputShapeTest : public GeneratedTest {};
+
+TEST_P(GeneratedTest, Test) {
+    Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/false);
+}
+
+TEST_P(DynamicOutputShapeTest, Test) {
+    Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/true);
+}
+
+INSTANTIATE_GENERATED_TEST(GeneratedTest,
+                           [](const TestModel& testModel) { return !testModel.expectFailure; });
+
+INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest,
+                           [](const TestModel& testModel) { return !testModel.expectFailure; });
+
+}  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
new file mode 100644
index 0000000..dfc980c
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H
+
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <functional>
+#include <vector>
+#include "1.0/Utils.h"
+#include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
+
+using NamedModel = Named<const test_helper::TestModel*>;
+using GeneratedTestParam = std::tuple<NamedDevice, NamedModel>;
+
+class GeneratedTestBase : public testing::TestWithParam<GeneratedTestParam> {
+  protected:
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(std::get<NamedDevice>(GetParam()));
+    const test_helper::TestModel& kTestModel = *getData(std::get<NamedModel>(GetParam()));
+};
+
+using FilterFn = std::function<bool(const test_helper::TestModel&)>;
+std::vector<NamedModel> getNamedModels(const FilterFn& filter);
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
+
+#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
+    INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite,                                    \
+                             testing::Combine(testing::ValuesIn(getNamedDevices()),       \
+                                              testing::ValuesIn(getNamedModels(filter))), \
+                             printGeneratedTest)
+
+// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp.
+// TODO: Clean up the hierarchy for ValidationTest.
+class ValidationTest : public GeneratedTestBase {};
+
+Model createModel(const test_helper::TestModel& testModel);
+
+void PrepareModel(const sp<IDevice>& device, const Model& model, sp<IPreparedModel>* preparedModel);
+
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel,
+                           const test_helper::TestModel& testModel, bool testDynamicOutputShape);
+
+}  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
+
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
deleted file mode 100644
index 2c3287a..0000000
--- a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_2_vts_tests.cpp"
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp
deleted file mode 100644
index 990cab9..0000000
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_0_vts_tests.cpp"
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp
deleted file mode 100644
index fa6d54d..0000000
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_1_vts_tests.cpp"
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/TestAssertions.cpp b/neuralnetworks/1.2/vts/functional/TestAssertions.cpp
new file mode 100644
index 0000000..a0aa3c3
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/TestAssertions.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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 <android/hardware/neuralnetworks/1.2/types.h>
+#include "TestHarness.h"
+
+namespace android::hardware::neuralnetworks::V1_2 {
+
+// Make sure that the HIDL enums are compatible with the values defined in
+// frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h.
+using namespace test_helper;
+#define CHECK_TEST_ENUM(EnumType, enumValue) \
+    static_assert(static_cast<EnumType>(Test##EnumType::enumValue) == EnumType::enumValue)
+
+CHECK_TEST_ENUM(OperandType, FLOAT32);
+CHECK_TEST_ENUM(OperandType, INT32);
+CHECK_TEST_ENUM(OperandType, UINT32);
+CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT32);
+CHECK_TEST_ENUM(OperandType, TENSOR_INT32);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM);
+CHECK_TEST_ENUM(OperandType, BOOL);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_SYMM);
+CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT16);
+CHECK_TEST_ENUM(OperandType, TENSOR_BOOL8);
+CHECK_TEST_ENUM(OperandType, FLOAT16);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM_PER_CHANNEL);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_ASYMM);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM);
+
+CHECK_TEST_ENUM(OperationType, ADD);
+CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D);
+CHECK_TEST_ENUM(OperationType, CONCATENATION);
+CHECK_TEST_ENUM(OperationType, CONV_2D);
+CHECK_TEST_ENUM(OperationType, DEPTHWISE_CONV_2D);
+CHECK_TEST_ENUM(OperationType, DEPTH_TO_SPACE);
+CHECK_TEST_ENUM(OperationType, DEQUANTIZE);
+CHECK_TEST_ENUM(OperationType, EMBEDDING_LOOKUP);
+CHECK_TEST_ENUM(OperationType, FLOOR);
+CHECK_TEST_ENUM(OperationType, FULLY_CONNECTED);
+CHECK_TEST_ENUM(OperationType, HASHTABLE_LOOKUP);
+CHECK_TEST_ENUM(OperationType, L2_NORMALIZATION);
+CHECK_TEST_ENUM(OperationType, L2_POOL_2D);
+CHECK_TEST_ENUM(OperationType, LOCAL_RESPONSE_NORMALIZATION);
+CHECK_TEST_ENUM(OperationType, LOGISTIC);
+CHECK_TEST_ENUM(OperationType, LSH_PROJECTION);
+CHECK_TEST_ENUM(OperationType, LSTM);
+CHECK_TEST_ENUM(OperationType, MAX_POOL_2D);
+CHECK_TEST_ENUM(OperationType, MUL);
+CHECK_TEST_ENUM(OperationType, RELU);
+CHECK_TEST_ENUM(OperationType, RELU1);
+CHECK_TEST_ENUM(OperationType, RELU6);
+CHECK_TEST_ENUM(OperationType, RESHAPE);
+CHECK_TEST_ENUM(OperationType, RESIZE_BILINEAR);
+CHECK_TEST_ENUM(OperationType, RNN);
+CHECK_TEST_ENUM(OperationType, SOFTMAX);
+CHECK_TEST_ENUM(OperationType, SPACE_TO_DEPTH);
+CHECK_TEST_ENUM(OperationType, SVDF);
+CHECK_TEST_ENUM(OperationType, TANH);
+CHECK_TEST_ENUM(OperationType, BATCH_TO_SPACE_ND);
+CHECK_TEST_ENUM(OperationType, DIV);
+CHECK_TEST_ENUM(OperationType, MEAN);
+CHECK_TEST_ENUM(OperationType, PAD);
+CHECK_TEST_ENUM(OperationType, SPACE_TO_BATCH_ND);
+CHECK_TEST_ENUM(OperationType, SQUEEZE);
+CHECK_TEST_ENUM(OperationType, STRIDED_SLICE);
+CHECK_TEST_ENUM(OperationType, SUB);
+CHECK_TEST_ENUM(OperationType, TRANSPOSE);
+CHECK_TEST_ENUM(OperationType, ABS);
+CHECK_TEST_ENUM(OperationType, ARGMAX);
+CHECK_TEST_ENUM(OperationType, ARGMIN);
+CHECK_TEST_ENUM(OperationType, AXIS_ALIGNED_BBOX_TRANSFORM);
+CHECK_TEST_ENUM(OperationType, BIDIRECTIONAL_SEQUENCE_LSTM);
+CHECK_TEST_ENUM(OperationType, BIDIRECTIONAL_SEQUENCE_RNN);
+CHECK_TEST_ENUM(OperationType, BOX_WITH_NMS_LIMIT);
+CHECK_TEST_ENUM(OperationType, CAST);
+CHECK_TEST_ENUM(OperationType, CHANNEL_SHUFFLE);
+CHECK_TEST_ENUM(OperationType, DETECTION_POSTPROCESSING);
+CHECK_TEST_ENUM(OperationType, EQUAL);
+CHECK_TEST_ENUM(OperationType, EXP);
+CHECK_TEST_ENUM(OperationType, EXPAND_DIMS);
+CHECK_TEST_ENUM(OperationType, GATHER);
+CHECK_TEST_ENUM(OperationType, GENERATE_PROPOSALS);
+CHECK_TEST_ENUM(OperationType, GREATER);
+CHECK_TEST_ENUM(OperationType, GREATER_EQUAL);
+CHECK_TEST_ENUM(OperationType, GROUPED_CONV_2D);
+CHECK_TEST_ENUM(OperationType, HEATMAP_MAX_KEYPOINT);
+CHECK_TEST_ENUM(OperationType, INSTANCE_NORMALIZATION);
+CHECK_TEST_ENUM(OperationType, LESS);
+CHECK_TEST_ENUM(OperationType, LESS_EQUAL);
+CHECK_TEST_ENUM(OperationType, LOG);
+CHECK_TEST_ENUM(OperationType, LOGICAL_AND);
+CHECK_TEST_ENUM(OperationType, LOGICAL_NOT);
+CHECK_TEST_ENUM(OperationType, LOGICAL_OR);
+CHECK_TEST_ENUM(OperationType, LOG_SOFTMAX);
+CHECK_TEST_ENUM(OperationType, MAXIMUM);
+CHECK_TEST_ENUM(OperationType, MINIMUM);
+CHECK_TEST_ENUM(OperationType, NEG);
+CHECK_TEST_ENUM(OperationType, NOT_EQUAL);
+CHECK_TEST_ENUM(OperationType, PAD_V2);
+CHECK_TEST_ENUM(OperationType, POW);
+CHECK_TEST_ENUM(OperationType, PRELU);
+CHECK_TEST_ENUM(OperationType, QUANTIZE);
+CHECK_TEST_ENUM(OperationType, QUANTIZED_16BIT_LSTM);
+CHECK_TEST_ENUM(OperationType, RANDOM_MULTINOMIAL);
+CHECK_TEST_ENUM(OperationType, REDUCE_ALL);
+CHECK_TEST_ENUM(OperationType, REDUCE_ANY);
+CHECK_TEST_ENUM(OperationType, REDUCE_MAX);
+CHECK_TEST_ENUM(OperationType, REDUCE_MIN);
+CHECK_TEST_ENUM(OperationType, REDUCE_PROD);
+CHECK_TEST_ENUM(OperationType, REDUCE_SUM);
+CHECK_TEST_ENUM(OperationType, ROI_ALIGN);
+CHECK_TEST_ENUM(OperationType, ROI_POOLING);
+CHECK_TEST_ENUM(OperationType, RSQRT);
+CHECK_TEST_ENUM(OperationType, SELECT);
+CHECK_TEST_ENUM(OperationType, SIN);
+CHECK_TEST_ENUM(OperationType, SLICE);
+CHECK_TEST_ENUM(OperationType, SPLIT);
+CHECK_TEST_ENUM(OperationType, SQRT);
+CHECK_TEST_ENUM(OperationType, TILE);
+CHECK_TEST_ENUM(OperationType, TOPK_V2);
+CHECK_TEST_ENUM(OperationType, TRANSPOSE_CONV_2D);
+CHECK_TEST_ENUM(OperationType, UNIDIRECTIONAL_SEQUENCE_LSTM);
+CHECK_TEST_ENUM(OperationType, UNIDIRECTIONAL_SEQUENCE_RNN);
+CHECK_TEST_ENUM(OperationType, RESIZE_NEAREST_NEIGHBOR);
+
+#undef CHECK_TEST_ENUM
+
+}  // namespace android::hardware::neuralnetworks::V1_2
diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
index 8c6391e..416744f 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
@@ -18,26 +18,25 @@
 
 #include "VtsHalNeuralnetworks.h"
 
-#include "Callbacks.h"
+#include "1.2/Callbacks.h"
 #include "ExecutionBurstController.h"
 #include "ExecutionBurstServer.h"
+#include "GeneratedTestHarness.h"
 #include "TestHarness.h"
 #include "Utils.h"
 
 #include <android-base/logging.h>
+#include <chrono>
 #include <cstring>
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
-using ::android::nn::ExecutionBurstController;
-using ::android::nn::RequestChannelSender;
-using ::android::nn::ResultChannelReceiver;
-using ExecutionBurstCallback = ::android::nn::ExecutionBurstController::ExecutionBurstCallback;
+using nn::ExecutionBurstController;
+using nn::RequestChannelSender;
+using nn::ResultChannelReceiver;
+using V1_0::ErrorStatus;
+using V1_0::Request;
+using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback;
 
 // This constant value represents the length of an FMQ that is large enough to
 // return a result from a burst execution for all of the generated test cases.
@@ -66,9 +65,9 @@
 
     // create FMQ objects
     auto [fmqRequestChannel, fmqRequestDescriptor] =
-            RequestChannelSender::create(kExecutionBurstChannelLength, /*blocking=*/true);
+            RequestChannelSender::create(kExecutionBurstChannelLength);
     auto [fmqResultChannel, fmqResultDescriptor] =
-            ResultChannelReceiver::create(resultChannelLength, /*blocking=*/true);
+            ResultChannelReceiver::create(resultChannelLength, std::chrono::microseconds{0});
     ASSERT_NE(nullptr, fmqRequestChannel.get());
     ASSERT_NE(nullptr, fmqResultChannel.get());
     ASSERT_NE(nullptr, fmqRequestDescriptor);
@@ -239,7 +238,7 @@
 ///////////////////////// BURST VALIATION TESTS ////////////////////////////////////
 
 static void validateBurstSerialization(const sp<IPreparedModel>& preparedModel,
-                                       const std::vector<Request>& requests) {
+                                       const Request& request) {
     // create burst
     std::unique_ptr<RequestChannelSender> sender;
     std::unique_ptr<ResultChannelReceiver> receiver;
@@ -250,35 +249,32 @@
     ASSERT_NE(nullptr, receiver.get());
     ASSERT_NE(nullptr, context.get());
 
-    // validate each request
-    for (const Request& request : requests) {
-        // load memory into callback slots
-        std::vector<intptr_t> keys;
-        keys.reserve(request.pools.size());
-        std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys),
-                       [](const auto& pool) { return reinterpret_cast<intptr_t>(&pool); });
-        const std::vector<int32_t> slots = callback->getSlots(request.pools, keys);
+    // load memory into callback slots
+    std::vector<intptr_t> keys;
+    keys.reserve(request.pools.size());
+    std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys),
+                   [](const auto& pool) { return reinterpret_cast<intptr_t>(&pool); });
+    const std::vector<int32_t> slots = callback->getSlots(request.pools, keys);
 
-        // ensure slot std::numeric_limits<int32_t>::max() doesn't exist (for
-        // subsequent slot validation testing)
-        ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) {
-            return slot != std::numeric_limits<int32_t>::max();
-        }));
+    // ensure slot std::numeric_limits<int32_t>::max() doesn't exist (for
+    // subsequent slot validation testing)
+    ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) {
+        return slot != std::numeric_limits<int32_t>::max();
+    }));
 
-        // serialize the request
-        const auto serialized = ::android::nn::serialize(request, MeasureTiming::YES, slots);
+    // serialize the request
+    const auto serialized = android::nn::serialize(request, MeasureTiming::YES, slots);
 
-        // validations
-        removeDatumTest(sender.get(), receiver.get(), serialized);
-        addDatumTest(sender.get(), receiver.get(), serialized);
-        mutateDatumTest(sender.get(), receiver.get(), serialized);
-    }
+    // validations
+    removeDatumTest(sender.get(), receiver.get(), serialized);
+    addDatumTest(sender.get(), receiver.get(), serialized);
+    mutateDatumTest(sender.get(), receiver.get(), serialized);
 }
 
 // This test validates that when the Result message size exceeds length of the
 // result FMQ, the service instance gracefully fails and returns an error.
 static void validateBurstFmqLength(const sp<IPreparedModel>& preparedModel,
-                                   const std::vector<Request>& requests) {
+                                   const Request& request) {
     // create regular burst
     std::shared_ptr<ExecutionBurstController> controllerRegular;
     ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength(
@@ -291,35 +287,36 @@
             preparedModel, kExecutionBurstChannelSmallLength, &controllerSmall));
     ASSERT_NE(nullptr, controllerSmall.get());
 
-    // validate each request
-    for (const Request& request : requests) {
-        // load memory into callback slots
-        std::vector<intptr_t> keys(request.pools.size());
-        for (size_t i = 0; i < keys.size(); ++i) {
-            keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
-        }
-
-        // collect serialized result by running regular burst
-        const auto [statusRegular, outputShapesRegular, timingRegular] =
-                controllerRegular->compute(request, MeasureTiming::NO, keys);
-
-        // skip test if regular burst output isn't useful for testing a failure
-        // caused by having too small of a length for the result FMQ
-        const std::vector<FmqResultDatum> serialized =
-                ::android::nn::serialize(statusRegular, outputShapesRegular, timingRegular);
-        if (statusRegular != ErrorStatus::NONE ||
-            serialized.size() <= kExecutionBurstChannelSmallLength) {
-            continue;
-        }
-
-        // by this point, execution should fail because the result channel isn't
-        // large enough to return the serialized result
-        const auto [statusSmall, outputShapesSmall, timingSmall] =
-                controllerSmall->compute(request, MeasureTiming::NO, keys);
-        EXPECT_NE(ErrorStatus::NONE, statusSmall);
-        EXPECT_EQ(0u, outputShapesSmall.size());
-        EXPECT_TRUE(badTiming(timingSmall));
+    // load memory into callback slots
+    std::vector<intptr_t> keys(request.pools.size());
+    for (size_t i = 0; i < keys.size(); ++i) {
+        keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
     }
+
+    // collect serialized result by running regular burst
+    const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] =
+            controllerRegular->compute(request, MeasureTiming::NO, keys);
+    const ErrorStatus statusRegular = nn::convertResultCodeToErrorStatus(nRegular);
+    EXPECT_FALSE(fallbackRegular);
+
+    // skip test if regular burst output isn't useful for testing a failure
+    // caused by having too small of a length for the result FMQ
+    const std::vector<FmqResultDatum> serialized =
+            android::nn::serialize(statusRegular, outputShapesRegular, timingRegular);
+    if (statusRegular != ErrorStatus::NONE ||
+        serialized.size() <= kExecutionBurstChannelSmallLength) {
+        return;
+    }
+
+    // by this point, execution should fail because the result channel isn't
+    // large enough to return the serialized result
+    const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] =
+            controllerSmall->compute(request, MeasureTiming::NO, keys);
+    const ErrorStatus statusSmall = nn::convertResultCodeToErrorStatus(nSmall);
+    EXPECT_NE(ErrorStatus::NONE, statusSmall);
+    EXPECT_EQ(0u, outputShapesSmall.size());
+    EXPECT_TRUE(badTiming(timingSmall));
+    EXPECT_FALSE(fallbackSmall);
 }
 
 static bool isSanitized(const FmqResultDatum& datum) {
@@ -367,7 +364,7 @@
 }
 
 static void validateBurstSanitized(const sp<IPreparedModel>& preparedModel,
-                                   const std::vector<Request>& requests) {
+                                   const Request& request) {
     // create burst
     std::unique_ptr<RequestChannelSender> sender;
     std::unique_ptr<ResultChannelReceiver> receiver;
@@ -378,40 +375,31 @@
     ASSERT_NE(nullptr, receiver.get());
     ASSERT_NE(nullptr, context.get());
 
-    // validate each request
-    for (const Request& request : requests) {
-        // load memory into callback slots
-        std::vector<intptr_t> keys;
-        keys.reserve(request.pools.size());
-        std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys),
-                       [](const auto& pool) { return reinterpret_cast<intptr_t>(&pool); });
-        const std::vector<int32_t> slots = callback->getSlots(request.pools, keys);
+    // load memory into callback slots
+    std::vector<intptr_t> keys;
+    keys.reserve(request.pools.size());
+    std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys),
+                   [](const auto& pool) { return reinterpret_cast<intptr_t>(&pool); });
+    const std::vector<int32_t> slots = callback->getSlots(request.pools, keys);
 
-        // send valid request
-        ASSERT_TRUE(sender->send(request, MeasureTiming::YES, slots));
+    // send valid request
+    ASSERT_TRUE(sender->send(request, MeasureTiming::YES, slots));
 
-        // receive valid result
-        auto serialized = receiver->getPacketBlocking();
-        ASSERT_TRUE(serialized.has_value());
+    // receive valid result
+    auto serialized = receiver->getPacketBlocking();
+    ASSERT_TRUE(serialized.has_value());
 
-        // sanitize result
-        ASSERT_TRUE(std::all_of(serialized->begin(), serialized->end(), isSanitized))
-                << "The result serialized data is not properly sanitized";
-    }
+    // sanitize result
+    ASSERT_TRUE(std::all_of(serialized->begin(), serialized->end(), isSanitized))
+            << "The result serialized data is not properly sanitized";
 }
 
 ///////////////////////////// ENTRY POINT //////////////////////////////////
 
-void ValidationTest::validateBurst(const sp<IPreparedModel>& preparedModel,
-                                   const std::vector<Request>& requests) {
-    ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, requests));
-    ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, requests));
-    ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, requests));
+void validateBurst(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, request));
+    ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, request));
+    ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request));
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index a0b6d9a..a14b86b 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -16,23 +16,17 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
+#include "1.0/Utils.h"
+#include "1.2/Callbacks.h"
+#include "GeneratedTestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
-#include "Callbacks.h"
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-
+using implementation::PreparedModelCallback;
+using V1_0::ErrorStatus;
 using V1_0::OperandLifeTime;
 using V1_1::ExecutionPreference;
-
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
 using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
@@ -41,10 +35,10 @@
                                            const Model& model) {
     SCOPED_TRACE(message + " [getSupportedOperations_1_2]");
 
-    Return<void> ret =
-        device->getSupportedOperations_1_2(model, [&](ErrorStatus status, const hidl_vec<bool>&) {
-            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
-        });
+    Return<void> ret = device->getSupportedOperations_1_2(
+            model, [&](ErrorStatus status, const hidl_vec<bool>&) {
+                EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+            });
     EXPECT_TRUE(ret.isOk());
 }
 
@@ -53,7 +47,6 @@
     SCOPED_TRACE(message + " [prepareModel_1_2]");
 
     sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
     Return<ErrorStatus> prepareLaunchStatus =
             device->prepareModel_1_2(model, preference, hidl_vec<hidl_handle>(),
                                      hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
@@ -87,36 +80,16 @@
     validatePrepareModel(device, message, model, preference);
 }
 
-// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
-// so this is efficiently accomplished by moving the element to the end and
-// resizing the hidl_vec to one less.
-template <typename Type>
-static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
-    if (vec) {
-        std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
-        vec->resize(vec->size() - 1);
-    }
-}
-
-template <typename Type>
-static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
-    // assume vec is valid
-    const uint32_t index = vec->size();
-    vec->resize(index + 1);
-    (*vec)[index] = value;
-    return index;
-}
-
 static uint32_t addOperand(Model* model) {
     return hidl_vec_push_back(&model->operands,
                               {
-                                  .type = OperandType::INT32,
-                                  .dimensions = {},
-                                  .numberOfConsumers = 0,
-                                  .scale = 0.0f,
-                                  .zeroPoint = 0,
-                                  .lifetime = OperandLifeTime::MODEL_INPUT,
-                                  .location = {.poolIndex = 0, .offset = 0, .length = 0},
+                                      .type = OperandType::INT32,
+                                      .dimensions = {},
+                                      .numberOfConsumers = 0,
+                                      .scale = 0.0f,
+                                      .zeroPoint = 0,
+                                      .lifetime = OperandLifeTime::MODEL_INPUT,
+                                      .location = {.poolIndex = 0, .offset = 0, .length = 0},
                               });
 }
 
@@ -256,7 +229,7 @@
 static void mutateOperandZeroPointTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         const std::vector<int32_t> invalidZeroPoints =
-            getInvalidZeroPoints(model.operands[operand].type);
+                getInvalidZeroPoints(model.operands[operand].type);
         for (int32_t invalidZeroPoint : invalidZeroPoints) {
             const std::string message = "mutateOperandZeroPointTest: operand " +
                                         std::to_string(operand) + " has zero point of " +
@@ -292,13 +265,13 @@
         case OperandType::TENSOR_FLOAT16:
         case OperandType::TENSOR_FLOAT32:
             newOperand.dimensions =
-                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.scale = 0.0f;
             newOperand.zeroPoint = 0;
             break;
         case OperandType::TENSOR_INT32:
             newOperand.dimensions =
-                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.zeroPoint = 0;
             break;
         case OperandType::TENSOR_QUANT8_ASYMM:
@@ -306,19 +279,20 @@
         case OperandType::TENSOR_QUANT16_ASYMM:
         case OperandType::TENSOR_QUANT16_SYMM:
             newOperand.dimensions =
-                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
             break;
         case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: {
             newOperand.dimensions =
-                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.scale = 0.0f;
             newOperand.zeroPoint = 0;
 
             SymmPerChannelQuantParams channelQuant;
             channelQuant.channelDim = 0;
             channelQuant.scales = hidl_vec<float>(
-                operand->dimensions.size() > 0 ? static_cast<size_t>(operand->dimensions[0]) : 0);
+                    operand->dimensions.size() > 0 ? static_cast<size_t>(operand->dimensions[0])
+                                                   : 0);
             for (size_t i = 0; i < channelQuant.scales.size(); ++i) {
                 channelQuant.scales[i] = 1.0f;
             }
@@ -435,7 +409,7 @@
                                         std::to_string(invalidOperationType);
             validate(device, message, model, [operation, invalidOperationType](Model* model) {
                 model->operations[operation].type =
-                    static_cast<OperationType>(invalidOperationType);
+                        static_cast<OperationType>(invalidOperationType);
             });
         }
     }
@@ -508,15 +482,15 @@
                 }
             }
         }
-        // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have either one or two
-        // outputs depending on their mergeOutputs parameter.
+        // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have
+        // either one or two outputs depending on their mergeOutputs parameter.
         if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM ||
             operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) {
-            for (const size_t outOprand : operation.outputs) {
-                if (operand == outOprand) {
-                    return true;
-                }
+          for (const size_t outOprand : operation.outputs) {
+            if (operand == outOprand) {
+              return true;
             }
+          }
         }
     }
     return false;
@@ -690,7 +664,7 @@
 static void addOperationOutputTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message =
-            "addOperationOutputTest: operation " + std::to_string(operation);
+                "addOperationOutputTest: operation " + std::to_string(operation);
         validate(device, message, model, [operation](Model* model) {
             uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
             hidl_vec_push_back(&model->operations[operation].outputs, index);
@@ -702,22 +676,23 @@
 ///////////////////////// VALIDATE EXECUTION PREFERENCE /////////////////////////
 
 static const int32_t invalidExecutionPreferences[] = {
-    static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1,        // lower bound
-    static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1,  // upper bound
+        static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1,        // lower bound
+        static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1,  // upper bound
 };
 
 static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
     for (int32_t preference : invalidExecutionPreferences) {
         const std::string message =
-            "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
-        validate(device, message, model, [](Model*) {},
-                 static_cast<ExecutionPreference>(preference));
+                "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
+        validate(
+                device, message, model, [](Model*) {},
+                static_cast<ExecutionPreference>(preference));
     }
 }
 
 ////////////////////////// ENTRY POINT //////////////////////////////
 
-void ValidationTest::validateModel(const Model& model) {
+void validateModel(const sp<IDevice>& device, const Model& model) {
     mutateOperandTypeTest(device, model);
     mutateOperandRankTest(device, model);
     mutateOperandScaleTest(device, model);
@@ -735,9 +710,4 @@
     mutateExecutionPreferenceTest(device, model);
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index 9703c2d..2d83b81 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -16,29 +16,20 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
+#include <chrono>
+#include "1.0/Utils.h"
+#include "1.2/Callbacks.h"
 #include "ExecutionBurstController.h"
+#include "GeneratedTestHarness.h"
 #include "TestHarness.h"
 #include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
 
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hidl::memory::V1_0::IMemory;
-using test_helper::for_all;
-using test_helper::MixedTyped;
-using test_helper::MixedTypedExample;
+using implementation::ExecutionCallback;
+using V1_0::ErrorStatus;
+using V1_0::Request;
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
@@ -69,7 +60,6 @@
         SCOPED_TRACE(message + " [execute_1_2]");
 
         sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-        ASSERT_NE(nullptr, executionCallback.get());
         Return<ErrorStatus> executeLaunchStatus =
                 preparedModel->execute_1_2(request, measure, executionCallback);
         ASSERT_TRUE(executeLaunchStatus.isOk());
@@ -105,7 +95,8 @@
 
         // create burst
         std::shared_ptr<::android::nn::ExecutionBurstController> burst =
-                ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
+                android::nn::ExecutionBurstController::create(preparedModel,
+                                                              std::chrono::microseconds{0});
         ASSERT_NE(nullptr, burst.get());
 
         // create memory keys
@@ -115,13 +106,12 @@
         }
 
         // execute and verify
-        ErrorStatus error;
-        std::vector<OutputShape> outputShapes;
-        Timing timing;
-        std::tie(error, outputShapes, timing) = burst->compute(request, measure, keys);
-        EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+        const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys);
+        const ErrorStatus status = nn::convertResultCodeToErrorStatus(n);
+        EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
         EXPECT_EQ(outputShapes.size(), 0);
         EXPECT_TRUE(badTiming(timing));
+        EXPECT_FALSE(fallback);
 
         // additional burst testing
         if (request.pools.size() > 0) {
@@ -137,26 +127,6 @@
     }
 }
 
-// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
-// so this is efficiently accomplished by moving the element to the end and
-// resizing the hidl_vec to one less.
-template <typename Type>
-static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
-    if (vec) {
-        std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
-        vec->resize(vec->size() - 1);
-    }
-}
-
-template <typename Type>
-static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
-    // assume vec is valid
-    const uint32_t index = vec->size();
-    vec->resize(index + 1);
-    (*vec)[index] = value;
-    return index;
-}
-
 ///////////////////////// REMOVE INPUT ////////////////////////////////////
 
 static void removeInputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
@@ -179,104 +149,21 @@
 
 ///////////////////////////// ENTRY POINT //////////////////////////////////
 
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples) {
-    const uint32_t INPUT = 0;
-    const uint32_t OUTPUT = 1;
-
-    std::vector<Request> requests;
-
-    for (auto& example : examples) {
-        const MixedTyped& inputs = example.operands.first;
-        const MixedTyped& outputs = example.operands.second;
-
-        std::vector<RequestArgument> inputs_info, outputs_info;
-        uint32_t inputSize = 0, outputSize = 0;
-
-        // This function only partially specifies the metadata (vector of RequestArguments).
-        // The contents are copied over below.
-        for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
-            if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
-            RequestArgument arg = {
-                .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
-                .dimensions = {},
-            };
-            RequestArgument arg_empty = {
-                .hasNoValue = true,
-            };
-            inputs_info[index] = s ? arg : arg_empty;
-            inputSize += s;
-        });
-        // Compute offset for inputs 1 and so on
-        {
-            size_t offset = 0;
-            for (auto& i : inputs_info) {
-                if (!i.hasNoValue) i.location.offset = offset;
-                offset += i.location.length;
-            }
-        }
-
-        // Go through all outputs, initialize RequestArgument descriptors
-        for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
-            if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
-            RequestArgument arg = {
-                .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
-                .dimensions = {},
-            };
-            outputs_info[index] = arg;
-            outputSize += s;
-        });
-        // Compute offset for outputs 1 and so on
-        {
-            size_t offset = 0;
-            for (auto& i : outputs_info) {
-                i.location.offset = offset;
-                offset += i.location.length;
-            }
-        }
-        std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
-                                          nn::allocateSharedMemory(outputSize)};
-        if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
-            return {};
-        }
-
-        // map pool
-        sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
-        if (inputMemory == nullptr) {
-            return {};
-        }
-        char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
-        if (inputPtr == nullptr) {
-            return {};
-        }
-
-        // initialize pool
-        inputMemory->update();
-        for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
-            char* begin = (char*)p;
-            char* end = begin + s;
-            // TODO: handle more than one input
-            std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
-        });
-        inputMemory->commit();
-
-        requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
-    }
-
-    return requests;
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    removeInputTest(preparedModel, request);
+    removeOutputTest(preparedModel, request);
 }
 
-void ValidationTest::validateRequests(const sp<IPreparedModel>& preparedModel,
-                                      const std::vector<Request>& requests) {
-    // validate each request
-    for (const Request& request : requests) {
-        removeInputTest(preparedModel, request);
-        removeOutputTest(preparedModel, request);
-    }
+void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    SCOPED_TRACE("Expecting request to fail [executeSynchronously]");
+    Return<void> executeStatus = preparedModel->executeSynchronously(
+            request, MeasureTiming::NO,
+            [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
+                ASSERT_NE(ErrorStatus::NONE, error);
+                EXPECT_EQ(outputShapes.size(), 0);
+                EXPECT_TRUE(badTiming(timing));
+            });
+    ASSERT_TRUE(executeStatus.isOk());
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
index 4ddefe8..4fbd0e2 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
@@ -17,42 +17,43 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include "VtsHalNeuralnetworks.h"
-
 #include <android-base/logging.h>
+#include <hidl/ServiceManagement.h>
+#include <string>
+#include <utility>
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "GeneratedTestHarness.h"
+#include "TestHarness.h"
 
-#include "Callbacks.h"
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using implementation::PreparedModelCallback;
 using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+using V1_0::ErrorStatus;
+using V1_0::Request;
 using V1_1::ExecutionPreference;
 
 // internal helper function
-static void createPreparedModel(const sp<IDevice>& device, const Model& model,
-                                sp<IPreparedModel>* preparedModel) {
+void createPreparedModel(const sp<IDevice>& device, const Model& model,
+                         sp<IPreparedModel>* preparedModel) {
     ASSERT_NE(nullptr, preparedModel);
+    *preparedModel = nullptr;
 
     // see if service can handle model
     bool fullySupportsModel = false;
-    Return<void> supportedOpsLaunchStatus = device->getSupportedOperations_1_2(
+    const Return<void> supportedCall = device->getSupportedOperations_1_2(
             model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
                 ASSERT_EQ(ErrorStatus::NONE, status);
                 ASSERT_NE(0ul, supported.size());
                 fullySupportsModel = std::all_of(supported.begin(), supported.end(),
                                                  [](bool valid) { return valid; });
             });
-    ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
+    ASSERT_TRUE(supportedCall.isOk());
 
     // launch prepare model
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2(
+    const sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+    const Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2(
             model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(),
             hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
@@ -60,7 +61,7 @@
 
     // retrieve prepared model
     preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
     *preparedModel = getPreparedModel_1_2(preparedModelCallback);
 
     // The getSupportedOperations_1_2 call returns a list of operations that are
@@ -72,106 +73,99 @@
     // can continue.
     if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
         ASSERT_EQ(nullptr, preparedModel->get());
-        LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
-                     "prepare model that it does not support.";
-        std::cout << "[          ]   Unable to test Request validation because vendor service "
-                     "cannot prepare model that it does not support."
+        LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare "
+                     "model that it does not support.";
+        std::cout << "[          ]   Early termination of test because vendor service cannot "
+                     "prepare model that it does not support."
                   << std::endl;
-        return;
+        GTEST_SKIP();
     }
     ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
     ASSERT_NE(nullptr, preparedModel->get());
 }
 
-// A class for test environment setup
-NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
-
-NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {}
-
-NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
-    // This has to return a "new" object because it is freed inside
-    // ::testing::AddGlobalTestEnvironment when the gtest is being torn down
-    static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
-    return instance;
-}
-
-void NeuralnetworksHidlEnvironment::registerTestServices() {
-    registerTestService<IDevice>();
-}
-
-// The main test class for NEURALNETWORK HIDL HAL.
-NeuralnetworksHidlTest::NeuralnetworksHidlTest() {}
-
-NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
-
 void NeuralnetworksHidlTest::SetUp() {
-    ::testing::VtsHalHidlTargetTestBase::SetUp();
-    device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
-            NeuralnetworksHidlEnvironment::getInstance());
-
-#ifdef PRESUBMIT_NOT_VTS
-    const std::string name =
-            NeuralnetworksHidlEnvironment::getInstance()->getServiceName<IDevice>();
-    const std::string sampleDriver = "sample-";
-    if (device == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) {
-        GTEST_SKIP();
-    }
-#endif  // PRESUBMIT_NOT_VTS
-
-    ASSERT_NE(nullptr, device.get());
+    testing::TestWithParam<NeuralnetworksHidlTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
 }
 
-void NeuralnetworksHidlTest::TearDown() {
-    device = nullptr;
-    ::testing::VtsHalHidlTargetTestBase::TearDown();
+static NamedDevice makeNamedDevice(const std::string& name) {
+    return {name, IDevice::getService(name)};
 }
 
-void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
-    validateModel(model);
+static std::vector<NamedDevice> getNamedDevicesImpl() {
+    // Retrieves the name of all service instances that implement IDevice,
+    // including any Lazy HAL instances.
+    const std::vector<std::string> names = hardware::getAllHalInstanceNames(IDevice::descriptor);
 
-    // create IPreparedModel
+    // Get a handle to each device and pair it with its name.
+    std::vector<NamedDevice> namedDevices;
+    namedDevices.reserve(names.size());
+    std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice);
+    return namedDevices;
+}
+
+const std::vector<NamedDevice>& getNamedDevices() {
+    const static std::vector<NamedDevice> devices = getNamedDevicesImpl();
+    return devices;
+}
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info) {
+    return gtestCompliantName(getName(info.param));
+}
+
+INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest);
+
+// Forward declaration from ValidateModel.cpp
+void validateModel(const sp<IDevice>& device, const Model& model);
+// Forward declaration from ValidateRequest.cpp
+void validateRequest(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+// Forward declaration from ValidateRequest.cpp
+void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+// Forward declaration from ValidateBurst.cpp
+void validateBurst(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+
+void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request) {
+    validateModel(device, model);
+
+    // Create IPreparedModel.
     sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
+
+    validateRequest(preparedModel, request);
+    validateBurst(preparedModel, request);
+}
+
+void validateFailure(const sp<IDevice>& device, const Model& model, const Request& request) {
+    // TODO: Should this always succeed?
+    //       What if the invalid input is part of the model (i.e., a parameter).
+    validateModel(device, model);
+
+    // Create IPreparedModel.
+    sp<IPreparedModel> preparedModel;
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
+
+    validateRequestFailure(preparedModel, request);
+}
+
+TEST_P(ValidationTest, Test) {
+    const Model model = createModel(kTestModel);
+    const Request request = createRequest(kTestModel);
+    if (kTestModel.expectFailure) {
+        validateFailure(kDevice, model, request);
+    } else {
+        validateEverything(kDevice, model, request);
     }
-
-    validateRequests(preparedModel, requests);
-    validateBurst(preparedModel, requests);
 }
 
-sp<IPreparedModel> getPreparedModel_1_2(
-    const sp<V1_2::implementation::PreparedModelCallback>& callback) {
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+
+sp<IPreparedModel> getPreparedModel_1_2(const sp<implementation::PreparedModelCallback>& callback) {
     sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
-    return V1_2::IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
+    return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
-
-namespace android::hardware::neuralnetworks::V1_0 {
-
-::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) {
-    return os << toString(errorStatus);
-}
-
-::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) {
-    return os << toString(deviceStatus);
-}
-
-}  // namespace android::hardware::neuralnetworks::V1_0
-
-using android::hardware::neuralnetworks::V1_2::vts::functional::NeuralnetworksHidlEnvironment;
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
-    ::testing::InitGoogleTest(&argc, argv);
-    NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
-
-    int status = RUN_ALL_TESTS();
-    return status;
-}
+}  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
index 8d1acbe..d01336e 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
@@ -14,97 +14,44 @@
  * limitations under the License.
  */
 
-#ifndef VTS_HAL_NEURALNETWORKS_V1_2_H
-#define VTS_HAL_NEURALNETWORKS_V1_2_H
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H
 
-#include "Callbacks.h"
-
-#include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
 #include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
 #include <android/hardware/neuralnetworks/1.2/types.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
-#include <android-base/macros.h>
 #include <gtest/gtest.h>
-#include <iostream>
-#include <vector>
+#include "1.0/Utils.h"
+#include "1.2/Callbacks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
-using V1_0::DeviceStatus;
-using V1_0::ErrorStatus;
-using V1_0::Request;
+using NamedDevice = Named<sp<IDevice>>;
+using NeuralnetworksHidlTestParam = NamedDevice;
 
-namespace vts {
-namespace functional {
-
-// A class for test environment setup
-class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
-    NeuralnetworksHidlEnvironment();
-    ~NeuralnetworksHidlEnvironment() override;
-
-   public:
-    static NeuralnetworksHidlEnvironment* getInstance();
-    void registerTestServices() override;
-};
-
-// The main test class for NEURALNETWORKS HIDL HAL.
-class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
-
-   public:
-    NeuralnetworksHidlTest();
-    ~NeuralnetworksHidlTest() override;
+class NeuralnetworksHidlTest : public testing::TestWithParam<NeuralnetworksHidlTestParam> {
+  protected:
     void SetUp() override;
-    void TearDown() override;
-
-   protected:
-    sp<IDevice> device;
+    const sp<IDevice> kDevice = getData(GetParam());
 };
 
-// Tag for the validation tests
-class ValidationTest : public NeuralnetworksHidlTest {
-   protected:
-     void validateEverything(const Model& model, const std::vector<Request>& requests);
+const std::vector<NamedDevice>& getNamedDevices();
 
-   private:
-     void validateModel(const Model& model);
-     void validateRequests(const sp<IPreparedModel>& preparedModel,
-                           const std::vector<Request>& requests);
-     void validateBurst(const sp<IPreparedModel>& preparedModel,
-                        const std::vector<Request>& requests);
-};
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info);
 
-// Tag for the generated tests
-class GeneratedTest : public NeuralnetworksHidlTest {};
+#define INSTANTIATE_DEVICE_TEST(TestSuite)                                                 \
+    INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \
+                             printNeuralnetworksHidlTest)
 
-// Tag for the dynamic output shape tests
-class DynamicOutputShapeTest : public NeuralnetworksHidlTest {};
+// Create an IPreparedModel object. If the model cannot be prepared,
+// "preparedModel" will be nullptr instead.
+void createPreparedModel(const sp<IDevice>& device, const Model& model,
+                         sp<IPreparedModel>* preparedModel);
 
 // Utility function to get PreparedModel from callback and downcast to V1_2.
-sp<IPreparedModel> getPreparedModel_1_2(
-    const sp<V1_2::implementation::PreparedModelCallback>& callback);
+sp<IPreparedModel> getPreparedModel_1_2(const sp<implementation::PreparedModelCallback>& callback);
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
 
-namespace android::hardware::neuralnetworks::V1_0 {
-
-// pretty-print values for error messages
-::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
-::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus);
-
-}  // namespace android::hardware::neuralnetworks::V1_0
-
-#endif  // VTS_HAL_NEURALNETWORKS_V1_2_H
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H
diff --git a/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h
new file mode 100644
index 0000000..bf4792c
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <hidl/Status.h>
+#include <condition_variable>
+#include <mutex>
+
+/*
+ * The Callback classes are used internally by the NeuralNetworks runtime to
+ * synchronize between different threads. An asynchronous task is launched
+ * paired with a callback object. When a client thread requires the output being
+ * generated by the asynchronous task, the client thread can wait for the result
+ * and be blocked until it has completed. Any wait may safely be called
+ * concurrently, even on the same callback object. When the asynchronous task
+ * has finished its workload, it must immediately call "notify*". If the
+ * asynchronous task has failed to launch, the function that tried to launch the
+ * asynchronous task must immediately call "notify*". This "notify*" call
+ * awakens any client threads waiting on the callback object.
+ *
+ * These classes exist to enable synchronization across HIDL. When
+ * synchronization is only required in the same process, consider using
+ * std::future, std::mutex, std::condition_variable, or std::experimental::latch
+ * instead.
+ */
+
+namespace android::hardware::neuralnetworks::V1_2::implementation {
+
+/**
+ * The PreparedModelCallback class is used to receive the error status of
+ * preparing a model as well as the prepared model from a task executing
+ * asynchronously with respect to the runtime. If a calling thread calls wait
+ * or get* on a PreparedModelCallback object and the corresponding asynchronous
+ * task has not finished preparing the model, the calling thread will block
+ * until the asynchronous task has either called notify or notify_1_2.
+ *
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify* are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IDevice::prepareModel*.
+ */
+class PreparedModelCallback : public IPreparedModelCallback {
+  public:
+    /**
+     * IPreparedModelCallback::notify marks the callback object with the return
+     * status of the asynchronous model preparation along with the prepared
+     * model, and allows all prior and future wait calls on the
+     * PreparedModelCallback object to proceed.
+     *
+     * Either IPreparedModelCallback::notify or
+     * IPreparedModelCallback::notify_1_2 must be called on a given
+     * PreparedModelCallback object.
+     *
+     * If the callback object is notified more than once, only the results of
+     * the first call to notify* are used, and the results from subsequent calls
+     * are discarded.
+     *
+     * @param status Error status returned from asynchronously preparing the
+     *     model; will be:
+     *     - NONE if the asynchronous preparation was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if the input model is invalid
+     * @param preparedModel Returned model that has been prepared for execution,
+     *     nullptr if the model was unable to be prepared.
+     */
+    Return<void> notify(V1_0::ErrorStatus status,
+                        const sp<V1_0::IPreparedModel>& preparedModel) override;
+
+    /**
+     * IPreparedModelCallback::notify_1_2 marks the callback object with the
+     * return status of the asynchronous model preparation along with the
+     * prepared model, and allows all prior and future wait calls on the
+     * PreparedModelCallback object to proceed.
+     *
+     * Either IPreparedModelCallback::notify or
+     * IPreparedModelCallback::notify_1_2 must be called on a given
+     * PreparedModelCallback object.
+     *
+     * If the callback object is notified more than once, only the results of
+     * the first call to notify* are used, and the results from subsequent calls
+     * are discarded.
+     *
+     * @param status Error status returned from asynchronously preparing the
+     *     model; will be:
+     *     - NONE if the asynchronous preparation was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if the input model is invalid
+     * @param preparedModel Returned model that has been prepared for execution,
+     *     nullptr if the model was unable to be prepared.
+     */
+    Return<void> notify_1_2(V1_0::ErrorStatus status,
+                            const sp<V1_2::IPreparedModel>& preparedModel) override;
+
+    /**
+     * PreparedModelCallback::wait blocks until notify* has been called on the
+     * callback object.
+     */
+    void wait() const;
+
+    /**
+     * Retrieves the error status returned from the asynchronous task launched
+     * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished
+     * asynchronously preparing the model, this call will block until the
+     * asynchronous task notifies the object.
+     *
+     * @return status Error status returned from asynchronously preparing the
+     *     model; will be:
+     *     - NONE if the asynchronous preparation was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if the input model is invalid
+     */
+    V1_0::ErrorStatus getStatus() const;
+
+    /**
+     * Retrieves the model that has been prepared for execution from the
+     * asynchronous task launched by IDevice::prepareModel*. If
+     * IDevice::prepareModel* has not finished asynchronously preparing the
+     * model, this call will block until the asynchronous task notifies the
+     * object.
+     *
+     * @return preparedModel Returned model that has been prepared for
+     *     execution, nullptr if the model was unable to be prepared.
+     */
+    sp<V1_0::IPreparedModel> getPreparedModel() const;
+
+  private:
+    mutable std::mutex mMutex;
+    mutable std::condition_variable mCondition;
+    bool mNotified GUARDED_BY(mMutex) = false;
+    V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE;
+    sp<V1_0::IPreparedModel> mPreparedModel;
+};
+
+/**
+ * The ExecutionCallback class is used to receive the results of the execution
+ * from a task executing asynchronously with respect to the runtime. If a
+ * calling thread calls wait or get* on a ExecutionCallback object and the
+ * corresponding asynchronous task has not finished the execution, the calling
+ * thread will block until the asynchronous task has either called notify or
+ * notify_1_2.
+ *
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify* are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IPreparedModel::execute*.
+ */
+class ExecutionCallback : public IExecutionCallback {
+  public:
+    /**
+     * IExecutionCallback::notify marks the callback object with the return
+     * status of the asynchronous execution that held this callback and enables
+     * all prior and future wait calls on the ExecutionCallback object to
+     * proceed.
+     *
+     * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
+     * be called on a given ExecutionCallback object.
+     *
+     * If the callback object is notified more than once, only the results of
+     * the first call to notify* are used, and the results from subsequent calls
+     * are discarded.
+     *
+     * @param status Error status returned from launching the asynchronous task
+     *     (if the launch fails) or from the asynchronous task itself (if the
+     *     launch succeeds). Must be:
+     *     - NONE if the asynchronous execution was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large
+     *         enough to store the resultant values
+     *     - INVALID_ARGUMENT if the input request is invalid
+     */
+    Return<void> notify(V1_0::ErrorStatus status) override;
+
+    /**
+     * IExecutionCallback::notify_1_2 marks the callback object with the results
+     * (error status, dynamic output shapes, and timing information) of the
+     * asynchronous execution that held this callback and enables all prior and
+     * future wait calls on the ExecutionCallback object to proceed.
+     *
+     * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
+     * be called on a given ExecutionCallback object.
+     *
+     * If the callback object is notified more than once, only the results of
+     * the first call to notify* are used, and the results from subsequent calls
+     * are discarded.
+     *
+     * @param status Error status returned from launching the asynchronous task
+     *     (if the launch fails) or from the asynchronous task itself (if the
+     *     launch succeeds). Must be:
+     *     - NONE if the asynchronous execution was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if the asynchronous task resulted in an unspecified
+     *         error
+     *     - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+     *         not large enough to store the corresponding output
+     *     - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+     *         invalid
+     * @param outputShapes A list of shape information of model output operands.
+     *     The index into "outputShapes" corresponds to the index of the output
+     *     operand in the Request outputs vector. outputShapes must be empty
+     *     unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE.
+     * @param Timing Duration of execution. Unless MeasureTiming::YES was passed
+     *     when launching the execution and status is NONE, all times must be
+     *     reported as UINT64_MAX. A driver may choose to report any time as
+     *     UINT64_MAX, indicating that particular measurement is not available.
+     */
+    Return<void> notify_1_2(V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+                            const Timing& timing) override;
+
+    // An overload of the latest notify interface to hide the version from ExecutionBuilder.
+    Return<void> notify(V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+                        const Timing& timing) {
+        return notify_1_2(status, outputShapes, timing);
+    }
+
+    /**
+     * ExecutionCallback::wait blocks until notify* has been called on the
+     * callback object.
+     */
+    void wait() const;
+
+    /**
+     * Retrieves the error status returned from the asynchronous task launched
+     * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If
+     * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished
+     * asynchronously executing, this call will block until the asynchronous
+     * task notifies the object.
+     *
+     * @return status Error status returned from launching the asynchronous task
+     *     (if the launch fails) or from the asynchronous task itself (if the
+     *     launch succeeds). Must be:
+     *     - NONE if the asynchronous execution was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if the asynchronous task resulted in an unspecified
+     *         error
+     *     - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+     *         not large enough to store the corresponding output
+     *     - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+     *         invalid
+     */
+    V1_0::ErrorStatus getStatus() const;
+
+    /**
+     * Retrieves the output shapes returned from the asynchronous task launched
+     * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not
+     * finished asynchronously executing, this call will block until the
+     * asynchronous task notifies the object.
+     *
+     * If the asynchronous task was launched by IPreparedModel::execute, an
+     * empty vector will be returned.
+     *
+     * @return outputShapes A list of shape information of model output
+     *     operands. The index into "outputShapes" corresponds to the index of
+     *     the output operand in the Request outputs vector. outputShapes must
+     *     be empty unless the status is either NONE or
+     *     OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is
+     *     NONE and all model output operands are fully-specified at execution
+     *     time. outputShapes must have the same number of elements as the
+     *     number of model output operands if the status is
+     *     OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has
+     *     at least one output operand that is not fully-specified.
+     */
+    const std::vector<OutputShape>& getOutputShapes() const;
+
+    /**
+     * Retrieves the duration of execution of the asynchronous task launched by
+     * IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not
+     * finished asynchronously executing, this call will block until the
+     * asynchronous task notifies the object.
+     *
+     * If the asynchronous task was launched by IPreparedModel::execute, every
+     * time must be UINT64_MAX.
+     *
+     * @return timing Duration of the execution. Every time must be UINT64_MAX
+     *     unless the status is NONE.
+     */
+    Timing getTiming() const;
+
+  private:
+    /*
+     * ExecutionCallback::notifyInternal stores the results of the execution
+     * (status, output shapes, and timing information) in the ExecutionCallback
+     * object before any call to wait or get* return. It then enables all prior
+     * and future wait calls on the ExecutionCallback object to proceed.
+     */
+    void notifyInternal(V1_0::ErrorStatus errorStatus, const hidl_vec<OutputShape>& outputShapes,
+                        const Timing& timing);
+
+    // members
+    mutable std::mutex mMutex;
+    mutable std::condition_variable mCondition;
+    bool mNotified GUARDED_BY(mMutex) = false;
+    V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE;
+    std::vector<OutputShape> mOutputShapes = {};
+    Timing mTiming = {};
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_2::implementation
+
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H
diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp
new file mode 100644
index 0000000..0b07a58
--- /dev/null
+++ b/neuralnetworks/1.3/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.neuralnetworks@1.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IDevice.hal",
+        "IPreparedModel.hal",
+        "IPreparedModelCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.2",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal
new file mode 100644
index 0000000..1295d6a
--- /dev/null
+++ b/neuralnetworks/1.3/IDevice.hal
@@ -0,0 +1,250 @@
+/*
+ * 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.neuralnetworks@1.3;
+
+import @1.0::ErrorStatus;
+import @1.1::ExecutionPreference;
+import @1.2::Constant;
+import @1.2::DeviceType;
+import @1.2::Extension;
+import @1.2::IDevice;
+import IPreparedModelCallback;
+
+/**
+ * This interface represents a device driver.
+ */
+interface IDevice extends @1.2::IDevice {
+    /**
+     * Gets the capabilities of a driver.
+     *
+     * @return status Error status of the call, must be:
+     *                - NONE if successful
+     *                - DEVICE_UNAVAILABLE if driver is offline or busy
+     *                - GENERAL_FAILURE if there is an unspecified error
+     * @return capabilities Capabilities of the driver.
+     */
+    getCapabilities_1_3() generates (ErrorStatus status, Capabilities capabilities);
+
+    /**
+     * Gets the supported operations in a model.
+     *
+     * getSupportedOperations indicates which operations of a model are fully
+     * supported by the vendor driver. If an operation may not be supported for
+     * any reason, getSupportedOperations must return false for that operation.
+     *
+     * @param model A model whose operations--and their corresponding operands--
+     *     are to be verified by the driver.
+     * @return status Error status of the call, must be:
+     *     - NONE if successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if provided model is invalid
+     * @return supportedOperations A list of supported operations, where true
+     *     indicates the operation is supported and false indicates the
+     *     operation is not supported. The index of "supported" corresponds with
+     *     the index of the operation it is describing.
+     */
+    getSupportedOperations_1_3(Model model)
+        generates (ErrorStatus status, vec<bool> supportedOperations);
+
+    /**
+     * Asynchronously creates a prepared model for execution and optionally
+     * saves it into cache files.
+     *
+     * prepareModel is used to make any necessary transformations to or
+     * alternative representations to a model for execution, possibly including
+     * transformations on the constant data, optimization on the model's graph,
+     * or compilation into the device's native binary format. The model itself
+     * is not changed.
+     *
+     * Optionally, caching information may be provided for the driver to save
+     * the prepared model to cache files for faster model compilation time when
+     * the same model preparation is requested in the future. There are two
+     * types of cache file handles provided to the driver: model cache and data
+     * cache. For more information on the two types of cache handles, refer to
+     * getNumberOfCacheFilesNeeded.
+     *
+     * The file descriptors must be opened with read and write permission. A
+     * file may have any size, and the corresponding file descriptor may have
+     * any offset. The driver must truncate a file to zero size before writing
+     * to that file. The file descriptors may be closed by the client once the
+     * asynchronous preparation has finished. The driver must dup a file
+     * descriptor if it wants to get access to the cache file later.
+     *
+     * The model is prepared asynchronously with respect to the caller. The
+     * prepareModel function must verify the inputs to the preparedModel
+     * function related to preparing the model (as opposed to saving the
+     * prepared model to cache) are correct. If there is an error, prepareModel
+     * must immediately invoke the callback with the appropriate ErrorStatus
+     * value and nullptr for the IPreparedModel, then return with the same
+     * ErrorStatus. If the inputs to the prepareModel function that are related
+     * to preparing the model are valid and there is no error, prepareModel must
+     * launch an asynchronous task to prepare the model in the background, and
+     * immediately return from prepareModel with ErrorStatus::NONE. If the
+     * asynchronous task fails to launch, prepareModel must immediately invoke
+     * the callback with ErrorStatus::GENERAL_FAILURE and nullptr for the
+     * IPreparedModel, then return with ErrorStatus::GENERAL_FAILURE.
+     *
+     * When the asynchronous task has finished preparing the model, it must
+     * immediately invoke the callback function provided as an input to
+     * prepareModel. If the model was prepared successfully, the callback object
+     * must be invoked with an error status of ErrorStatus::NONE and the
+     * produced IPreparedModel object. If an error occurred preparing the model,
+     * the callback object must be invoked with the appropriate ErrorStatus
+     * value and nullptr for the IPreparedModel.
+     *
+     * Optionally, the driver may save the prepared model to cache during the
+     * asynchronous preparation. Any error that occurs when saving to cache must
+     * not affect the status of preparing the model. Even if the input arguments
+     * related to the cache may be invalid, or the driver may fail to save to
+     * cache, the prepareModel function must finish preparing the model. The
+     * driver may choose not to save to cache even if the caching information is
+     * provided and valid.
+     *
+     * The only information that may be unknown to the model at this stage is
+     * the shape of the tensors, which may only be known at execution time. As
+     * such, some driver services may return partially prepared models, where
+     * the prepared model may only be finished when it is paired with a set of
+     * inputs to the model. Note that the same prepared model object may be used
+     * with different shapes of inputs on different (possibly concurrent)
+     * executions.
+     *
+     * Multiple threads may call prepareModel on the same model concurrently.
+     *
+     * @param model The model to be prepared for execution.
+     * @param preference Indicates the intended execution behavior of a prepared
+     *     model.
+     * @param modelCache A vector of handles with each entry holding exactly one
+     *     cache file descriptor for the security-sensitive cache. The length of
+     *     the vector must either be 0 indicating that caching information is
+     *     not provided, or match the numModelCache returned from
+     *     getNumberOfCacheFilesNeeded. The cache handles will be provided in
+     *     the same order when retrieving the preparedModel from cache files
+     *     with prepareModelFromCache_1_3.
+     * @param dataCache A vector of handles with each entry holding exactly one
+     *     cache file descriptor for the constants' cache. The length of the
+     *     vector must either be 0 indicating that caching information is not
+     *     provided, or match the numDataCache returned from
+     *     getNumberOfCacheFilesNeeded. The cache handles will be provided in
+     *     the same order when retrieving the preparedModel from cache files
+     *     with prepareModelFromCache_1_3.
+     * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN
+     *     identifying the prepared model. The same token will be provided when
+     *     retrieving the prepared model from the cache files with
+     *     prepareModelFromCache_1_3.  Tokens should be chosen to have a low rate of
+     *     collision for a particular application. The driver cannot detect a
+     *     collision; a collision will result in a failed execution or in a
+     *     successful execution that produces incorrect output values. If both
+     *     modelCache and dataCache are empty indicating that caching
+     *     information is not provided, this token must be ignored.
+     * @param callback A callback object used to return the error status of
+     *     preparing the model for execution and the prepared model if
+     *     successful, nullptr otherwise. The callback object's notify function
+     *     must be called exactly once, even if the model could not be prepared.
+     * @return status Error status of launching a task which prepares the model
+     *     in the background; must be:
+     *     - NONE if preparation task is successfully launched
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if one of the input arguments related to preparing
+     *       the model is invalid
+     */
+    prepareModel_1_3(Model model, ExecutionPreference preference,
+                     vec<handle> modelCache, vec<handle> dataCache,
+                     uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token,
+                     IPreparedModelCallback callback)
+        generates (ErrorStatus status);
+
+    /**
+     * Creates a prepared model from cache files for execution.
+     *
+     * prepareModelFromCache_1_3 is used to retrieve a prepared model directly from
+     * cache files to avoid slow model compilation time. There are
+     * two types of cache file handles provided to the driver: model cache
+     * and data cache. For more information on the two types of cache handles,
+     * refer to getNumberOfCacheFilesNeeded.
+     *
+     * The file descriptors must be opened with read and write permission. A file may
+     * have any size, and the corresponding file descriptor may have any offset. The
+     * driver must truncate a file to zero size before writing to that file. The file
+     * descriptors may be closed by the client once the asynchronous preparation has
+     * finished. The driver must dup a file descriptor if it wants to get access to
+     * the cache file later.
+     *
+     * The model is prepared asynchronously with respect to the caller. The
+     * prepareModelFromCache_1_3 function must verify the inputs to the
+     * prepareModelFromCache_1_3 function are correct, and that the security-sensitive
+     * cache has not been modified since it was last written by the driver.
+     * If there is an error, or if compilation caching is not supported, or if the
+     * security-sensitive cache has been modified, prepareModelFromCache_1_3 must
+     * immediately invoke the callback with the appropriate ErrorStatus value and
+     * nullptr for the IPreparedModel, then return with the same ErrorStatus. If
+     * the inputs to the prepareModelFromCache_1_3 function are valid, the security-sensitive
+     * cache is not modified, and there is no error, prepareModelFromCache_1_3 must launch an
+     * asynchronous task to prepare the model in the background, and immediately return
+     * from prepareModelFromCache_1_3 with ErrorStatus::NONE. If the asynchronous task
+     * fails to launch, prepareModelFromCache_1_3 must immediately invoke the callback
+     * with ErrorStatus::GENERAL_FAILURE and nullptr for the IPreparedModel, then
+     * return with ErrorStatus::GENERAL_FAILURE.
+     *
+     * When the asynchronous task has finished preparing the model, it must
+     * immediately invoke the callback function provided as an input to
+     * prepareModelFromCache_1_3. If the model was prepared successfully, the
+     * callback object must be invoked with an error status of ErrorStatus::NONE
+     * and the produced IPreparedModel object. If an error occurred preparing
+     * the model, the callback object must be invoked with the appropriate
+     * ErrorStatus value and nullptr for the IPreparedModel.
+     *
+     * The only information that may be unknown to the model at this stage is
+     * the shape of the tensors, which may only be known at execution time. As
+     * such, some driver services may return partially prepared models, where
+     * the prepared model may only be finished when it is paired with a set of
+     * inputs to the model. Note that the same prepared model object may be
+     * used with different shapes of inputs on different (possibly concurrent)
+     * executions.
+     *
+     * @param modelCache A vector of handles with each entry holding exactly one
+     *     cache file descriptor for the security-sensitive cache. The length of
+     *     the vector must match the numModelCache returned from getNumberOfCacheFilesNeeded.
+     *     The cache handles will be provided in the same order as with prepareModel_1_3.
+     * @param dataCache A vector of handles with each entry holding exactly one
+     *     cache file descriptor for the constants' cache. The length of the vector
+     *     must match the numDataCache returned from getNumberOfCacheFilesNeeded.
+     *     The cache handles will be provided in the same order as with prepareModel_1_3.
+     * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN
+     *     identifying the prepared model. It is the same token provided when saving
+     *     the cache files with prepareModel_1_3. Tokens should be chosen
+     *     to have a low rate of collision for a particular application. The driver
+     *     cannot detect a collision; a collision will result in a failed execution
+     *     or in a successful execution that produces incorrect output values.
+     * @param callback A callback object used to return the error status of
+     *     preparing the model for execution and the prepared model if
+     *     successful, nullptr otherwise. The callback object's notify function
+     *     must be called exactly once, even if the model could not be prepared.
+     * @return status Error status of launching a task which prepares the model
+     *     in the background; must be:
+     *     - NONE if preparation task is successfully launched
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if caching is not supported or if there is an
+     *       unspecified error
+     *     - INVALID_ARGUMENT if one of the input arguments is invalid
+     */
+    prepareModelFromCache_1_3(vec<handle> modelCache, vec<handle> dataCache,
+                              uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token,
+                              IPreparedModelCallback callback)
+            generates (ErrorStatus status);
+};
diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
new file mode 100644
index 0000000..c04809f
--- /dev/null
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -0,0 +1,90 @@
+/*
+ * 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.neuralnetworks@1.3;
+
+import @1.0::ErrorStatus;
+import @1.0::Request;
+import @1.2::MeasureTiming;
+import @1.2::IExecutionCallback;
+import @1.2::IPreparedModel;
+
+/**
+ * IPreparedModel describes a model that has been prepared for execution and
+ * is used to launch executions.
+ */
+interface IPreparedModel extends @1.2::IPreparedModel {
+    /**
+     * Launches an asynchronous execution on a prepared model.
+     *
+     * The execution is performed asynchronously with respect to the caller.
+     * execute_1_3 must verify the inputs to the function are correct. If there is
+     * an error, execute_1_3 must immediately invoke the callback with the
+     * appropriate ErrorStatus value, then return with the same ErrorStatus. If
+     * the inputs to the function are valid and there is no error, execute_1_3 must
+     * launch an asynchronous task to perform the execution in the background,
+     * and immediately return with ErrorStatus::NONE. If the asynchronous task
+     * fails to launch, execute_1_3 must immediately invoke the callback with
+     * ErrorStatus::GENERAL_FAILURE, then return with
+     * ErrorStatus::GENERAL_FAILURE.
+     *
+     * When the asynchronous task has finished its execution, it must
+     * immediately invoke the callback object provided as an input to the
+     * execute_1_3 function. This callback must be provided with the ErrorStatus of
+     * the execution.
+     *
+     * If the launch is successful, the caller must not change the content of
+     * any data object referenced by 'request' (described by the
+     * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}) until the
+     * asynchronous task has invoked the callback object. The asynchronous task
+     * must not change the content of any of the data objects corresponding to
+     * 'request' inputs.
+     *
+     * If the prepared model was prepared from a model wherein all tensor
+     * operands have fully specified dimensions, and the inputs to the function
+     * are valid, then:
+     * - the execution should launch successfully (ErrorStatus::NONE): There
+     *   must be no failure unless the device itself is in a bad state.
+     * - if at execution time every operation's input operands have legal
+     *   values, the execution should complete successfully (ErrorStatus::NONE):
+     *   There must be no failure unless the device itself is in a bad state.
+     *
+     * Any number of calls to the execute, execute_1_2, execute_1_3, and executeSynchronously
+     * functions, in any combination, may be made concurrently, even on the same
+     * IPreparedModel object.
+     *
+     * @param request The input and output information on which the prepared
+     *                model is to be executed.
+     * @param measure Specifies whether or not to measure duration of the execution.
+     *                The duration runs from the time the driver sees the call
+     *                to the execute_1_3 function to the time the driver invokes
+     *                the callback.
+     * @param callback A callback object used to return the error status of
+     *                 the execution. The callback object's notify function must
+     *                 be called exactly once, even if the execution was
+     *                 unsuccessful.
+     * @return status Error status of the call, must be:
+     *                - NONE if task is successfully launched
+     *                - DEVICE_UNAVAILABLE if driver is offline or busy
+     *                - GENERAL_FAILURE if there is an unspecified error
+     *                - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
+     *                  not large enough to store the resultant values
+     *                - INVALID_ARGUMENT if one of the input arguments is
+     *                  invalid
+     */
+    execute_1_3(Request request, MeasureTiming measure, IExecutionCallback callback)
+        generates (ErrorStatus status);
+};
diff --git a/neuralnetworks/1.3/IPreparedModelCallback.hal b/neuralnetworks/1.3/IPreparedModelCallback.hal
new file mode 100644
index 0000000..ff295a2
--- /dev/null
+++ b/neuralnetworks/1.3/IPreparedModelCallback.hal
@@ -0,0 +1,57 @@
+/*
+ * 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.neuralnetworks@1.3;
+
+import @1.0::ErrorStatus;
+import @1.2::IPreparedModelCallback;
+import IPreparedModel;
+
+/**
+ * IPreparedModelCallback must be used to return a prepared model produced by an
+ * asynchronous task launched from IDevice::prepareModel.
+ */
+interface IPreparedModelCallback extends @1.2::IPreparedModelCallback {
+
+    /**
+     * There are three notify methods declared for the IPreparedModelCallback
+     * interface: notify_1_3, notify_1_2, and notify. One of the three
+     * notify methods must be invoked immediately after the asynchronous
+     * task holding this callback has finished preparing the model. If the model was
+     * successfully prepared, one of the notify methods must be invoked with
+     * ErrorStatus::NONE and the prepared model. If the model was not able to be
+     * successfully prepared, one of the notify methods must be invoked with the
+     * appropriate ErrorStatus and nullptr as the IPreparedModel. If the asynchronous
+     * task holding this callback fails to launch or if the model provided to
+     * IDevice::prepareModel is invalid, one of the notify methods must be invoked
+     * with the appropriate error as well as nullptr for the IPreparedModel.
+     *
+     * @param status Error status returned from the asynchronous model
+     *               preparation task; must be:
+     *               - NONE if the asynchronous task successfully prepared the
+     *                 model
+     *               - DEVICE_UNAVAILABLE if driver is offline or busy
+     *               - GENERAL_FAILURE if the asynchronous task resulted in an
+     *                 unspecified error
+     *               - INVALID_ARGUMENT if one of the input arguments to
+     *                 prepareModel is invalid
+     * @param preparedModel A model that has been asynchronously prepared for
+     *                      execution. If the model was unable to be prepared
+     *                      due to an error, nullptr must be passed in place of
+     *                      the IPreparedModel object.
+     */
+    oneway notify_1_3(ErrorStatus status, IPreparedModel preparedModel);
+};
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
new file mode 100644
index 0000000..84c4813
--- /dev/null
+++ b/neuralnetworks/1.3/types.hal
@@ -0,0 +1,4915 @@
+/*
+ * 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.neuralnetworks@1.3;
+
+import @1.0::DataLocation;
+import @1.0::OperandLifeTime;
+import @1.0::PerformanceInfo;
+import @1.2::OperandType;
+import @1.2::OperationType;
+import @1.2::SymmPerChannelQuantParams;
+
+import android.hidl.safe_union@1.0::Monostate;
+
+enum OperandType : @1.2::OperandType {
+    /**
+     * A tensor of 8 bit signed integers that represent real numbers.
+     *
+     * Attached to this tensor are two numbers that can be used to convert the
+     * 8 bit integer to the real value and vice versa. These two numbers are:
+     * - scale: a 32 bit floating point value greater than zero.
+     * - zeroPoint: a 32 bit integer, in range [-128, 127].
+     *
+     * The formula is:
+     * real_value = (integer_value - zeroPoint) * scale.
+     */
+    TENSOR_QUANT8_ASYMM_SIGNED = 14,
+
+    /*
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
+     *
+     * OEM specific scalar value.
+     * OEM                 = 10000,
+     */
+    /*
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
+     *
+     * A tensor of OEM specific values.
+     * TENSOR_OEM_BYTE     = 10001,
+     */
+    /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF
+     * OperandTypeRange::FUNDAMENTAL_MAX.
+     */
+    /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF
+     * OperandTypeRange::OEM_MAX.
+     */
+};
+
+/**
+ * The range of operand values in the OperandType enum.
+ */
+enum OperandTypeRange : uint32_t {
+    BASE_MIN        = 0,
+    FUNDAMENTAL_MIN = 0,
+    FUNDAMENTAL_MAX = 14,
+    OEM_MIN         = 10000,
+    OEM_MAX         = 10001,
+    BASE_MAX        = 0xFFFF,
+};
+
+/**
+ * Operation types.
+ *
+ * The type of an operation in a model.
+ */
+enum OperationType : int32_t {
+
+    /**
+     * Adds two tensors, element-wise.
+     *
+     * Takes two input tensors of identical {@link OperandType} and compatible
+     * dimensions. The output is the sum of both input tensors, optionally
+     * modified by an activation function.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the output is the maximum size along each dimension of the
+     * input operands. It starts with the trailing dimensions, and works its
+     * way forward.
+     *
+     * Example:
+     *
+     *     input1.dimension = {4, 1, 2}
+     *     input2.dimension = {5, 4, 3, 1}
+     *     output.dimension = {5, 4, 3, 2}
+     *
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+     *      as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
+     * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     *
+     * Outputs:
+     * * 0: The sum, a tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    ADD = @1.2::OperationType:ADD,
+
+    /**
+     * Performs a 2-D average pooling operation.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, channel] =
+     *         sum_{di, dj}(
+     *             input[b, strides[1] * i + di, strides[2] * j + dj, channel]
+     *         ) / sum(1)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
+     *       Set to true to specify NCHW data layout for input0 and output0.
+     *       Available since HAL version 1.2.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    AVERAGE_POOL_2D = @1.2::OperationType:AVERAGE_POOL_2D,
+
+    /**
+     * Concatenates the input tensors along the given dimension.
+     *
+     * The input tensors must have identical {@link OperandType} and the same
+     * dimensions except the dimension along the concatenation axis.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (full support since HAL version 1.2, see the input section)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0 ~ n-1: The list of n input tensors, of shape
+     *            [D0, D1, ..., Daxis(i), ..., Dm].
+     *            Before HAL version 1.2, all input tensors of
+     *            {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *            must have the same scale and zeroPoint as the output tensor.
+     *            Input tensors of
+     *            {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+     *            are allowed to have different scale and zeroPoint.
+     *            Since HAL version 1.2, zero-sized tensors are supported.
+     * * n: An {@link OperandType::INT32} scalar, specifying the
+     *      concatenation axis.
+     *
+     * Outputs:
+     * * 0: The output, a tensor of the same {@link OperandType} as the input
+     *      tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm].
+     *      Since HAL version 1.2, for a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint values can be different from
+     *      input tensors. Before HAL version 1.2 they have to be the same as for the input tensors.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint values can be different from input tensors.
+     */
+    CONCATENATION = @1.2::OperationType:CONCATENATION,
+
+    /**
+     * Performs a 2-D convolution operation.
+     *
+     * The CONV_2D op sweeps a 2-D filter that can mix channels together over a
+     * batch of images, applying the filter to each window of each image of the
+     * appropriate size.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, channel] =
+     *         sum_{di, dj, k} (
+     *             input[b, strides[1] * i + di, strides[2] * j + dj, k] *
+     *             filter[channel, di, dj, k]
+     *         ) + bias[channel]
+     *
+     * Supported tensor {@link OperandType} configurations:
+     * * 32 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias.
+     *
+     * * Quantized:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * Available since HAL version 1.2:
+     * * 16 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
+     *
+     * * Quantized with symmetric per channel quantization for the filter:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output.
+     * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+     * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+     * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_in], specifying the
+     *      filter.
+     *      For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     * * 11: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on width dimension. If this input is set,
+     *      input 12 (dilation factor for height) must be specified as well.
+     *      Available since HAL version 1.2.
+     * * 12: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on height dimension. If this input is set,
+     *      input 11 (dilation factor for width) must be specified as well.
+     *      Available since HAL version 1.2.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_in], specifying the
+     *      filter.
+     *      For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     * * 8: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on width dimension. If this input is set,
+     *      input 9 (dilation factor for height) must be specified as well.
+     *      Available since HAL version 1.2.
+     * * 9: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on height dimension. If this input is set,
+     *      input 8 (dilation factor for width) must be specified as well.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth_out].
+     *      Before HAL version 1.2, for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the following condition must be satisfied: output_scale > input_scale * filter_scale
+     */
+    CONV_2D = @1.2::OperationType:CONV_2D,
+
+    /**
+     * Performs a depthwise 2-D convolution operation.
+     *
+     * Given an input tensor of shape [batches, height, width, depth_in] and a
+     * filter tensor of shape [1, filter_height, filter_width, depth_out]
+     * containing depth_out convolutional filters of depth 1, DEPTHWISE_CONV
+     * applies a different filter to each input channel (expanding from 1
+     * channel to channel_multiplier channels for each), then concatenates the
+     * results together.
+     *
+     * The output has depth_out = depth_in * depth_multiplier channels.
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, k * channel_multiplier + q] =
+     *         sum_{di, dj} (
+     *             input[b, strides[1] * i + di, strides[2] * j + dj, k] *
+     *             filter[1, di, dj, k * channel_multiplier + q]
+     *         ) + bias[k * channel_multiplier + q]
+     *
+     * Supported tensor {@link OperandType} configurations:
+     * * 32 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias.
+     *
+     * * Quantized:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * Available since HAL version 1.2:
+     * * 16 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
+     *
+     * * Quantized with symmetric per channel quantization for the filter:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output.
+     * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+     * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+     * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
+     *      specifying the filter.
+     *      For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 3.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 9: An {@link OperandType::INT32} scalar, specifying the depthwise
+     *      multiplier.
+     * * 10: An {@link OperandType::INT32} scalar, and has to be one of the
+     *       {@link FusedActivationFunc} values. Specifies the activation to
+     *       invoke on the result.
+     * * 11: An optional {@link OperandType::BOOL} scalar, default to false.
+     *       Set to true to specify NCHW data layout for input0 and output0.
+     *       Available since HAL version 1.2.
+     * * 12: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on width dimension. If this input is set,
+     *      input 13 (dilation factor for height) must be specified as well.
+     *      Available since HAL version 1.2.
+     * * 13: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on height dimension. If this input is set,
+     *      input 12 (dilation factor for width) must be specified as well.
+     *      Available since HAL version 1.2.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
+     *      specifying the filter.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the depthwise
+     *      multiplier.
+     * * 7: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 8: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     * * 9: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on width dimension. If this input is set,
+     *      input 10 (dilation factor for height) must be specified as well.
+     *      Available since HAL version 1.2.
+     * * 10: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on height dimension. If this input is set,
+     *      input 9 (dilation factor for width) must be specified as well.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth_out]. Before HAL version 1.2, for
+     *      output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the following condition must be satisfied:
+     *      output_scale > input_scale * filter_scale
+     */
+    DEPTHWISE_CONV_2D = @1.2::OperationType:DEPTHWISE_CONV_2D,
+
+    /**
+     * Rearranges data from depth into blocks of spatial data.
+     *
+     * More specifically, this op outputs a copy of the input tensor where
+     * values from the depth dimension are moved in spatial blocks to the height
+     * and width dimensions. The value block_size indicates the input block size
+     * and how the data is moved.
+     *
+     * Chunks of data of size block_size * block_size from depth are rearranged
+     * into non-overlapping blocks of size block_size x block_size.
+     *
+     * The width of the output tensor is input_depth * block_size, whereas the
+     * height is input_height * block_size. The depth of the input tensor must
+     * be divisible by block_size * block_size
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the block_size.
+     *      block_size must be >=1 and block_size * block_size must be a divisor
+     *      of the input depth.
+     * * 2: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape [batch, height*block_size,
+     *      width*block_size, depth/(block_size*block_size)].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    DEPTH_TO_SPACE = @1.2::OperationType:DEPTH_TO_SPACE,
+
+    /**
+     * Dequantizes the input tensor.
+     *
+     * The formula is:
+     *
+     *     output = (input - zeroPoint) * scale.
+     *
+     * Supported input tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_SYMM} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} (since HAL version 1.2)
+     *
+     * Supported output tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}.
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: A tensor with the same shape as input0.
+     */
+    DEQUANTIZE = @1.2::OperationType:DEQUANTIZE,
+
+    /**
+     * Looks up sub-tensors in the input tensor.
+     *
+     * This operator takes for input a tensor of values (Values) and
+     * a one-dimensional tensor of selection indices (Lookups).
+     * The output tensor is the concatenation of sub-tensors of Values as
+     * selected by Lookups.
+     *
+     * Think of Values as being sliced along its first dimension:
+     * The entries in Lookups select which slices are concatenated together
+     * to create the output tensor.
+     *
+     * For example, if Values has shape of [40, 200, 300] and
+     * Lookups has shape of [3], all three values found in Lookups are
+     * expected to be between 0 and 39. The resulting tensor must
+     * have shape of [3, 200, 300].
+     *
+     * If a value in Lookups is out of bounds, the operation must fail
+     * and an error must be reported.
+     *
+     * Supported value tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported value tensor rank: from 2
+     *
+     * Inputs:
+     * * 0: Lookups. A 1-D tensor of {@link OperandType::TENSOR_INT32}.
+     *      The values are indices into the first dimension of Values.
+     * * 1: Values. An n-D tensor, where n >= 2, from which sub-tensors are
+     *      extracted.
+     *
+     * Output:
+     * * 0: A n-D tensor with the same rank and shape as the Values
+     *      tensor, except for the first dimension which has the same size
+     *      as Lookups' only dimension.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input1.
+     */
+    EMBEDDING_LOOKUP = @1.2::OperationType:EMBEDDING_LOOKUP,
+
+    /**
+     * Computes element-wise floor() on the input tensor.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor, of the same {@link OperandType} and dimensions as
+     *      the input tensor.
+     */
+    FLOOR = @1.2::OperationType:FLOOR,
+
+    /**
+     * Denotes a fully (densely) connected layer, which connects all elements
+     * in the input tensor with each element in the output tensor.
+     *
+     * This layer implements the operation:
+     *
+     *     outputs = activation(inputs * weights’ + bias)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor of at least rank 2, specifying the input. If rank is
+     *      greater than 2, then it gets flattened to a 2-D Tensor. The
+     *      (flattened) 2-D Tensor is reshaped (if necessary) to
+     *      [batch_size, input_size], where "input_size" corresponds to the
+     *      number of inputs to the layer, matching the second dimension of
+     *      weights, and "batch_size" is calculated by dividing the number of
+     *      elements by "input_size".
+     *      Since HAL version 1.2, zero batch_size is supported for this tensor.
+     * * 1: A 2-D tensor, specifying the weights, of shape
+     *      [num_units, input_size], where "num_units" corresponds to the number
+     *      of output nodes.
+     * * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input
+     *      tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
+     *      also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
+     *      of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
+     *      of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
+     *      bias_scale == input_scale * filter_scale.
+     * * 3: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     *
+     * Outputs:
+     * * 0: The output tensor, of shape [batch_size, num_units]. Before HAL version 1.2, for
+     *      output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following
+     *      condition must be satisfied: output_scale > input_scale * filter_scale.
+     */
+    FULLY_CONNECTED = @1.2::OperationType:FULLY_CONNECTED,
+
+    /**
+     * Looks up sub-tensors in the input tensor using a key-value map.
+     *
+     * This operator takes for input a tensor of values (Values),
+     * a one-dimensional tensor of selection values (Lookups) and
+     * a one-dimensional tensor that maps these values to Values
+     * indexes. The output tensor is the concatenation of sub-tensors of
+     * Values as selected by Lookups via Keys.
+     *
+     * Think of Values as being sliced along its outer-most dimension.
+     * The output is a concatenation of selected slices, with one slice
+     * for each entry of Lookups. The slice selected is the one at the
+     * same index as the Maps entry that matches the value in Lookups.
+     *
+     * For a hit, the corresponding sub-tensor of Values is included
+     * in the Output tensor. For a miss, the corresponding sub-tensor in
+     * Output must have zero values.
+     *
+     * For example, if Values has shape of [40, 200, 300],
+     * Keys should have a shape of [40]. If Lookups tensor has shape
+     * of [3], three slices are being concatenated, so the resulting tensor
+     * must have the shape of [3, 200, 300]. If the first entry in Lookups
+     * has the value 123456, that value must be located in Keys tensor.
+     * If the sixth entry of Keys contains 123456, the sixth slice of Values
+     * must be selected. If no entry in Keys has 123456, a slice of zeroes
+     * must be concatenated.
+     *
+     * Supported value tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported value tensor rank: from 2
+     *
+     * Inputs:
+     * * 0: Lookups. A 1-D {@link OperandType::TENSOR_INT32} tensor with
+     *      shape [ k ].
+     * * 1: Keys. A 1-D {@link OperandType::TENSOR_INT32} tensor with shape
+     *      [ n ]; Keys and Values pair represent a map, i.e., the ith element
+     *      in Keys (Keys[i]) is the key to select the ith sub-tensor in Values
+     *      (Values[i]), where 0 <= i <= n-1. Keys tensor *MUST* be sorted in
+     *      ascending order.
+     * * 2: Values. A tensor with shape of [ n, … ]; i.e., the first dimension
+     *      must be n.
+     *
+     * Outputs:
+     * * 0: Output. A tensor with shape [ k …].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input2.
+     * * 1: Hits. A boolean tensor with shape [ k ] indicates whether the lookup
+     *      hits (True) or not (False).
+     *      Stored as {@link OperandType::TENSOR_QUANT8_ASYMM} with offset 0
+     *      and scale 1.0f.
+     *      A non-zero byte represents True, a hit. A zero indicates otherwise.
+     */
+    HASHTABLE_LOOKUP = @1.2::OperationType:HASHTABLE_LOOKUP,
+
+    /**
+     * Applies L2 normalization along the depth dimension.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[batch, row, col, channel] =
+     *         input[batch, row, col, channel] /
+     *         sqrt(sum_{c} pow(input[batch, row, col, c], 2))
+     *
+     * For input tensor with rank less than 4, independently normalizes each
+     * 1-D slice along dimension dim.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+     *
+     * Supported tensor rank: up to 4
+     * Tensors with rank less than 4 are only supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be normalized.
+     * * 1: An optional {@link OperandType::INT32} scalar, default to -1,
+     *      specifying the dimension normalization would be performed on.
+     *      Negative index is used to specify axis from the end (e.g. -1 for
+     *      the last axis). Must be in the range [-n, n).
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} and same shape as input0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale must be 1.f / 128 and the zeroPoint must be 128.
+     */
+    L2_NORMALIZATION = @1.2::OperationType:L2_NORMALIZATION,
+
+    /**
+     * Performs an 2-D L2 pooling operation.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, c] =
+     *         sqrt(sum_{di, dj} pow(input[b, strides[1] * i + di, strides[2] * j + dj, c], 2) /
+     *              sum(1))
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
+     *       Set to true to specify NCHW data layout for input0 and output0.
+     *       Available since HAL version 1.2.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth].
+     */
+    L2_POOL_2D = @1.2::OperationType:L2_POOL_2D,
+
+    /**
+     * Applies Local Response Normalization along the depth dimension.
+     *
+     * The 4-D input tensor is treated as a 3-D array of 1-D vectors (along the
+     * last dimension), and each vector is normalized independently. Within a
+     * given vector, each component is divided by the weighted, squared sum of
+     * inputs within depth_radius.
+     *
+     * The output is calculated using this formula:
+     *
+     *     sqr_sum[a, b, c, d] = sum(
+     *         pow(input[a, b, c, d - depth_radius : d + depth_radius + 1], 2))
+     *     output = input / pow((bias + alpha * sqr_sum), beta)
+     *
+     * For input tensor with rank less than 4, independently normalizes each
+     * 1-D slice along specified dimension.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: up to 4
+     * Tensors with rank less than 4 are only supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the radius of
+     *      the normalization window.
+     * * 2: A scalar, specifying the bias, must not be zero.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the bias
+     *      value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias
+     *      value must be of {@link OperandType::FLOAT32}.
+     * * 3: A scalar, specifying the scale factor, alpha.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the
+     *      alpha value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the
+     *      alpha value must be of {@link OperandType::FLOAT32}.
+     * * 4: A scalar, specifying the exponent, beta.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the beta
+     *      value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the beta
+     *      value must be of {@link OperandType::FLOAT32}.
+     * * 5: An optional {@link OperandType::INT32} scalar, default to -1,
+     *      specifying the dimension normalization would be performed on.
+     *      Negative index is used to specify axis from the end (e.g. -1 for
+     *      the last axis). Must be in the range [-n, n).
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    LOCAL_RESPONSE_NORMALIZATION = @1.2::OperationType:LOCAL_RESPONSE_NORMALIZATION,
+
+    /**
+     * Computes sigmoid activation on the input tensor element-wise.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = 1 / (1 + exp(-input))
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale must be 1.f / 256 and the zeroPoint must be 0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      the scale must be 1.f / 256 and the zeroPoint must be -128.
+     */
+    LOGISTIC = @1.2::OperationType:LOGISTIC,
+
+    /**
+     * Projects an input to a bit vector via locality senstive hashing.
+     *
+     * Supported input tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported input tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: Hash functions. Dim.size == 2, DataType: Float.
+     *      Tensor[0].Dim[0]: Number of hash functions.
+     *      Tensor[0].Dim[1]: Number of projected output bits generated by each
+     *      hash function.
+     *      If the projection type is Sparse:
+     *      Tensor[0].Dim[1] + ceil(log2(Tensor[0].Dim[0])) <= 32
+     *
+     * * 1: Input. Dim.size >= 1, no restriction on DataType.
+     * * 2: Weight. Optional. Dim.size == 1, DataType: Float.
+     *      If not set, each input element is considered to have the same weight
+     *      of 1.0.
+     *      Tensor[1].Dim[0] == Tensor[2].Dim[0]
+     * * 3: Type:
+     *        Sparse:
+     *          Value LSHProjectionType_SPARSE(=3) (since HAL version 1.2).
+     *          Computed bit vector is considered to be sparse.
+     *          Each output element is an int32 made up of multiple bits
+     *          computed from hash functions.
+     *
+     *          NOTE: To avoid collisions across hash functions, an offset value
+     *          of k * (1 << Tensor[0].Dim[1]) will be added to each signature,
+     *          where k is the index of the hash function.
+     *
+     *          Value LSHProjectionType_SPARSE_DEPRECATED(=1).
+     *          Legacy behavior that does not include the offset value.
+     *
+     *        Dense:
+     *          Value LSHProjectionType_DENSE(=2).
+     *          Computed bit vector is considered to be dense. Each output
+     *          element represents a bit and can take the value of either
+     *          0 or 1.
+     *
+     * Outputs:
+     * * 0: If the projection type is Sparse:
+     *      Output.Dim == { Tensor[0].Dim[0] }
+     *      A tensor of int32 that represents hash signatures.
+     *
+     *      If the projection type is Dense:
+     *      Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] }
+     *      A flattened tensor that represents projected bit vectors.
+     * The offset value for sparse projections was added in HAL version 1.2.
+     */
+    LSH_PROJECTION = @1.2::OperationType:LSH_PROJECTION,
+
+    /**
+     * Performs a single time step in a Long Short-Term Memory (LSTM) layer
+     *
+     * The LSTM operation is described by the following equations.
+     *
+     * \f{eqnarray*}{
+     * i_t =& \sigma(W_{xi}x_t+W_{hi}h_{t-1}+W_{ci}C_{t-1}+b_i) & \\
+     * f_t =& \sigma(W_{xf}x_t+W_{hf}h_{t-1}+W_{cf}C_{t-1}+b_f) & \\
+     * C_t =& clip(f_t \odot C_{t-1} + i_t \odot
+     *        g(W_{xc}x_t+W_{hc}h_{t-1}+b_c),\ t_{cell}) & \\
+     * o_t =& \sigma(W_{xo}x_t+W_{ho}h_{t-1}+W_{co}C_t+b_o) & \\
+     *      & & \\
+     *      & clip(W_{proj}(o_t \odot g(C_t))+b_{proj},\ t_{proj})
+     *      & if\ there\ is\ a\ projection; \\
+     * h_t =& & \\
+     *      & o_t \odot g(C_t) & otherwise. \\
+     * \f}
+     * Where:
+     * * \f$x_t\f$ is the input,
+     * * \f$i_t\f$ is the input gate,
+     * * \f$f_t\f$ is the forget gate,
+     * * \f$C_t\f$ is the cell state,
+     * * \f$o_t\f$ is the output,
+     * * \f$h_t\f$ is the output state,
+     * * \f$\sigma\f$ is the logistic sigmoid function,
+     * * \f$g\f$ is the cell input and cell output activation function, usually
+     *   \f$tahn\f$,
+     * * \f$W_{xi}\f$ is the input-to-input weight matrix,
+     * * \f$W_{hi}\f$ is the recurrent to input weight matrix,
+     * * \f$W_{ci}\f$ is the cell-to-input weight matrix,
+     * * \f$b_i\f$ is the input gate bias,
+     * * \f$W_{xf}\f$ is the input-to-forget weight matrix,
+     * * \f$W_{hf}\f$ is the recurrent-to-forget weight matrix,
+     * * \f$W_{cf}\f$ is the cell-to-forget weight matrix,
+     * * \f$b_f\f$ is the forget gate bias,
+     * * \f$W_{xc}\f$ is the input-to-cell weight matrix,
+     * * \f$W_{hc}\f$ is the recurrent-to-cell weight matrix,
+     * * \f$b_c\f$ is the cell bias,
+     * * \f$W_{xo}\f$ is the input-to-output weight matrix,
+     * * \f$W_{ho}\f$ is the recurrent-to-output weight matrix,
+     * * \f$W_{co}\f$ is the cell-to-output weight matrix,
+     * * \f$b_o\f$ is the output gate bias,
+     * * \f$W_{proj}\f$ is the projection weight matrix,
+     * * \f$b_{proj}\f$ is the projection bias,
+     * * \f$t_{cell}\f$ is the threshold for clipping the cell state, and
+     * * \f$t_{proj}\f$ is the threshold for clipping the projected output.
+     * * \f$\odot\f$ is the
+     *   <a href="https://en.wikipedia.org/wiki/Hadamard_product_(matrices)">
+     *   Hadamard product</a> that takes two matrices and produces another
+     *   matrix, each element of which is the product of the corresponding
+     *   elements of the input matrices.
+     *
+     * Since HAL version 1.2 LSTM supports layer normalization.
+     * In case layer normalization is used, the inputs to internal activation
+     * functions (sigmoid and \f$g\f$) are normalized, rescaled and recentered
+     * following an approach from section 3.1 from
+     * https://arxiv.org/pdf/1607.06450.pdf
+     *
+     * The operation has the following independently optional inputs:
+     * * The cell-to-input weights (\f$W_{ci}\f$), cell-to-forget weights
+     *   (\f$W_{cf}\f$) and cell-to-output weights (\f$W_{co}\f$) either all
+     *   have values or neither of them have values (i.e., all set to null). If
+     *   they have values, the peephole optimization is used.
+     * * The input-to-input weights (\f$W_{xi}\f$), recurrent-to-input weights
+     *   (\f$W_{hi}\f$) and input gate bias (\f$b_i\f$) either all have values,
+     *   or none of them have values. If they have no values, coupling of input
+     *   and forget gates (CIFG) is used, in which case the input gate
+     *   (\f$i_t\f$) is calculated using the following equation instead.
+     *   \f{eqnarray*}{
+     *   i_t = 1 - f_t
+     *   \f}
+     *   In case peephole optimization is used and CIFG is not used
+     *   cell-to-input (\f$W_{ci}\f$) weights must be present. Otherwise, the
+     *   cell-to-input weights must have no value.
+     * * The projection weights (\f$W_{proj}\f$) is required only for the
+     *   recurrent projection layer, and should otherwise have no value.
+     * * The projection bias (\f$b_{proj}\f$) may (but not required to) have a
+     *   value if the recurrent projection layer exists, and should otherwise
+     *   have no value.
+     * * (HAL version 1.2 or later) The four layer normalization weights either all have
+     *   values or none of them have values. Additionally, if CIFG is used,
+     *   input layer normalization weights tensor is omitted and the other layer
+     *   normalization weights either all have values or none of them have
+     *   values. Layer normalization is used when the values of all the layer
+     *   normalization weights are present.
+     *
+     * References:
+     *
+     * The default non-peephole non-CIFG implementation is based on:
+     * http://www.bioinf.jku.at/publications/older/2604.pdf
+     * S. Hochreiter and J. Schmidhuber. "Long Short-Term Memory". Neural
+     * Computation, 9(8):1735-1780, 1997.
+     *
+     * The peephole implementation and projection layer is based on:
+     * https://research.google.com/pubs/archive/43905.pdf
+     * Hasim Sak, Andrew Senior, and Francoise Beaufays. "Long short-term memory
+     * recurrent neural network architectures for large scale acoustic
+     * modeling." INTERSPEECH, 2014.
+     * (However, the concept of peephole optimization was introduced in work
+     * prior to this paper.)
+     *
+     * The coupling of input and forget gate (CIFG) is based on:
+     * http://arxiv.org/pdf/1503.04069.pdf
+     * Greff et al. "LSTM: A Search Space Odyssey"
+     *
+     * The layer normalization is based on:
+     * https://arxiv.org/pdf/1607.06450.pdf
+     * Jimmy Ba et al. "Layer Normalization"
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * All input and output tensors must be of the same type.
+     *
+     * Inputs:
+     * * 0: The input (\f$x_t\f$).
+     *      A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+     *      corresponds to the batching dimension, and “input_size” is the size
+     *      of the input.
+     * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of cell units.
+     * * 2: The input-to-forget weights (\f$W_{xf}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 3: The input-to-cell weights (\f$W_{xc}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 4: The input-to-output weights (\f$W_{xo}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional.
+     *      A 2-D tensor of shape [num_units, output_size], where “output_size”
+     *      corresponds to either the number of cell units (i.e., “num_units”),
+     *      or the second dimension of the “projection_weights”, if defined.
+     * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 8: The recurrent-to-output weights (\f$W_{ho}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 12:The input gate bias (\f$b_i\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 13:The forget gate bias (\f$b_f\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 14:The cell bias (\f$b_c\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 15:The output gate bias (\f$b_o\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 16:The projection weights (\f$W_{proj}\f$). Optional.
+     *      A 2-D tensor of shape [output_size, num_units].
+     * * 17:The projection bias (\f$b_{proj}\f$). Optional.
+     *      A 1-D tensor of shape [output_size].
+     * * 18:The output state (in) (\f$h_{t-1}\f$).
+     *      A 2-D tensor of shape [batch_size, output_size].
+     * * 19:The cell state (in) (\f$C_{t-1}\f$).
+     *      A 2-D tensor of shape [batch_size, num_units].
+     * * 20:The activation function (\f$g\f$).
+     *      A value indicating the activation function:
+     *      <ul>
+     *      <li>0: None;
+     *      <li>1: Relu;
+     *      <li>3: Relu6;
+     *      <li>4: Tanh;
+     *      <li>6: Sigmoid.
+     *      </ul>
+     * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such
+     *      that values are bound within [-cell_clip, cell_clip]. If set to 0.0
+     *      then clipping is disabled.
+     *      Until HAL version 1.2 this scalar must be of type {@link
+     *      OperandType::FLOAT32}. Since HAL version 1.2, if all the input
+     *      tensors have type {@link OperandType::TENSOR_FLOAT32}, this
+     *      scalar must be of the type {@link OperandType::FLOAT32},
+     *      otherwise if all the input tensors have the type {@link
+     *      OperandType::TENSOR_FLOAT16}, this scalar must be of type {@link
+     *      OperandType::FLOAT16}.
+     * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the
+     *      projection layer, such that values are bound within
+     *      [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
+     *      Until HAL version 1.2 this scalar must be of type {@link
+     *      OperandType::FLOAT32}. Since HAL version 1.2, if all the input
+     *      tensors have type {@link OperandType::TENSOR_FLOAT32}, this
+     *      scalar must be of the type {@link OperandType::FLOAT32},
+     *      otherwise if all the input tensors have the type {@link
+     *      OperandType::TENSOR_FLOAT16}, this scalar must be of type {@link
+     *      OperandType::FLOAT16}.
+     * Since HAL version 1.2 there are additional inputs to this op:
+     * * 23:The input layer normalization weights.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at input gate.
+     * * 24:The forget layer normalization weights.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at forget gate.
+     * * 25:The cell layer normalization weights.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at cell gate.
+     * * 26:The output layer normalization weights.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at output gate.
+     *
+     * Outputs:
+     * * 0: The scratch buffer.
+     *      A 2-D tensor of shape [batch_size, num_units * 3] with CIFG, or
+     *      [batch_size, num_units * 4] without CIFG.
+     * * 1: The output state (out) (\f$h_t\f$).
+     *      A 2-D tensor of shape [batch_size, output_size].
+     * * 2: The cell state (out) (\f$C_t\f$).
+     *      A 2-D tensor of shape [batch_size, num_units].
+     * * 3: The output (\f$o_t\f$).
+     *      A 2-D tensor of shape [batch_size, output_size]. This is effectively
+     *      the same as the current “output state (out)” value.
+     */
+    LSTM = @1.2::OperationType:LSTM,
+
+    /**
+     * Performs an 2-D max pooling operation.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, channel] =
+     *         max_{di, dj} (
+     *             input[b, strides[1] * i + di, strides[2] * j + dj, channel]
+     *         )
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
+     *       Set to true to specify NCHW data layout for input0 and output0.
+     *       Available since HAL version 1.2.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    MAX_POOL_2D = @1.2::OperationType:MAX_POOL_2D,
+
+    /**
+     * Multiplies two tensors, element-wise.
+     *
+     * Takes two input tensors of identical {@link OperandType} and compatible
+     * dimensions. The output is the product of both input tensors, optionally
+     * modified by an activation function.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the resulting output is the maximum size along each dimension
+     * of the input operands. It starts with the trailing dimensions, and works
+     * its way forward.
+     *
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+     *      as input0.
+     * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     *
+     * Outputs:
+     * * 0: The product, a tensor of the same {@link OperandType} as input0.
+     *      For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      the following condition must be satisfied:
+     *      output_scale > input1_scale * input2_scale.
+     */
+    MUL = @1.2::OperationType:MUL,
+
+    /**
+     * Computes rectified linear activation on the input tensor element-wise.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = max(0, input)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RELU = @1.2::OperationType:RELU,
+
+    /**
+     * Computes rectified linear 1 activation on the input tensor element-wise.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = min(1.f, max(-1.f, input))
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of the same shape as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RELU1 = @1.2::OperationType:RELU1,
+
+    /**
+     * Computes rectified linear 6 activation on the input tensor element-wise.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = min(6, max(0, input))
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RELU6 = @1.2::OperationType:RELU6,
+
+    /**
+     * Reshapes a tensor.
+     *
+     * Given tensor, this operation returns a tensor that has the same values as
+     * tensor, but with a newly specified shape.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the tensor to be reshaped.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}, defining the
+     *      shape of the output tensor. The number of elements implied by shape
+     *      must be the same as the number of elements in the input tensor.
+     *
+     *      If one component of shape is the special value -1, the size of that
+     *      dimension is computed so that the total size remains constant. In
+     *      particular, a shape of [-1] flattens into 1-D. At most one component
+     *      of shape can be -1.
+     *
+     * Outputs:
+     * * 0: The output tensor, of shape specified by the input shape.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RESHAPE = @1.2::OperationType:RESHAPE,
+
+    /**
+     * Resizes images to given size using the bilinear interpretation.
+     *
+     * Resized images must be distorted if their output aspect ratio is not the
+     * same as input aspect ratio. The corner pixels of output may not be the
+     * same as corner pixels of input.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both resizing by shape and resizing by scale are supported.
+     *
+     * Inputs (resizing by shape):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the output
+     *      width of the output tensor.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
+     * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Inputs (resizing by scale, since HAL version 1.2):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input. Zero batches is supported for this tensor.
+     * * 1: A scalar, specifying width_scale, the scaling factor of the width
+     *      dimension from the input tensor to the output tensor. The output
+     *      width is calculated as new_width = floor(width * width_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 2: A scalar, specifying height_scale, the scaling factor of the height
+     *      dimension from the input tensor to the output tensor. The output
+     *      height is calculated as new_height = floor(height * height_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, new_height, new_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RESIZE_BILINEAR = @1.2::OperationType:RESIZE_BILINEAR,
+
+    /**
+     * A basic recurrent neural network layer.
+     *
+     * This layer implements the operation:
+     * outputs = state = activation(inputs * input_weights +
+     *                              state * recurrent_weights + bias)
+     *
+     * Where:
+     * * “input_weights” is a weight matrix that multiplies the inputs;
+     * * “recurrent_weights” is a weight matrix that multiplies the current
+     *    “state” which itself is the output from the previous time step
+     *    computation;
+     * * “bias” is a bias vector (added to each output vector in the batch);
+     * * “activation” is the function passed as the “fused_activation_function”
+     *   argument (if not “NONE”).
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * The input tensors must all be the same type.
+     *
+     * Inputs:
+     * * 0: input.
+     *      A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+     *      corresponds to the batching dimension, and “input_size” is the size
+     *      of the input.
+     * * 1: weights.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of units.
+     * * 2: recurrent_weights.
+     *      A 2-D tensor of shape [num_units, num_units], with columns
+     *      corresponding to the weights from each unit.
+     * * 3: bias.
+     *      A 1-D tensor of shape [num_units].
+     * * 4: hidden state (in).
+     *      A 2-D tensor of shape [batch_size, num_units].
+     * * 5: fused_activation_function.
+     *      An optional {@link FusedActivationFunc} value indicating the
+     *      activation function. If “NONE” is specified then it results in a
+     *      linear activation.
+     *
+     * Outputs:
+     * * 0: hidden state (out).
+     *      A 2-D tensor of shape [batch_size, num_units].
+     *
+     * * 1: output.
+     *      A 2-D tensor of shape [batch_size, num_units]. This is effectively
+     *      the same as the current state value.
+     */
+    RNN = @1.2::OperationType:RNN,
+
+    /**
+     * Computes the softmax activation on the input tensor element-wise, per
+     * batch, by normalizing the input vector so the maximum coefficient is
+     * zero.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output[batch, i] =
+     *         exp((input[batch, i] - max(input[batch, :])) * beta) /
+     *         sum_{k}{exp((input[batch, k] - max(input[batch, :])) * beta)}
+     *
+     * For input tensor with rank other than 2, the activation will be applied
+     * independently on each 1-D slice along specified dimension.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4.
+     * Tensors with rank other than 2 or 4 are only supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     * * 1: A scalar, specifying the positive scaling factor for the exponent,
+     *      beta. If input0 is of {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the scalar must be of
+     *      {@link OperandType::FLOAT32}.
+     *      If input0 is of {@link OperandType::TENSOR_FLOAT16}, then the
+     *      scalar must be of {@link OperandType::FLOAT16}.
+     * * 2: An optional {@link OperandType::INT32} scalar, default to -1,
+     *      specifying the dimension the activation would be performed on.
+     *      Negative index is used to specify axis from the end (e.g. -1 for
+     *      the last axis). Must be in the range [-n, n).
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale must be 1.f / 256 and the zeroPoint must be 0.
+     */
+    SOFTMAX = @1.2::OperationType:SOFTMAX,
+
+    /**
+     * Rearranges blocks of spatial data, into depth.
+     *
+     * More specifically, this op outputs a copy of the input tensor where
+     * values from the height and width dimensions are moved to the depth
+     * dimension. The value block_size indicates the input block size and how
+     * the data is moved.
+     *
+     * Chunks of data of size block_size * block_size from depth are rearranged
+     * into non-overlapping blocks of size block_size x block_size.
+     *
+     * The depth of the output tensor is input_depth * block_size * block_size.
+     * The input tensor's height and width must be divisible by block_size.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the block_size.
+     *      block_size must be >=1 and block_size must be a divisor of both the
+     *      input height and width.
+     * * 2: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape [batches, height/block_size,
+     *      width/block_size, depth_in*block_size*block_size].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    SPACE_TO_DEPTH = @1.2::OperationType:SPACE_TO_DEPTH,
+
+    /**
+     * SVDF op is a kind of stateful layer derived from the notion that a
+     * densely connected layer that's processing a sequence of input frames can
+     * be approximated by using a singular value decomposition of each of its
+     * nodes. The implementation is based on:
+     *
+     * https://research.google.com/pubs/archive/43813.pdf
+     *
+     * P. Nakkiran, R. Alvarez, R. Prabhavalkar, C. Parada.
+     * “Compressing Deep Neural Networks using a Rank-Constrained Topology”.
+     * INTERSPEECH, 2015.
+     *
+     * It processes the incoming input using a 2-stage filtering mechanism:
+     * * stage 1 performs filtering on the "features" dimension, whose outputs
+     *   get pushed into a memory of fixed-size memory_size.
+     * * stage 2 performs filtering on the "time" dimension of the memory_size
+     *   memoized outputs of stage 1.
+     *
+     * Specifically, for rank 1, this layer implements the operation:
+     *
+     *     memory = push(conv1d(inputs, weights_feature, feature_dim,
+     *                          "PADDING_VALID"));
+     *     outputs = activation(memory * weights_time + bias);
+     *
+     * Where:
+     * * “weights_feature” is a weights matrix that processes the inputs (by
+     *   convolving the input with every “feature filter”), and whose outputs
+     *   get pushed, stacked in order, into the fixed-size “memory” (the oldest
+     *   entry gets dropped);
+     * * “weights_time” is a weights matrix that processes the “memory” (by a
+     *   batched matrix multiplication on the num_units);
+     * * “bias” is an optional bias vector (added to each output vector in the
+     *   batch); and
+     * * “activation” is the function passed as the “fused_activation_function”
+     *   argument (if not “NONE”).
+     *
+     * Each rank adds a dimension to the weights matrices by means of stacking
+     * the filters.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * All input tensors must be the same type.
+     *
+     * Inputs:
+     * * 0: input.
+     *      A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+     *      corresponds to the batching dimension, and “input_size” is the size
+     *      of the input.
+     * * 1: weights_feature.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of units.
+     * * 2: weights_time.
+     *      A 2-D tensor of shape [num_units, memory_size], where “memory_size”
+     *      corresponds to the fixed-size of the memory.
+     * * 3: bias.
+     *      An optional 1-D tensor of shape [num_units].
+     * * 4: state (in).
+     *      A 2-D tensor of shape [batch_size, (memory_size - 1) * num_units * rank].
+     * * 5: rank.
+     *      The rank of the SVD approximation.
+     * * 6: fused_activation_function.
+     *      An optional {@link FusedActivationFunc} value indicating the
+     *      activation function. If “NONE” is specified then it results in a
+     *      linear activation.
+     *
+     * Outputs:
+     * * 0: state (out).
+     *      A 2-D tensor of the same {@link OperandType} as the inputs, with shape
+     *      [batch_size, (memory_size - 1) * num_units * rank].
+     * * 1: output.
+     *      A 2-D tensor of the same {@link OperandType} as the inputs, with shape
+     *      [batch_size, num_units].
+     */
+    SVDF = @1.2::OperationType:SVDF,
+
+    /**
+     * Computes hyperbolic tangent of input tensor element-wise.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = tanh(input)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale must be 1.f / 128 and the zeroPoint must be 128.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      the scale must be 1.f / 128 and the zeroPoint must be 0.
+     */
+    TANH = @1.2::OperationType:TANH,
+
+    /**
+     * BatchToSpace for N-dimensional tensors.
+     *
+     * This operation reshapes the batch dimension (dimension 0) into M + 1
+     * dimensions of shape block_shape + [batch], interleaves these blocks back
+     * into the grid defined by the spatial dimensions [1, ..., M], to obtain a
+     * result with the same rank as the input.
+     *
+     * This is the reverse of SpaceToBatch.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be reshaped
+     * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the block
+     *      sizes for each spatial dimension of the input tensor. All values
+     *      must be >= 1.
+     * * 2: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since API level 29.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    BATCH_TO_SPACE_ND = @1.2::OperationType:BATCH_TO_SPACE_ND,
+
+    /**
+     * Element-wise division of two tensors.
+     *
+     * Takes two input tensors of identical {@link OperandType} and compatible
+     * dimensions. The output is the result of dividing the first input tensor
+     * by the second, optionally modified by an activation function.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the output is the maximum size along each dimension of the
+     * input operands. It starts with the trailing dimensions, and works its way
+     * forward.
+     *
+     * Example:
+     *     input1.dimension =    {4, 1, 2}
+     *     input2.dimension = {5, 4, 3, 1}
+     *     output.dimension = {5, 4, 3, 2}
+     *
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the first input.
+     * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+     *      as input0.
+     * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     */
+    DIV = @1.2::OperationType:DIV,
+
+    /**
+     * Computes the mean of elements across dimensions of a tensor.
+     *
+     * Reduces the input tensor along the given dimensions to reduce. Unless
+     * keep_dims is true, the rank of the tensor is reduced by 1 for each entry
+     * in axis. If keep_dims is true, the reduced dimensions are retained with
+     * length 1.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Must be in the range
+     *      [-rank(input_tensor), rank(input_tensor)).
+     *
+     *      NOTE: When the operation was introduced, the documentation
+     *      incorrectly stated that if dimensions were empty, the operation
+     *      would reduce across all dimensions. This behavior was never
+     *      implemented.
+     *
+     * * 2: An {@link OperandType::INT32} scalar, keep_dims. If positive,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    MEAN = @1.2::OperationType:MEAN,
+
+    /**
+     * Pads a tensor.
+     *
+     * This operation pads a tensor according to the specified paddings.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (full support since HAL version 1.2, see the output section)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be padded.
+     * * 1: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings
+     *      for each spatial dimension of the input tensor. The shape of the
+     *      tensor must be {rank(input0), 2}.
+     *      padding[i, 0] specifies the number of elements to be padded in the
+     *      front of dimension i.
+     *      padding[i, 1] specifies the number of elements to be padded after the
+     *      end of dimension i.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0. The
+     *      output tensor has the same rank as input0, and each
+     *      dimension of the output tensor has the same size as the
+     *      corresponding dimension of the input tensor plus the size
+     *      of the padding:
+     *          output0.dimension[i] =
+     *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     *
+     *      NOTE: Before HAL version 1.2, the pad value for
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} is undefined.
+     *      Since HAL version 1.2, the pad value is always the logical zero.
+     */
+    PAD = @1.2::OperationType:PAD,
+
+    /**
+     * SpaceToBatch for N-Dimensional tensors.
+     *
+     * This operation divides "spatial" dimensions [1, ..., M] of the input into
+     * a grid of blocks of shape block_shape, and interleaves these blocks with
+     * the "batch" dimension (0) such that in the output, the spatial dimensions
+     * [1, ..., M] correspond to the position within the grid, and the batch
+     * dimension combines both the position within a spatial block and the
+     * original batch position. Prior to division into blocks, the spatial
+     * dimensions of the input are optionally zero padded according to paddings.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (full support since HAL version 1.2, see the output section)
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the input.
+     * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the block
+     *      sizes for each spatial dimension of the input tensor. All values
+     *      must be >= 1.
+     * * 2: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings
+     *      for each spatial dimension of the input tensor. All values must be
+     *      >= 0. The shape of the tensor must be {M, 2}, where M is the number
+     *      of spatial dimensions.
+     *      padding[i, 0] specifies the number of element to be padded in the
+     *      front of dimension i.
+     *      padding[i, 1] specifies the number of element to be padded after the
+     *      end of dimension i.
+     * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     *
+     *      NOTE: Before HAL version 1.2, the pad value for
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} is undefined.
+     *      Since HAL version 1.2, the pad value is always the logical zero.
+     */
+    SPACE_TO_BATCH_ND = @1.2::OperationType:SPACE_TO_BATCH_ND,
+
+    /**
+     * Removes dimensions of size 1 from the shape of a tensor.
+     *
+     * Given a tensor input, this operation returns a tensor of the same
+     * {@link OperandType} with all dimensions of size 1 removed. If you don't
+     * want to remove all size 1 dimensions, you can remove specific size 1
+     * dimensions by specifying the axes (input1).
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, the tensor to be squeezed.
+     * * 1: An optional 1-D tensor of {@link OperandType::TENSOR_INT32}. The
+     *      dimensions to squeeze. If specified only squeezes the dimensions
+     *      listed. Otherwise, squeezes all dimensions. The dimension index
+     *      starts at 0. An error must be reported if squeezing a dimension that
+     *      is not 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0. Contains the
+     *      same data as input, but has one or more dimensions of size 1
+     *      removed.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    SQUEEZE = @1.2::OperationType:SQUEEZE,
+
+    /**
+     * Extracts a strided slice of a tensor.
+     *
+     * Roughly speaking, this op extracts a slice of size (end - begin) / stride
+     * from the given input tensor. Starting at the location specified by begin
+     * the slice continues by adding stride to the index until all dimensions
+     * are not less than end. Note that a stride can be negative, which causes a
+     * reverse slice.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be sliced.
+     * * 1: begin, a 1-D tensor of {@link OperandType::TENSOR_INT32}. The
+     *      starts of the dimensions of the input tensor to be sliced. The
+     *      length must be of rank(input0).
+     * * 2: end, a 1-D tensor of {@link OperandType::TENSOR_INT32}. The
+     *      ends of the dimensions of the input tensor to be sliced. The length
+     *      must be of rank(input0).
+     * * 3: strides, a 1-D tensor of {@link OperandType::TENSOR_INT32}. The
+     *      strides of the dimensions of the input tensor to be sliced. The
+     *      length must be of rank(input0). The entries must be non-zero.
+     * * 4: begin_mask, an {@link OperandType::INT32} scalar. If the ith bit
+     *      of begin_mask is set, begin[i] is ignored and the fullest possible
+     *      range in that dimension is used instead.
+     * * 5: end_mask, an {@link OperandType::INT32} scalar. If the ith bit of
+     *      end_mask is set, end[i] is ignored and the fullest possible range in
+     *      that dimension is used instead.
+     * * 6: shrink_axis_mask, an {@link OperandType::INT32} scalar. If the
+     *      ith bit of shrink_axis_mask is set, the ith dimension specification
+     *      shrinks the dimensionality by 1, taking on the value at index
+     *      begin[i]. In this case, the ith specification must define a
+     *      slice of size 1, e.g. begin[i] = x, end[i] = x + 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0 and rank (n - k),
+     *      where k is the number of bits set in shrink_axis_mask.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    STRIDED_SLICE = @1.2::OperationType:STRIDED_SLICE,
+
+    /**
+     * Element-wise subtraction of two tensors.
+     *
+     * Takes two input tensors of identical {@link OperandType} and compatible
+     * dimensions. The output is the result of subtracting the second input
+     * tensor from the first one, optionally modified by an activation function.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the output is the maximum size along each dimension of the
+     * input operands. It starts with the trailing dimensions, and works its way
+     * forward.
+     *
+     * Example:
+     *     input1.dimension =    {4, 1, 2}
+     *     input2.dimension = {5, 4, 3, 1}
+     *     output.dimension = {5, 4, 3, 2}
+     *
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the first input.
+     * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+     *      as input0.
+     * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    SUB = @1.2::OperationType:SUB,
+
+    /**
+     * Transposes the input tensor, permuting the dimensions according to the
+     * perm tensor.
+     *
+     * The returned tensor's dimension i corresponds to the input dimension
+     * perm[i]. If perm is not given, it is set to (n-1...0), where n is the
+     * rank of the input tensor. Hence by default, this operation performs a
+     * regular matrix transpose on 2-D input Tensors.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be transposed.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     * * 1: An optional 1-D Tensor of {@link OperandType::TENSOR_INT32},
+     *      the permutation of the dimensions of the input tensor.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    TRANSPOSE = @1.2::OperationType:TRANSPOSE,
+
+    /**
+     * Computes the absolute value of a tensor, element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    ABS = @1.2::OperationType:ABS,
+
+    /**
+     * Returns the index of the largest element along an axis.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor specifying the input. Must be non-empty.
+     * * 1: An {@link OperandType::INT32} scalar specifying the axis to
+     *      reduce across. Negative index is used to specify axis from the
+     *      end (e.g. -1 for the last axis). Must be in the range [-n, n).
+     *
+     * Outputs:
+     * * 0: An (n - 1)-D {@link OperandType::TENSOR_INT32} tensor.
+     */
+    // There is no underscore in ARG_MAX to avoid name conflict with
+    // the macro defined in libc/kernel/uapi/linux/limits.h.
+    ARGMAX = @1.2::OperationType:ARGMAX,
+
+    /**
+     * Returns the index of the smallest element along an axis.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor specifying the input. Must be non-empty.
+     * * 1: An {@link OperandType::INT32} scalar specifying the axis to
+     *      reduce across. Negative index is used to specify axis from the
+     *      end (e.g. -1 for the last axis). Must be in the range [-n, n).
+     *
+     * Outputs:
+     * * 0: An (n - 1)-D {@link OperandType::TENSOR_INT32} tensor.
+     */
+    ARGMIN = @1.2::OperationType:ARGMIN,  // See ARGMAX for naming discussion.
+
+    /**
+     * Transform axis-aligned bounding box proposals using bounding box deltas.
+     *
+     * Given the positions of bounding box proposals and the corresponding
+     * bounding box deltas for each class, return the refined bounding box
+     * regions. The resulting bounding boxes are cliped against the edges of
+     * the image.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT16_ASYMM}
+     *
+     * Inputs:
+     * * 0: A 2-D Tensor of shape [num_rois, 4], specifying the locations of the
+     *      bounding box proposals, each line with format [x1, y1, x2, y2].
+     *      For tensor of type {@link OperandType::TENSOR_QUANT16_ASYMM},
+     *      the zeroPoint must be 0 and the scale must be 0.125. Zero num_rois
+     *      is supported for this tensor.
+     * * 1: A 2-D Tensor of shape [num_rois, num_classes * 4], specifying the
+     *      bounding box delta for each region of interest and each class. The
+     *      bounding box deltas are organized in the following order
+     *      [dx, dy, dw, dh], where dx and dy is the relative correction factor
+     *      for the center position of the bounding box with respect to the width
+     *      and height, dw and dh is the log-scale relative correction factor
+     *      for the width and height. For input0 of type
+     *      {@link OperandType::TENSOR_QUANT16_ASYMM}, this tensor should be
+     *      of {@link OperandType::TENSOR_QUANT8_ASYMM}. Zero num_rois is
+     *      supported for this tensor.
+     * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_rois], specifying the batch index of each box. Boxes with
+     *      the same batch index are grouped together. Zero num_rois is
+     *      supported for this tensor.
+     * * 3: A 2-D Tensor of shape [batches, 2], specifying the information of
+     *      each image in the batch, each line with format
+     *      [image_height, image_width].
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0, with shape
+     *      [num_rois, num_classes * 4], specifying the coordinates of each
+     *      output bounding box for each class, with format [x1, y1, x2, y2].
+     *      For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the
+     *      scale must be 0.125 and the zero point must be 0.
+     */
+    AXIS_ALIGNED_BBOX_TRANSFORM = @1.2::OperationType:AXIS_ALIGNED_BBOX_TRANSFORM,
+
+    /**
+     * Performs a forward LSTM on the input followed by a backward LSTM.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: 3, either time-major or batch-major.
+     *
+     * All input and output tensors must be of the same type.
+     *
+     *
+     * Inputs:
+     * * 0: The input.
+     *      A 3-D tensor of shape:
+     *        If time-major: [max_time, batch_size, input_size]
+     *        If batch-major: [batch_size, max_time, input_size]
+     *      where "max_time" is the number of timesteps (sequence length),
+     *      "batch_size" corresponds to the batching dimension, and
+     *      "input_size" is the size of the input.
+     * * 1: The forward input-to-input weights. Optional.
+     *      A 2-D tensor of shape [fw_num_units, input_size], where “fw_num_units”
+     *      corresponds to the number of forward cell units.
+     * * 2: The forward input-to-forget weights.
+     *      A 2-D tensor of shape [fw_num_units, input_size].
+     * * 3: The forward input-to-cell weights.
+     *      A 2-D tensor of shape [fw_num_units, input_size].
+     * * 4: The forward input-to-output weights.
+     *      A 2-D tensor of shape [fw_num_units, input_size].
+     * * 5: The forward recurrent-to-input weights. Optional.
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size], where “fw_output_size”
+     *      corresponds to either the number of cell units (i.e., fw_num_units),
+     *      or the second dimension of the “fw_projection_weights”, if defined.
+     * * 6: The forward recurrent-to-forget weights.
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size].
+     * * 7: The forward recurrent-to-cell weights.
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size].
+     * * 8: The forward recurrent-to-output weights.
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size].
+     * * 9: The forward cell-to-input weights. Optional.
+     *      A 1-D tensor of shape [fw_num_units].
+     * * 10: The forward cell-to-forget weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 11: The forward cell-to-output weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 12: The forward input gate bias. Optional.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 13: The forward forget gate bias.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 14: The forward cell gate bias.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 15: The forward output gate bias.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 16: The forward projection weights. Optional.
+     *       A 2-D tensor of shape [fw_output_size, fw_num_units].
+     * * 17: The forward projection bias. Optional.
+     *       A 1-D tensor of shape [fw_output_size].
+     * * 18: The backward input-to-input weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, input_size], where “bw_num_units”
+     *       corresponds to the number of backward cell units.
+     * * 19: The backward input-to-forget weights.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 20: The backward input-to-cell weights.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 21: The backward input-to-output weights.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 22: The backward recurrent-to-input weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size], where “bw_output_size”
+     *       corresponds to either the number of cell units (i.e., “bw_num_units”),
+     *       or the second dimension of the “bw_projection_weights”, if defined.
+     * * 23: The backward recurrent-to-forget weights.
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size].
+     * * 24: The backward recurrent-to-cell weights.
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size].
+     * * 25: The backward recurrent-to-output weights.
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size].
+     * * 26: The backward cell-to-input weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 27: The backward cell-to-forget weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 28: The backward cell-to-output weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 29: The backward input gate bias. Optional.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 30: The backward forget gate bias.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 31: The backward cell gate bias.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 32: The backward output gate bias.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 33: The backward projection weights. Optional.
+     *       A 2-D tensor of shape [bw_output_size, bw_num_units].
+     * * 34: The backward projection bias. Optional.
+     *       A 1-D tensor of shape [bw_output_size].
+     * * 35: The forward input activation state.
+     *       A 2-D tensor of shape [batch_size, bw_output_size].
+     * * 36: The forward input cell state.
+     *       A 2-D tensor of shape [batch_size, bw_num_units].
+     * * 37: The backward input activation state.
+     *       A 2-D tensor of shape [batch_size, bw_output_size].
+     * * 38: The backward input cell state.
+     *       A 2-D tensor of shape [batch_size, bw_num_units].
+     * * 39: The auxiliary input. Optional.
+     *       A 3-D tensor of shape [max_time, batch_size, input_size], where “batch_size”
+     *       corresponds to the batching dimension, and “input_size” is the size
+     *       of the input.
+     * * 40: The forward auxiliary input-to-input weights. Optional.
+     *       A 2-D tensor of shape [fw_num_units, input_size].
+     * * 41: The forward auxiliary input-to-forget weights. Optional.
+     *       A 2-D tensor of shape [fw_num_units, input_size].
+     * * 42: The forward auxiliary input-to-cell weights. Optional.
+     *       A 2-D tensor of shape [fw_num_units, input_size].
+     * * 43: The forward auxiliary input-to-output weights. Optional.
+     *       A 2-D tensor of shape [fw_num_units, input_size].
+     * * 44: The backward auxiliary input-to-input weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 45: The backward auxiliary input-to-forget weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 46: The backward auxiliary input-to-cell weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 47: The backward auxiliary input-to-output weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 48: The activation function.
+     *       A value indicating the activation function:
+     *       <ul>
+     *       <li>0: None;
+     *       <li>1: Relu;
+     *       <li>3: Relu6;
+     *       <li>4: Tanh;
+     *       <li>6: Sigmoid.
+     *       </ul>
+     * * 49: The clipping threshold for the cell state, such
+     *       that values are bound within [-cell_clip, cell_clip]. If set to 0.0
+     *       then clipping is disabled.
+     *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
+     *       this scalar must be of the type {@link OperandType::FLOAT32},
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
+     * * 50: The clipping threshold for the output from the
+     *       projection layer, such that values are bound within
+     *       [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
+     *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
+     *       this scalar must be of the type {@link OperandType::FLOAT32},
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
+     * * 51: merge_outputs
+     *       An {@link OperandType::BOOL} scalar specifying if the outputs
+     *       from forward and backward cells should be merged.
+     * * 52: time_major
+     *       An {@link OperandType::BOOL} scalar specifying the shape format
+     *       of input and output tensors.
+     * * 53: The forward input layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at input gate.
+     * * 54: The forward forget layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at forget gate.
+     * * 55: The forward cell layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at cell gate.
+     * * 56: The forward output layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at output gate.
+     * * 57: The backward input layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at input gate.
+     * * 58: The backward forget layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at forget gate.
+     * * 59: The backward cell layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at cell gate.
+     * * 60: The backward output layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at output gate.
+     *
+     * Outputs:
+     * * 0: The forward output.
+     *      A 3-D tensor of shape:
+     *        If time-major and not merge_outputs:
+     *          [max_time, batch_size, fw_output_size]
+     *        If time-major and merge_outputs:
+     *          [max_time, batch_size, fw_output_size + bw_output_size]
+     *        If batch-major and not merge_outputs:
+     *          [batch_size, max_time, fw_output_size]
+     *        If batch-major and merge_outputs:
+     *          [batch_size, max_time, fw_output_size + bw_output_size]
+     * * 1: The backward output.  Unused if merge_outputs is true.
+     *      A 3-D tensor of shape:
+     *        If time-major: [max_time, batch_size, bw_output_size]
+     *        If batch-major: [batch_size, max_time, bw_output_size]
+     */
+    BIDIRECTIONAL_SEQUENCE_LSTM = @1.2::OperationType:BIDIRECTIONAL_SEQUENCE_LSTM,
+
+    /**
+     * A recurrent neural network layer that applies a basic RNN cell to a
+     * sequence of inputs in forward and backward directions.
+     *
+     * This Op unrolls the input along the sequence dimension, and implements
+     * the following operation for each element in the sequence s =
+     * 1...sequence_length:
+     *   fw_outputs[s] = fw_state = activation(inputs[s] * fw_input_weights’ +
+     *          fw_state * fw_recurrent_weights’ + fw_bias)
+     *
+     * And for each element in sequence t = sequence_length : 1
+     *   bw_outputs[t] = bw_state = activation(inputs[t] * bw_input_weights’ +
+     *          bw_state * bw_recurrent_weights’ + bw_bias)
+     *
+     * Where:
+     * * “{fw,bw}_input_weights” is a weight matrix that multiplies the inputs;
+     * * “{fw,bw}_recurrent_weights” is a weight matrix that multiplies the
+     *    current “state” which itself is the output from the previous time step
+     *    computation;
+     * * “{fw,bw}_bias” is a bias vector (added to each output vector in the
+     *    batch);
+     * * “activation” is the function passed as the “fused_activation_function”
+     *   argument (if not “NONE”).
+     *
+     * The op also supports an auxiliary input. Regular cell feeds one input
+     * into the two RNN cells in the following way:
+     *
+     *       INPUT  (INPUT_REVERSED)
+     *         |         |
+     *    ---------------------
+     *    | FW_RNN     BW_RNN |
+     *    ---------------------
+     *         |         |
+     *      FW_OUT     BW_OUT
+     *
+     * An op with an auxiliary input takes two inputs and feeds them into the
+     * RNN cells in the following way:
+     *
+     *       AUX_INPUT   (AUX_INPUT_REVERSED)
+     *           |             |
+     *     INPUT | (INPUT_R'D.)|
+     *       |   |       |     |
+     *    -----------------------
+     *    |  \  /        \    / |
+     *    | FW_RNN       BW_RNN |
+     *    -----------------------
+     *         |           |
+     *      FW_OUT      BW_OUT
+     *
+     * While stacking this op on top of itself, this allows to connect both
+     * forward and backward outputs from previous cell to the next cell's
+     * inputs.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * The input tensors must all be the same type.
+     *
+     * Inputs:
+     * * 0: input.
+     *      A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+     *      it is set to true, then the input has a shape [maxTime, batchSize,
+     *      inputSize], otherwise the input has a shape [batchSize, maxTime,
+     *      inputSize].
+     * * 1: fwWeights.
+     *      A 2-D tensor of shape [fwNumUnits, inputSize].
+     * * 2: fwRecurrentWeights.
+     *      A 2-D tensor of shape [fwNumUnits, fwNumUnits].
+     * * 3: fwBias.
+     *      A 1-D tensor of shape [fwNumUnits].
+     * * 4: fwHiddenState.
+     *      A 2-D tensor of shape [batchSize, fwNumUnits]. Specifies a hidden
+     *      state input for the first time step of the computation.
+     * * 5: bwWeights.
+     *      A 2-D tensor of shape [bwNumUnits, inputSize].
+     * * 6: bwRecurrentWeights.
+     *      A 2-D tensor of shape [bwNumUnits, bwNumUnits].
+     * * 7: bwBias.
+     *      A 1-D tensor of shape [bwNumUnits].
+     * * 8: bwHiddenState
+     *      A 2-D tensor of shape [batchSize, bwNumUnits]. Specifies a hidden
+     *      state input for the first time step of the computation.
+     * * 9: auxInput.
+     *      A 3-D tensor. The shape is the same as of the input 0.
+     * * 10:fwAuxWeights.
+     *      A 2-D tensor of shape [fwNumUnits, inputSize].
+     * * 11:bwAuxWeights.
+     *      A 2-D tensor of shape [bwNumUnits, inputSize].
+     * * 12:fusedActivationFunction.
+     *      A {@link FusedActivationFunc} value indicating the activation function. If
+     *      “NONE” is specified then it results in a linear activation.
+     * * 13:timeMajor
+     *      An {@link OperandType::BOOL} scalar specifying the shape format
+     *      of input and output tensors.
+     * * 14:mergeOutputs
+     *      An {@link OperandType::BOOL} scalar specifying if the outputs
+     *      from forward and backward cells are separate (if set to false) or
+     *      concatenated (if set to true).
+     * Outputs:
+     * * 0: fwOutput.
+     *      A 3-D tensor. The first two dimensions of the shape are defined by
+     *      the input 6 (timeMajor) and the third dimension is defined by the
+     *      input 14 (mergeOutputs). If timeMajor is set to true, then the first
+     *      two dimensions are [maxTime, batchSize], otherwise they are set to
+     *      [batchSize, maxTime]. If mergeOutputs is set to true, then the third
+     *      dimension is equal to (fwNumUnits + bwNumUnits), otherwise it is set
+     *      to fwNumUnits.
+     * * 1: bwOutput.
+     *      A 3-D tensor. If the input 14 (mergeOutputs) is set to true, then
+     *      this tensor is not produced. The shape is defined by the input 6
+     *      (timeMajor). If it is set to true, then the shape is set to
+     *      [maxTime, batchSize, bwNumUnits], otherwise the shape is set to
+     *      [batchSize, maxTime, bwNumUnits].
+     */
+    BIDIRECTIONAL_SEQUENCE_RNN = @1.2::OperationType:BIDIRECTIONAL_SEQUENCE_RNN,
+
+    /**
+     * Greedily selects a subset of bounding boxes in descending order of score.
+     *
+     * This op applies NMS algorithm to each class. In each loop of execution,
+     * the box with maximum score gets selected and removed from the pending set.
+     * The scores of the rest of boxes are lowered according to the
+     * intersection-over-union (IOU) overlapping with the previously selected
+     * boxes and a specified NMS kernel method. Any boxes with score less
+     * than a threshold are removed from the pending set.
+     *
+     * Three NMS kernels are supported:
+     * * Hard:     score_new = score_old * (1 if IoU < threshold else 0)
+     * * Linear:   score_new = score_old * (1 if IoU < threshold else 1 - IoU)
+     * * Gaussian: score_new = score_old * exp(- IoU^2 / sigma)
+     *
+     * Axis-aligned bounding boxes are represented by its upper-left corner
+     * coordinate (x1,y1) and lower-right corner coordinate (x2,y2). A valid
+     * bounding box should satisfy x1 <= x2 and y1 <= y2.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Inputs:
+     * * 0: A 2-D Tensor of shape [num_rois, num_classes], specifying the score
+     *      of each bounding box proposal. The boxes are grouped by batches in the
+     *      first dimension. Zero num_rois is supported for this tensor.
+     * * 1: A 2-D Tensor specifying the bounding boxes of shape
+     *      [num_rois, num_classes * 4], organized in the order [x1, y1, x2, y2].
+     *      The boxes are grouped by batches in the first dimension. The sequential
+     *      order of the boxes corresponds with input0. For input0 of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of
+     *      {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint of 0 and
+     *      scale of 0.125. Zero num_rois is supported for this tensor.
+     * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_rois], specifying the batch index of each box. Boxes with
+     *      the same batch index are grouped together.
+     * * 3: An {@link OperandType::FLOAT32} scalar, score_threshold. Boxes
+     *      with scores lower than the threshold are filtered before sending
+     *      to the NMS algorithm.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the maximum
+     *      number of selected bounding boxes for each image. Set to a negative
+     *      value for unlimited number of output bounding boxes.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the NMS
+     *      kernel method, options are 0:hard, 1:linear, 2:gaussian.
+     * * 6: An {@link OperandType::FLOAT32} scalar, specifying the IoU
+     *      threshold in hard and linear NMS kernel. This field is ignored if
+     *      gaussian kernel is selected.
+     * * 7: An {@link OperandType::FLOAT32} scalar, specifying the sigma in
+     *      gaussian NMS kernel. This field is ignored if gaussian kernel is
+     *      not selected.
+     * * 8: An {@link OperandType::FLOAT32} scalar, nms_score_threshold.
+     *      Boxes with scores lower than the threshold are dropped during the
+     *      score updating phase in soft NMS.
+     *
+     * Outputs:
+     * * 0: A 1-D Tensor of the same {@link OperandType} as input0, with shape
+     *      [num_output_rois], specifying the score of each output box. The boxes
+     *      are grouped by batches, but the sequential order in each batch is not
+     *      guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale and zero point must be the same as input0.
+     * * 1: A 2-D Tensor of the same {@link OperandType} as input1, with shape
+     *      [num_output_rois, 4], specifying the coordinates of each
+     *      output bounding box with the same format as input1. The sequential
+     *      order of the boxes corresponds with output0. For type of
+     *      {@link OperandType::TENSOR_QUANT16_ASYMM}, the scale must be
+     *      0.125 and the zero point must be 0.
+     * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_output_rois], specifying the class of each output box. The
+     *      sequential order of the boxes corresponds with output0.
+     * * 3: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_output_rois], specifying the batch index of each box. Boxes
+     *      with the same batch index are grouped together.
+     */
+    BOX_WITH_NMS_LIMIT = @1.2::OperationType:BOX_WITH_NMS_LIMIT,
+
+    /**
+     * Casts a tensor to a new type.
+     *
+     * This operation ignores the scale and zeroPoint of quanized tensors,
+     * e.g. it treats a {@link OperandType::TENSOR_QUANT8_ASYMM} input
+     * as a tensor of uint8 values.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: A tensor with the same shape as input0.
+     */
+    CAST = @1.2::OperationType:CAST,
+
+    /**
+     * Shuffle the channels of the input tensor.
+     *
+     * Given an input tensor and a integer value of num_groups, CHANNEL_SHUFFLE
+     * divide the channel dimension into num_groups groups, and reorganize the
+     * channels by grouping channels with the same index in each group.
+     *
+     * Along the channel dimension, the output is calculated using this formula:
+     *
+     *     output_channel[k * num_groups + g] = input_channel[g * group_size + k]
+     *
+     * where group_size = num_channels / num_groups
+     *
+     * The number of channels must be divisible by num_groups.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be shuffled.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the number of
+     *      groups.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the dimension
+     *      channel shuffle would be performed on. Negative index is used to
+     *      specify axis from the end (e.g. -1 for the last axis). Must be in
+     *      the range [-n, n).
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} and same shape as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    CHANNEL_SHUFFLE = @1.2::OperationType:CHANNEL_SHUFFLE,
+
+    /**
+     * Apply postprocessing steps to bounding box detections.
+     *
+     * Bounding box detections are generated by applying transformation on a set
+     * of predefined anchors with the bounding box deltas from bounding box
+     * regression. A final step of hard NMS is applied to limit the number of
+     * returned boxes.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Inputs:
+     * * 0: A 3-D Tensor of shape [batches, num_anchors, num_classes], specifying
+     *      the score of each anchor with each class. Class 0 for each
+     *      [batches, num_anchors, 0] is background and will be ignored.
+     * * 1: A 3-D Tensor of shape [batches, num_anchors, length_box_encoding], with
+     *      the first four values in length_box_encoding specifying the bounding
+     *      box deltas. The box deltas are encoded in the order of [dy, dx, dh, dw],
+     *      where dy and dx is the linear-scale relative correction factor for the
+     *      center position of the bounding box with respect to the width and height,
+     *      dh and dw is the log-scale relative correction factor for the width and
+     *      height. All the entries in length_box_encoding beyond the first four
+     *      values are ignored in this operation.
+     * * 2: A 2-D Tensor of shape [num_anchors, 4], specifying the shape of each
+     *      predefined anchor, with format [ctr_y, ctr_x, h, w], where ctr_y and
+     *      ctr_x are the center position of the box, and h and w are the height
+     *      and the width.
+     * * 3: An {@link OperandType::FLOAT32} scalar, specifying the scaling
+     *      factor for dy in bounding box deltas.
+     * * 4: An {@link OperandType::FLOAT32} scalar, specifying the scaling
+     *      factor for dx in bounding box deltas.
+     * * 5: An {@link OperandType::FLOAT32} scalar, specifying the scaling
+     *      factor for dh in bounding box deltas.
+     * * 6: An {@link OperandType::FLOAT32} scalar, specifying the scaling
+     *      factor for dw in bounding box deltas.
+     * * 7: An {@link OperandType::BOOL} scalar, set to true to use regular
+     *      multi-class NMS algorithm that do NMS separately for each class,
+     *      set to false for a faster algorithm that only do one single NMS
+     *      using the highest class score..
+     * * 8: An {@link OperandType::INT32} scalar, max_num_detections, specifying
+     *      the maximum number of boxes for the output. Boxes with the lowest
+     *      scores are discarded to meet the limit.
+     * * 9: An {@link OperandType::INT32} scalar, only used when input7 is
+     *      set to false, specifying the maximum number of classes per detection.
+     * * 10: An {@link OperandType::INT32} scalar, only used when input7 is
+     *       set to true, specifying the maximum number of detections when
+     *       applying NMS algorithm for each single class.
+     * * 11: A scalar, score_threshold. Boxes with scores lower than the
+     *       threshold are filtered before sending to the NMS algorithm. The
+     *       scalar must be of {@link OperandType::FLOAT16} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT16} and of
+     *       {@link OperandType::FLOAT32} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT32}.
+     * * 12: A scalar, specifying the IoU threshold for hard NMS. The scalar
+     *       must be of {@link OperandType::FLOAT16} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT16} and of
+     *       {@link OperandType::FLOAT32} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT32}.
+     * * 13: An {@link OperandType::BOOL} scalar, set to true to include
+     *       background class in the list of label map for the output, set
+     *       to false to not include the background. When the background
+     *       class is included, it has label 0 and the output classes start
+     *       at 1 in the label map, otherwise, the output classes start at 0.
+     *
+     * Outputs:
+     * * 0: A 2-D tensor of the same {@link OperandType} as input0, with shape
+     *      [batches, max_num_detections], specifying the score of each output
+     *      detections.
+     * * 1: A 3-D tensor of shape [batches, max_num_detections, 4], specifying the
+     *      coordinates of each output bounding box, with format
+     *      [y1, x1, y2, x2].
+     * * 2: A 2-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [batches, max_num_detections], specifying the class label for each
+     *      output detection.
+     * * 3: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape [batches],
+     *      specifying the number of valid output detections for each batch.
+     */
+    DETECTION_POSTPROCESSING = @1.2::OperationType:DETECTION_POSTPROCESSING,
+
+    /**
+     * For input tensors x and y, computes x == y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    EQUAL = @1.2::OperationType:EQUAL,
+
+    /**
+     * Computes exponential of x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    EXP = @1.2::OperationType:EXP,
+
+    /**
+     * Inserts a dimension of 1 into a tensor's shape.
+     *
+     * Given a tensor input, this operation inserts a dimension of 1 at the
+     * given dimension index of input's shape. The dimension index starts at
+     * zero; if you specify a negative dimension index, it is counted backward
+     * from the end.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: An {@link OperandType::INT32} scalar specifying the dimension
+     *      index to expand. Must be in the range [-(n + 1), (n + 1)).
+     *
+     * Outputs:
+     * * 0: An (n + 1)-D tensor with the same {@link OperandType} and data as
+     *      input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    EXPAND_DIMS = @1.2::OperationType:EXPAND_DIMS,
+
+    /**
+     * Gathers values along an axis.
+     *
+     * Produces an output tensor with shape
+     *     input0.dimension[:axis] + indices.dimension + input0.dimension[axis + 1:]
+     * where:
+     *     # Vector indices (output is rank(input0)).
+     *     output[a_0, ..., a_n, i, b_0, ..., b_n] =
+     *       input0[a_0, ..., a_n, indices[i], b_0, ..., b_n]
+     *
+     *     # Higher rank indices (output is rank(input0) + rank(indices) - 1).
+     *     output[a_0, ..., a_n, i, ..., j, b_0, ... b_n] =
+     *       input0[a_0, ..., a_n, indices[i, ..., j], b_0, ..., b_n]
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor from which to gather values.
+     * * 1: An {@link OperandType::INT32} scalar specifying the axis.
+     *      Negative index is used to specify axis from the end
+     *      (e.g. -1 for the last axis). Must be in the range [-n, n).
+     * * 2: A k-D tensor {@link OperandType::TENSOR_INT32} of indices.
+     *      The values must be in the bounds of the corresponding dimensions
+     *      of input0.
+     *
+     * Outputs:
+     * * 0: An (n + k - 1)-D tensor with the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    GATHER = @1.2::OperationType:GATHER,
+
+    /**
+     * Generate aixs-aligned bounding box proposals.
+     *
+     * Bounding box proposals are generated by applying transformation on a set
+     * of predefined anchors with the bounding box deltas from bounding box
+     * regression. A final step of hard NMS is applied to limit the number of
+     * returned boxes.
+     *
+     * Axis-aligned bounding boxes are represented by its upper-left corner
+     * coordinate (x1,y1) and lower-right corner coordinate (x2,y2). A valid
+     * bounding box should satisfy x1 <= x2 and y1 <= y2.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Inputs:
+     * * 0: A 4-D Tensor specifying the score of each anchor at each
+     *      location. With "NHWC" data layout, the tensor shape is
+     *      [batches, height, width, num_anchors]. With "NCHW" data layout,
+     *      the tensor shape is [batches, num_anchors, height, width].
+     * * 1: A 4-D Tensor specifying the bounding box deltas. With "NHWC" data
+     *      layout, the tensor shape is [batches, height, width, num_anchors * 4].
+     *      With "NCHW" data layout, the tensor shape is
+     *      [batches, num_anchors * 4, height, width]. The box deltas are encoded
+     *      in the order of [dx, dy, dw, dh], where dx and dy is the linear-scale
+     *      relative correction factor for the center position of the bounding box
+     *      with respect to the width and height, dw and dh is the log-scale
+     *      relative correction factor for the width and height. The last
+     *      dimensions is the channel dimension.
+     * * 2: A 2-D Tensor of shape [num_anchors, 4], specifying the shape of each
+     *      predefined anchor, with format [x1, y1, x2, y2]. For input0 of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of
+     *      {@link OperandType::TENSOR_QUANT16_SYMM}, with scale of 0.125.
+     * * 3: A 2-D Tensor of shape [batches, 2], specifying the size of
+     *      each image in the batch, with format [image_height, image_width].
+     *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM}, this
+     *      tensor should be of {@link OperandType::TENSOR_QUANT16_SYMM}, with
+     *      scale of 0.125.
+     * * 4: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the height of original image to the height of feature map.
+     * * 5: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the width of original image to the width of feature map.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the maximum
+     *      number of boxes before going into the hard NMS algorithm. Boxes
+     *      with the lowest scores are discarded to meet the limit. Set to
+     *      a non-positive value for unlimited number.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the maximum
+     *      number of boxes returning from the hard NMS algorithm. Boxes
+     *      with the lowest scores are discarded to meet the limit. Set to
+     *      a non-positive value for unlimited number.
+     * * 8: An {@link OperandType::FLOAT32} scalar, specifying the IoU
+     *      threshold for hard NMS.
+     * * 9: An {@link OperandType::FLOAT32} scalar, min_size. Boxes with
+     *      height or width lower than the absolute threshold are filtered out.
+     * * 10: An {@link OperandType::BOOL} scalar, set to true to specify
+     *       NCHW data layout for input0 and input1. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0, of shape
+     *      [num_output_rois], specifying the score of each output box.
+     *      The boxes are grouped by batches, but the sequential order in
+     *      each batch is not guaranteed. For type of
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the scale and zero
+     *      point must be the same as input0.
+     * * 1: A tensor of the same {@link OperandType} as input3, of shape
+     *      [num_output_rois, 4], specifying the coordinates of each output
+     *      bounding box for each class, with format [x1, y1, x2, y2].
+     *      The sequential order of the boxes corresponds with output0.
+     *      For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the
+     *      scale must be 0.125 and the zero point must be 0.
+     * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_output_rois], specifying the batch index of each box. Boxes
+     *      with the same batch index are grouped together.
+     */
+    GENERATE_PROPOSALS = @1.2::OperationType:GENERATE_PROPOSALS,
+
+    /**
+     * For input tensors x and y, computes x > y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    GREATER = @1.2::OperationType:GREATER,
+    /**
+     * For input tensors x and y, computes x >= y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    GREATER_EQUAL = @1.2::OperationType:GREATER_EQUAL,
+
+    /**
+     * Performs a grouped 2-D convolution operation.
+     *
+     * Given an input tensor of shape [batches, height, width, depth_in] and a
+     * filter tensor of shape [depth_out, filter_height, filter_width, depth_group]
+     * containing depth_out convolutional filters of depth depth_group, GROUPED_CONV
+     * applies a group of different filters to each input channel group, then
+     * concatenates the results together.
+     *
+     * Specifically, the input channels are divided into num_groups groups, each with
+     * depth depth_group, i.e. depth_in = num_groups * depth_group. The convolutional
+     * filters are also divided into num_groups groups, i.e. depth_out is divisible
+     * by num_groups. GROUPED_CONV applies each group of filters to the corresponding
+     * input channel group, and the result are concatenated together.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, g * channel_multiplier + q] =
+     *         sum_{di, dj, dk} (
+     *             input[b, strides[1] * i + di, strides[2] * j + dj,
+     *                   g * depth_group + dk] *
+     *             filter[g * channel_multiplier + q, di, dj, dk]
+     *         ) + bias[channel]
+     *
+     * where channel_multiplier = depth_out / num_groups
+     *
+     * Supported tensor {@link OperandType} configurations:
+     * * 16 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
+     *
+     * * 32 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias.
+     *
+     * * Quantized:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * * Quantized with symmetric per channel quantization for the filter:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output.
+     * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+     * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+     * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input, where depth_in = num_groups * depth_group.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_group], specifying
+     *      the filter, where depth_out must be divisible by num_groups.  For
+     *      tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (channelDim at
+     *      {@link SymmPerChannelQuantParams}) must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale. For filter tensor
+     *      of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
+     *      should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
+     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 9: An {@link OperandType::INT32} scalar, specifying the number of
+            groups.
+     * * 10: An {@link OperandType::INT32} scalar, and has to be one of the
+     *       {@link FusedActivationFunc} values. Specifies the activation to
+     *       invoke on the result.
+     * * 11: An {@link OperandType::BOOL} scalar, set to true to specify
+     *       NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input, where depth_in = num_groups * depth_group.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_group], specifying
+     *      the filter, where depth_out must be divisible by num_groups.  For
+     *      tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale. For filter tensor
+     *      of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
+     *      should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
+     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the number of
+     *      groups.
+     * * 7: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 8: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth_out].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    GROUPED_CONV_2D = @1.2::OperationType:GROUPED_CONV_2D,
+
+    /**
+     * Localize the maximum keypoints from heatmaps.
+     *
+     * This operation approximates the accurate maximum keypoint scores and
+     * indices after bicubic upscaling by using Taylor expansion up to the
+     * quadratic term.
+     *
+     * The bounding box is represented by its upper-left corner coordinate
+     * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image.
+     * A valid bounding box should satisfy x1 <= x2 and y1 <= y2.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Inputs:
+     * * 0: A 4-D Tensor of shape
+     *      [num_boxes, heatmap_size, heatmap_size, num_keypoints],
+     *      specifying the heatmaps, the height and width of heatmaps should
+     *      be the same, and must be greater than or equal to 2.
+     * * 1: A 2-D Tensor of shape [num_boxes, 4], specifying the bounding boxes,
+     *      each with format [x1, y1, x2, y2]. For input0 of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should
+     *      be of {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint
+     *      of 0 and scale of 0.125.
+     * * 2: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0, with shape
+     *      [num_boxes, num_keypoints], specifying score of the keypoints.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from input0 scale and zeroPoint.
+     * * 1: A tensor of the same {@link OperandType} as input1, with shape
+     *      [num_boxes, num_keypoints, 2], specifying the location of
+     *      the keypoints, the second dimension is organized as
+     *      [keypoint_x, keypoint_y].
+     *      For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the
+     *      scale must be 0.125 and the zero point must be 0.
+     */
+    HEATMAP_MAX_KEYPOINT = @1.2::OperationType:HEATMAP_MAX_KEYPOINT,
+
+    /**
+     * Applies instance normalization to the input tensor.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, h, w, c] =
+     *         (input[b, h, w, c] - mean[b, c]) * gamma /
+     *         sqrt(var[b, c] + epsilon) + beta
+     *
+     * Where the mean and variance are computed across the spatial dimensions:
+     *
+     *     mean[b, c] =
+     *         sum_{h, w}(input[b, h, w, c]) / sum(1)
+     *
+     *     var[b, c] =
+     *         sum_{h, w}(pow(input[b, h, w, c] - mean[b, c], 2)) / sum(1)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be normalized.
+     * * 1: A scalar, specifying gamma, the scale applied to the normalized
+     *      tensor. The scalar must be of {@link OperandType::FLOAT16} if
+     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} if input0 is of
+     *      {@link OperandType::TENSOR_FLOAT32}.
+     * * 2: A scalar, specifying beta, the offset applied to the normalized
+     *      tensor. The scalar must be of {@link OperandType::FLOAT16} if
+     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} if input0 is of
+     *      {@link OperandType::TENSOR_FLOAT32}.
+     * * 3: A scalar, specifying epsilon, the small value added to variance to
+     *      avoid dividing by zero. The scalar must be of {@link OperandType::FLOAT16} if
+     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} if input0 is of
+     *      {@link OperandType::TENSOR_FLOAT32}.
+     * * 4: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} and same shape as input0.
+     */
+    INSTANCE_NORMALIZATION = @1.2::OperationType:INSTANCE_NORMALIZATION,
+
+    /**
+     * For input tensors x and y, computes x < y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    LESS = @1.2::OperationType:LESS,
+
+    /**
+     * For input tensors x and y, computes x <= y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    LESS_EQUAL = @1.2::OperationType:LESS_EQUAL,
+
+    /**
+     * Computes natural logarithm of x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    LOG = @1.2::OperationType:LOG,
+
+    /**
+     * Returns the truth value of x AND y element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     * * 1: A tensor of {@link OperandType::TENSOR_BOOL8} and dimensions
+     *      compatible with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    LOGICAL_AND = @1.2::OperationType:LOGICAL_AND,
+
+    /**
+     * Computes the truth value of NOT x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    LOGICAL_NOT = @1.2::OperationType:LOGICAL_NOT,
+
+    /**
+     * Returns the truth value of x OR y element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     * * 1: A tensor of {@link OperandType::TENSOR_BOOL8} and dimensions
+     *      compatible with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    LOGICAL_OR = @1.2::OperationType:LOGICAL_OR,
+
+    /**
+     * Computes the log softmax activations given logits.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = logits * beta - log(reduce_sum(exp(logits * beta), axis))
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor specifying the input logits.
+     * * 1: A scalar, specifying the positive scaling factor for the exponent,
+     *      beta.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the beta
+     *      value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the beta
+     *      value must be of {@link OperandType::FLOAT32}.
+     * * 2: An {@link OperandType::INT32} scalar specifying the axis to
+     *      reduce across. Negative index is used to specify axis from the
+     *      end (e.g. -1 for the last axis). Must be in the range [-n, n).
+     *
+     * Outputs:
+     * * 0: The output tensor of the same {@link OperandType} and shape as
+     *      input0.
+     */
+    LOG_SOFTMAX = @1.2::OperationType:LOG_SOFTMAX,
+
+    /**
+     * Returns the element-wise maximum of two tensors.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and compatible dimensions
+     *      with input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    MAXIMUM = @1.2::OperationType:MAXIMUM,
+
+    /**
+     * Returns the element-wise minimum of two tensors.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and compatible dimensions
+     *      with input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    MINIMUM = @1.2::OperationType:MINIMUM,
+
+    /**
+     * Computes numerical negative value element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    NEG = @1.2::OperationType:NEG,
+
+    /**
+     * For input tensors x and y, computes x != y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    NOT_EQUAL = @1.2::OperationType:NOT_EQUAL,
+
+    /**
+     * Pads a tensor with the given constant value according to the specified
+     * paddings.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be padded.
+     * * 1: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings
+     *      for each spatial dimension of the input tensor. The shape of the
+     *      tensor must be {rank(input0), 2}.
+     *      padding[i, 0] specifies the number of elements to be padded in the
+     *      front of dimension i.
+     *      padding[i, 1] specifies the number of elements to be padded after
+     *      the end of dimension i.
+     * * 2: An scalar specifying the value to use for padding input0.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the
+     *      pad value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the
+     *      pad value must be of {@link OperandType::FLOAT32}.
+     *      For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the pad value must be of {@link OperandType::INT32}. The
+     *      scale and zeroPoint are assumed to be the same as in input0.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0. The
+     *      output tensor has the same rank as input0, and each
+     *      dimension of the output tensor has the same size as the
+     *      corresponding dimension of the input tensor plus the size
+     *      of the padding:
+     *          output0.dimension[i] =
+     *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    PAD_V2 = @1.2::OperationType:PAD_V2,
+
+    /**
+     * Computes the power of one value to another.
+     *
+     * Given a tensor base and a tensor exponent, this operation computes
+     * base^exponent elementwise.
+     *
+     * This operations supports broadcasting. The size of the output is the
+     * maximum size along each dimension of the input operands. It starts with
+     * the trailing dimensions, and works its way forward.
+     *
+     * For example:
+     *     base.dimension     =    {4, 1, 2}
+     *     exponent.dimension = {5, 4, 3, 1}
+     *     output.dimension   = {5, 4, 3, 2}
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A tensor specifying the base.
+     * * 1: A tensor specifying the exponent.
+     *
+     * Outputs:
+     * * 0: An output tensor.
+     */
+    POW = @1.2::OperationType:POW,
+
+    /**
+     * Parametric Rectified Linear Unit.
+     *
+     * It follows: f(x) = alpha * x for x < 0, f(x) = x for x >= 0, where alpha
+     * is a learned array with the same {@link OperandType} and compatible
+     * dimensions as input x.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the output is the maximum size along each dimension of the
+     * input operands. It starts with the trailing dimensions, and works its way
+     * forward.
+     *
+     * Example:
+     *     input.dimension  =    {4, 1, 2}
+     *     alpha.dimension  = {5, 4, 3, 1}
+     *     output.dimension = {5, 4, 3, 2}
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+     *      as input0, specifying the alpha.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be diffent from the input0 scale and zeroPoint.
+     */
+    PRELU = @1.2::OperationType:PRELU,
+
+    /**
+     * Quantizes the input tensor.
+     *
+     * The formula is:
+     *
+     *     output = max(0, min(255, round(input / scale) + zeroPoint)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A tensor, may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0, but with
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}.
+     */
+    QUANTIZE = @1.2::OperationType:QUANTIZE,
+
+    /**
+     * A version of quantized LSTM, using 16 bit quantization for internal
+     * state.
+     *
+     * There is no projection layer, so cell state size is equal to the output
+     * size.
+     *
+     * Inputs:
+     * * 0: A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [numBatches, inputSize] specifying the input to the LSTM
+     *      cell. Tensor is quantized with a fixed quantization range of
+     *      [-1, 127/128] (scale = 1/128, zeroPoint = 128).
+     * * 1: The input-to-input weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, inputSize] specifying input-to-input part of
+     *      weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 2: The input-to-forget weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, inputSize] specifying input-to-forget part of
+     *      weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 3: The input-to-cell weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, inputSize] specifying input-to-cell part of
+     *      weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 4: The input-to-output weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, inputSize] specifying input-to-output part of
+     *      weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 5: The recurrent-to-input weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, outputSize] specifying recurrent-to-input part
+     *      of weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 6: The recurrent-to-forget weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, outputSize] specifying recurrent-to-forget
+     *      part of weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 7: The recurrent-to-cell weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, outputSize] specifying recurrent-to-cell part
+     *      of weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 8: The recurrent-to-output weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, outputSize] specifying recurrent-to-output
+     *      part of weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 9: The input gate bias.
+     *      A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape
+     *      [outputSize] specifying the bias for the fully-connected layer
+     *      inside the LSTM cell. Bias is quantized with scale being a product
+     *      of input and weights scales and zeroPoint equal to 0.
+     * * 10:The forget gate bias.
+     *      A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape
+     *      [outputSize] specifying the bias for the fully-connected layer
+     *      inside the LSTM cell. Bias is quantized with scale being a product
+     *      of input and weights scales and zeroPoint equal to 0.
+     * * 11:The cell bias.
+     *      A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape
+     *      [outputSize] specifying the bias for the fully-connected layer
+     *      inside the LSTM cell. Bias is quantized with scale being a product
+     *      of input and weights scales and zeroPoint equal to 0.
+     * * 12:The output gate bias.
+     *      A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape
+     *      [outputSize] specifying the bias for the fully-connected layer
+     *      inside the LSTM cell. Bias is quantized with scale being a product
+     *      of input and weights scales and zeroPoint equal to 0.
+     * * 13: A 2-D tensor of type {@link OperandType::TENSOR_QUANT16_SYMM}
+     *       and shape [numBatches, outputSize] specifying the cell state from the
+     *       previous time step of the LSTM cell. It is quantized using a
+     *       quantization range of [-2^4, 2^4 * 32767/32768] (scale = 2^4 /
+     *       32768, zeroPoint = 0).
+     * * 14: A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *       and shape [numBathes, outputSize] specifying the output of the LSTM
+     *       cell from previous time-step. Tensor is quantized with a fixed
+     *       quantization range of [-1, 127/128] (scale = 1/128, zeroPoint =
+     *       128).
+     *
+     *
+     * Outputs:
+     * * 0: A 2-D tensor of type {@link OperandType::TENSOR_QUANT16_SYMM}
+     *      and shape [numBatches, outputSize] which contains a cell state from
+     *      the current time step. Tensor is quantized using a quantization
+     *      range of [-2^4, 2^4 * 32767/32768] (scale = 2^4 / 32768, zeroPoint =
+     *      0).
+     * * 1: A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [numBathes, outputSize] which contains the output value.
+     *      Tensor is quantized with a fixed quantization range of [-1, 127/128]
+     *      (scale = 1/128, zeroPoint = 128).
+     */
+    QUANTIZED_16BIT_LSTM = @1.2::OperationType:QUANTIZED_16BIT_LSTM,
+
+    /**
+     * Draws samples from a multinomial distribution.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Inputs:
+     * * 0: A 2-D tensor with shape [batches, classes], specifying the
+     *      unnormalized log-probabilities for all classes.
+     * * 1: A scalar {@link OperandType::INT32}, specifying the number of
+     *      independent samples to draw for each row slice.
+     * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor with shape [2],
+     *      specifying seeds used to initialize the random distribution.
+     * Outputs:
+     * * 0: A 2-D {@link OperandType::TENSOR_INT32} tensor with shape
+     *      [batches, samples], containing the drawn samples.
+     */
+    RANDOM_MULTINOMIAL = @1.2::OperationType:RANDOM_MULTINOMIAL,
+
+    /**
+     * Reduces a tensor by computing the "logical and" of elements along given
+     * dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     */
+    REDUCE_ALL = @1.2::OperationType:REDUCE_ALL,
+
+    /**
+     * Reduces a tensor by computing the "logical or" of elements along given
+     * dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     */
+    REDUCE_ANY = @1.2::OperationType:REDUCE_ANY,
+
+    /**
+     * Reduces a tensor by computing the maximum of elements along given
+     * dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    REDUCE_MAX = @1.2::OperationType:REDUCE_MAX,
+
+    /**
+     * Reduces a tensor by computing the minimum of elements along given
+     * dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    REDUCE_MIN = @1.2::OperationType:REDUCE_MIN,
+
+    /**
+     * Reduces a tensor by multiplying elements along given dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     */
+    REDUCE_PROD = @1.2::OperationType:REDUCE_PROD,
+
+    /**
+     * Reduces a tensor by summing elements along given dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     */
+    REDUCE_SUM = @1.2::OperationType:REDUCE_SUM,
+
+    /**
+     * Select and scale the feature map of each region of interest to a unified
+     * output size by average pooling sampling points from bilinear interpolation.
+     *
+     * The region of interest is represented by its upper-left corner coordinate
+     * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image.
+     * A spatial scaling factor is applied to map into feature map coordinate.
+     * A valid region of interest should satisfy x1 <= x2 and y1 <= y2.
+     *
+     * No rounding is applied in this operation. The sampling points are unified
+     * distributed in the pooling bin and their values are calculated by bilinear
+     * interpolation.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Inputs:
+     * * 0: A 4-D tensor, specifying the feature map.
+     * * 1: A 2-D Tensor of shape [num_rois, 4], specifying the locations of
+     *      the regions of interest, each line with format [x1, y1, x2, y2].
+     *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM},
+     *      with zeroPoint of 0 and scale of 0.125. Zero num_rois is
+     *      supported for this tensor.
+     * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_rois], specifying the batch index of each box. Boxes with
+     *      the same batch index are grouped together. Zero num_rois is
+     *      supported for this tensor.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the output
+     *      width of the output tensor.
+     * * 5: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the height of original image to the height of feature map.
+     * * 6: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the width of original image to the width of feature map.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the number of
+     *      sampling points in height dimension used to compute the output.
+     *      Set to 0 for adaptive value of ceil(roi_height/out_height).
+     * * 8: An {@link OperandType::INT32} scalar, specifying the number of
+     *      sampling points in width dimension used to compute the output.
+     *      Set to 0 for adaptive value of ceil(roi_width/out_width).
+     * * 9: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0. The output
+     *      shape is [num_rois, out_height, out_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from the input0 scale and zeroPoint.
+     */
+    ROI_ALIGN = @1.2::OperationType:ROI_ALIGN,
+
+    /**
+     * Select and scale the feature map of each region of interest to a unified
+     * output size by max-pooling.
+     *
+     * The region of interest is represented by its upper-left corner coordinate
+     * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image.
+     * A spatial scaling factor is applied to map into feature map coordinate.
+     * A valid region of interest should satisfy x1 <= x2 and y1 <= y2.
+     *
+     * Rounding is applied in this operation to ensure integer boundary for
+     * regions of interest and pooling bins.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Inputs:
+     * * 0: A 4-D tensor, specifying the feature map.
+     * * 1: A 2-D Tensor of shape [num_rois, 4], specifying the locations of
+     *      the regions of interest, each line with format [x1, y1, x2, y2].
+     *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM},
+     *      with zeroPoint of 0 and scale of 0.125.
+     * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_rois], specifying the batch index of each box. Boxes with
+     *      the same batch index are grouped together.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the output
+     *      width of the output tensor.
+     * * 5: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the height of original image to the height of feature map.
+     * * 6: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the width of original image to the width of feature map.
+     * * 7: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0. The output
+     *      shape is [num_rois, out_height, out_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    ROI_POOLING = @1.2::OperationType:ROI_POOLING,
+
+    /**
+     * Computes reciprocal of square root of x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    RSQRT = @1.2::OperationType:RSQRT,
+
+    /**
+     * Using a tensor of booleans c and input tensors x and y select values
+     * elementwise from both input tensors:
+     *
+     * O[i] = C[i] ? x[i] : y[i].
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A tensor of type {@link OperandType::TENSOR_BOOL8} acting as a
+     *      mask that chooses, based on the value at each element, whether the
+     *      corresponding element in the output should be taken from input1 (if
+     *      true) or input2 (if false).
+     * * 1: An input tensor of the same shape as input0.
+     * * 2: An input tensor of the same shape and type as input1.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scales and zeroPoint can be different from input1 scale and zeroPoint.
+     *
+     * Outputs:
+     * * 0: A tensor of the same type and shape as input1 and input2.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    SELECT = @1.2::OperationType:SELECT,
+
+    /**
+     * Computes sin of x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    SIN = @1.2::OperationType:SIN,
+
+    /**
+     * Extracts a slice of specified size from the input tensor starting at a
+     * specified location.
+     *
+     * The starting location is specified as a 1-D tensor containing offsets
+     * for each dimension. The size is specified as a 1-D tensor containing
+     * either size of a slice along corresponding dimension or -1. In the latter
+     * case, all the remaining elements in dimension are included in the slice.
+     *
+     * A sum of begin offset and a size of a slice must not exceed size of a
+     * corresponding dimension.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor to take slice from, may be zero-sized.
+     * * 1: A 1-D tensor of type {@link OperandType::TENSOR_INT32} specifying
+     *      the beginning indices of the slice in each dimension.
+     * * 2: A 1-D tensor of type {@link OperandType::TENSOR_INT32} specifying
+     *      the size of the slice in each dimension.
+     *
+     * Outputs:
+     * * 0: An n-D tensor of the same type as the input containing the slice.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      its scale and zeroPoint has to be same as the input0 scale and zeroPoint.
+     */
+    SLICE = @1.2::OperationType:SLICE,
+
+    /**
+     * Splits a tensor along a given axis into num_splits subtensors.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor to split.
+     * * 1: An {@link OperandType::INT32} scalar specifying the axis along
+     *      which to split.
+     * * 2: An {@link OperandType::INT32} scalar indicating the number of
+     *      splits along given axis. Must evenly divide axis size.
+     *
+     * Outputs:
+     * * 0 ~ (num_splits - 1): Resulting subtensors.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    SPLIT = @1.2::OperationType:SPLIT,
+
+    /**
+     * Computes square root of x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    SQRT = @1.2::OperationType:SQRT,
+
+    /**
+     * Constructs a tensor by tiling a given tensor.
+     *
+     * This operation creates a new tensor by replicating `input` `multiples`
+     * times. The output tensor's i-th dimension has `input.dims(i) * multiples[i]`
+     * elements, and the values of `input` are replicated `multiples[i]` times
+     * along the i-th dimension.
+     * For example, tiling `[a b c d]` by `[2]` produces `[a b c d a b c d]`.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: input, an n-D tensor specifying the input.
+     * * 1: multiples, a 1-D tensor of {@link OperandType::TENSOR_INT32}.
+     *      The length of multiples must be n.
+     *
+     * Outputs:
+     * * 0: A tiled tensor of the same {@link OperandType} and rank as `input`.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    TILE = @1.2::OperationType:TILE,
+
+    /**
+     * Finds values and indices of the k largest entries for the last dimension.
+     *
+     * Resulting values in each dimensions are sorted in descending order. If
+     * two values are equal, the one with larger index appears first.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: input, an n-D tensor specifying the input.
+     * * 1: k, an {@link OperandType::INT32} scalar, specifying the number of
+     *      top elements to look for along the last dimension.
+     *
+     * Outputs:
+     * * 0: An n-D tensor of the same type as the input, containing the k
+     *      largest elements along each last dimensional slice.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     * * 1: An n-D tensor of type {@link OperandType::TENSOR_INT32}
+     *      containing the indices of values within the last dimension of input.
+     */
+    TOPK_V2 = @1.2::OperationType:TOPK_V2,
+
+    /**
+     * Performs the transpose of 2-D convolution operation.
+     *
+     * This operation is sometimes called "deconvolution" after Deconvolutional
+     * Networks, but is actually the transpose (gradient) of
+     * {@link OperandType::CONV_2D} rather than an actual deconvolution.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * Supported tensor {@link OperandType} configurations:
+     * * 16 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
+     *
+     * * 32 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias.
+     *
+     * * Quantized:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * * Quantized with symmetric per channel quantization for the filter:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output.
+     * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+     * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+     * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_in], specifying the
+     *      filter. For tensor of type
+     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
+     *      dimension (SymmPerChannelQuantParams::channelDim) must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias should be of the
+     *      same type. For input tensor of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
+     *      of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
+     *      bias_scale == input_scale * filter_scale. For filter tensor of
+     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
+     *      must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
+     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal
+     *      to bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 10: An {@link OperandType::BOOL} scalar, set to true to specify
+     *       NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_in], specifying the
+     *      filter. For tensor of type
+     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
+     *      dimension (SymmPerChannelQuantParams::channelDim) must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias should be of the
+     *      same type. For input tensor of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
+     *      of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
+     *      bias_scale == input_scale * filter_scale. For filter tensor of
+     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
+     *      must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
+     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal
+     *      to bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::TENSOR_INT32} tensor, specifying the output
+     *      tensor shape.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 8: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth_out].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    TRANSPOSE_CONV_2D = @1.2::OperationType:TRANSPOSE_CONV_2D,
+
+    /**
+     * A recurrent neural network specified by an LSTM cell.
+     *
+     * Performs (fully) dynamic unrolling of input.
+     *
+     * This Op unrolls the input along the time dimension, and implements the
+     * following operation for each element in the sequence
+     * s = 1...sequence_length:
+     *   outputs[s] = projection(state = activation(LSTMOp(inputs[s])))
+     *
+     * Where LSTMOp is the LSTM op as in {@link OperandType::LSTM},
+     * the "projection" is an optional projection layer from state and output
+     * and the “activation” is the function passed as the
+     * “fused_activation_function” argument (if not “NONE”).
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: 3, either time-major or batch-major.
+     *
+     * All input and output tensors must be of the same type.
+     *
+     * Inputs:
+     * * 0: The input (\f$x_t\f$).
+     *      A 3-D tensor of shape:
+     *        If time-major: [max_time, batch_size, input_size]
+     *        If batch-major: [batch_size, max_time, input_size]
+     *      where “max_time” is the number of timesteps (sequence length),
+     *      “batch_size” corresponds to the batching dimension, and
+     *      “input_size” is the size of the input.
+     * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of cell units.
+     * * 2: The input-to-forget weights (\f$W_{xf}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 3: The input-to-cell weights (\f$W_{xc}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 4: The input-to-output weights (\f$W_{xo}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional.
+     *      A 2-D tensor of shape [num_units, output_size], where “output_size”
+     *      corresponds to either the number of cell units (i.e., “num_units”),
+     *      or the second dimension of the “projection_weights”, if defined.
+     * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 8: The recurrent-to-output weights (\f$W_{ho}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 12:The input gate bias (\f$b_i\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 13:The forget gate bias (\f$b_f\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 14:The cell bias (\f$b_c\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 15:The output gate bias (\f$b_o\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 16:The projection weights (\f$W_{proj}\f$). Optional.
+     *      A 2-D tensor of shape [output_size, num_units].
+     * * 17:The projection bias (\f$b_{proj}\f$). Optional.
+     *      A 1-D tensor of shape [output_size].
+     * * 18:The output state (in) (\f$h_{t-1}\f$).
+     *      A 2-D tensor of shape [batch_size, output_size].
+     * * 19:The cell state (in) (\f$C_{t-1}\f$).
+     *      A 2-D tensor of shape [batch_size, num_units].
+     * * 20:The activation function (\f$g\f$).
+     *      A value indicating the activation function:
+     *      <ul>
+     *      <li>0: None;
+     *      <li>1: Relu;
+     *      <li>3: Relu6;
+     *      <li>4: Tanh;
+     *      <li>6: Sigmoid.
+     *      </ul>
+     * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such
+     *      that values are bound within [-cell_clip, cell_clip]. If set to 0.0
+     *      then clipping is disabled.
+     * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the
+     *      projection layer, such that values are bound within
+     *      [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
+     * * 23:Time-major if true, batch-major if false.
+     * * 24:The input layer normalization weights. Optional.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at input gate.
+     * * 25:The forget layer normalization weights. Optional.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at forget gate.
+     * * 26:The cell layer normalization weights. Optional.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at cell gate.
+     * * 27:The output layer normalization weights. Optional.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at output gate.
+     *
+     * Outputs:
+     * * 0: The output (\f$o_t\f$).
+     *      A 3-D tensor of shape:
+     *        If time-major: [max_time, batch_size, output_size]
+     *        If batch-major: [batch_size, max_time, output_size]
+     */
+    UNIDIRECTIONAL_SEQUENCE_LSTM = @1.2::OperationType:UNIDIRECTIONAL_SEQUENCE_LSTM,
+
+    /**
+     * A recurrent neural network layer that applies a basic RNN cell to a
+     * sequence of inputs.
+     *
+     * This layer unrolls the input along the sequence dimension, and implements
+     * the following operation
+     * for each element in the sequence s = 1...sequence_length:
+     *   outputs[s] = state = activation(inputs[s] * input_weights’ + state *
+     *   recurrent_weights’ + bias)
+     *
+     * Where:
+     * * “input_weights” is a weight matrix that multiplies the inputs;
+     * * “recurrent_weights” is a weight matrix that multiplies the current
+     *    “state” which itself is the output from the previous time step
+     *    computation;
+     * * “bias” is a bias vector (added to each output vector in the batch);
+     * * “activation” is the function passed as the “fused_activation_function”
+     *   argument (if not “NONE”).
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * The input tensors must all be the same type.
+     *
+     * Inputs:
+     * * 0: input.
+     *      A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+     *      it is set to 1, then the input has a shape [maxTime, batchSize,
+     *      inputSize], otherwise the input has a shape [batchSize, maxTime,
+     *      inputSize].
+     * * 1: weights.
+     *      A 2-D tensor of shape [numUnits, inputSize].
+     * * 2: recurrent_weights.
+     *      A 2-D tensor of shape [numUnits, numUnits].
+     * * 3: bias.
+     *      A 1-D tensor of shape [numUnits].
+     * * 4: hidden state
+     *      A 2-D tensor of shape [batchSize, numUnits]. Specifies a hidden
+     *      state input for the first time step of the computation.
+     * * 5: fusedActivationFunction.
+     *      A {@link FusedActivationFunc} value indicating the activation function. If
+     *      “NONE” is specified then it results in a linear activation.
+     * * 6: timeMajor
+     *      An {@link OperandType::INT32} scalar specifying the shape format
+     *      of input and output tensors. Must be set to either 0 or 1.
+     * Outputs:
+     * * 0: output.
+     *      A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+     *      it is set to 1, then the output has a shape [maxTime, batchSize,
+     *      numUnits], otherwise the output has a shape [batchSize, maxTime,
+     *      numUnits].
+     */
+    UNIDIRECTIONAL_SEQUENCE_RNN = @1.2::OperationType:UNIDIRECTIONAL_SEQUENCE_RNN,
+
+    /**
+     * Resizes images to given size using the nearest neighbor interpretation.
+     *
+     * Resized images must be distorted if their output aspect ratio is not the
+     * same as input aspect ratio. The corner pixels of output may not be the
+     * same as corner pixels of input.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Both resizing by shape and resizing by scale are supported.
+     *
+     * Inputs (resizing by shape):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input. Zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the output
+     *      width of the output tensor.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
+     * * 3: An {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *
+     * Inputs (resizing by scale):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input. Zero batches is supported for this tensor.
+     * * 1: A scalar, specifying width_scale, the scaling factor of the width
+     *      dimension from the input tensor to the output tensor. The output
+     *      width is calculated as new_width = floor(width * width_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 2: A scalar, specifying height_scale, the scaling factor of the height
+     *      dimension from the input tensor to the output tensor. The output
+     *      height is calculated as new_height = floor(height * height_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 3: An {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, new_height, new_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RESIZE_NEAREST_NEIGHBOR = @1.2::OperationType:RESIZE_NEAREST_NEIGHBOR,
+
+    /**
+     * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
+     * OEM operation and data types.
+     *
+     * This operation is OEM specific. It should only be used for OEM
+     * applications.
+     */
+    OEM_OPERATION = @1.2::OperationType:OEM_OPERATION,
+    /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF
+     * OperationTypeRange::FUNDAMENTAL_MAX.
+     */
+    /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF
+     * OperationTypeRange::OEM_MAX.
+     */
+};
+
+/**
+ * The range of values in the OperationType enum.
+ */
+enum OperationTypeRange : uint32_t {
+    BASE_MIN        = 0,
+    FUNDAMENTAL_MIN = 0,
+    FUNDAMENTAL_MAX = 94,
+    OEM_MIN         = 10000,
+    OEM_MAX         = 10000,
+    BASE_MAX        = 0xFFFF,
+};
+
+
+/**
+ * The capabilities of a driver.
+ *
+ * Performance of an operation comes from the type of its first operand.
+ * This represents performance for non extension operand types.
+ */
+struct Capabilities {
+    /**
+     * Driver performance when operating on float32 data but performing
+     * calculations with range and/or precision as low as that of the IEEE
+     * 754 16-bit floating-point format.
+     */
+    PerformanceInfo relaxedFloat32toFloat16PerformanceScalar;
+    PerformanceInfo relaxedFloat32toFloat16PerformanceTensor;
+
+    /**
+     * Driver performance when operating on a particular data type.
+     * In the case of float32 data, this is used when the calculations
+     * are not relaxed.
+     */
+    struct OperandPerformance {
+        OperandType type;
+        PerformanceInfo info;
+    };
+
+    /**
+     * Performance by operand type. Must be sorted by OperandType.
+     * If a particular OperandType is not present in operandPerformance,
+     * its performance is treated as
+     * { .execTime = FLT_MAX, .powerUsage = FLT_MAX }.
+     */
+    vec<OperandPerformance> operandPerformance;
+};
+
+/**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+    /**
+     * The operation type.
+     *
+     * Besides the values listed in {@link OperationType}, any value above
+     * {@link OperationTypeRange::BASE_MAX} is possible and should be interpreted
+     * as an extension type according to {@link Model::extensionNameToPrefix}.
+     */
+    OperationType type;
+
+    /**
+     * Describes the table that contains the indexes of the inputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> inputs;
+
+    /**
+     * Describes the table that contains the indexes of the outputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> outputs;
+};
+
+/**
+ * Describes one operand of the model's graph.
+ */
+struct Operand {
+    /**
+     * The data type.
+     *
+     * Besides the values listed in {@link OperandType}, any value above
+     * {@link OperandTypeRange::BASE_MAX} is possible and should be interpreted
+     * as an extension type according to {@link Model::extensionNameToPrefix}.
+     */
+    OperandType type;
+
+    /**
+     * Dimensions of the operand.
+     *
+     * For a scalar operand, dimensions.size() must be 0.
+     *
+     * A tensor operand with all dimensions specified has "fully
+     * specified" dimensions. Whenever possible (i.e., whenever the
+     * dimensions are known at model construction time), a tensor
+     * operand should have (but is not required to have) fully
+     * specified dimensions, in order to enable the best possible
+     * performance.
+     *
+     * If a tensor operand's dimensions are not fully specified, the
+     * dimensions of the operand are deduced from the operand
+     * dimensions and values of the operation for which that operand
+     * is an output.
+     *
+     * In the following situations, a tensor operand's dimensions must
+     * be fully specified:
+     *
+     *     . The operand has lifetime CONSTANT_COPY or
+     *       CONSTANT_REFERENCE.
+     *
+     *     . The operand has lifetime MODEL_INPUT. Fully
+     *       specified dimensions must either be present in the
+     *       Operand or they must be provided in the corresponding
+     *       RequestArgument.
+     *       EXCEPTION: If the input is optional and omitted
+     *       (by setting the hasNoValue field of the corresponding
+     *       RequestArgument to true) then it need not have fully
+     *       specified dimensions.
+     *
+     * A tensor operand with some number of unspecified dimensions is
+     * represented by setting each unspecified dimension to 0.
+     *
+     * A tensor operand with unspecified rank is represented by providing
+     * an empty dimensions vector.
+     */
+    vec<uint32_t> dimensions;
+
+    /**
+     * The number of times this operand appears as an operation input.
+     *
+     * (For example, if this operand appears once in one operation's
+     * input list, and three times in another operation's input list,
+     * then numberOfConsumers = 4.)
+     */
+    uint32_t numberOfConsumers;
+
+    /**
+     * Quantized scale of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or
+     * TENSOR_INT32.
+     */
+    float scale;
+
+    /**
+     * Quantized zero-point offset of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM.
+     */
+    int32_t zeroPoint;
+
+    /**
+     * How the operand is used.
+     */
+    OperandLifeTime lifetime;
+
+    /**
+     * Where to find the data for this operand.
+     * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
+     * NO_VALUE:
+     * - All the fields must be 0.
+     * If the lifetime is CONSTANT_COPY:
+     * - location.poolIndex is 0.
+     * - location.offset is the offset in bytes into Model.operandValues.
+     * - location.length is set.
+     * If the lifetime is CONSTANT_REFERENCE:
+     * - location.poolIndex is set.
+     * - location.offset is the offset in bytes into the specified pool.
+     * - location.length is set.
+     */
+    DataLocation location;
+
+    /**
+     * Additional parameters specific to a particular operand type.
+     */
+    safe_union ExtraParams {
+       /**
+        * No additional parameters.
+        */
+       Monostate none;
+
+       /**
+        * Symmetric per-channel quantization parameters.
+        *
+        * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL.
+        */
+       SymmPerChannelQuantParams channelQuant;
+
+       /**
+        * Extension operand parameters.
+        *
+        * The framework treats this as an opaque data blob.
+        * The format is up to individual extensions.
+        */
+       vec<uint8_t> extension;
+    } extraParams;
+};
+
+/**
+ * A Neural Network Model.
+ *
+ * This includes not only the execution graph, but also constant data such as
+ * weights or scalars added at construction time. The only information that
+ * may not be known is the shape of the input tensors.
+ */
+struct Model {
+    /**
+     * All operands included in the model.
+     */
+    vec<Operand> operands;
+
+    /**
+     * All operations included in the model.
+     *
+     * The operations are sorted into execution order. Every operand
+     * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
+     * written before it is read.
+     */
+    vec<Operation> operations;
+
+    /**
+     * Input indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> inputIndexes;
+
+    /**
+     * Output indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> outputIndexes;
+
+    /**
+     * A byte buffer containing operand data that were copied into the model.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_COPY.
+     */
+    vec<uint8_t> operandValues;
+
+    /**
+     * A collection of shared memory pools containing operand values.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_REFERENCE.
+     */
+    vec<memory> pools;
+
+    /**
+     * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or
+     * precision as low as that of the IEEE 754 16-bit floating-point format.
+     * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the
+     * range and precision of the IEEE 754 32-bit floating-point format.
+     */
+    bool relaxComputationFloat32toFloat16;
+
+    /**
+     * The mapping between extension names and prefixes of operand and
+     * operation type values.
+     *
+     * An operand or operation whose numeric type value is above
+     * {@link OperandTypeRange::BASE_MAX} or
+     * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
+     * as an extension operand. The low
+     * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
+     * correspond to the type ID within the extension and the high
+     * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+     * the "prefix", which maps uniquely to the extension name.
+     *
+     * For example, if a model contains an operation whose value is
+     * 0xAAAABBBB and extensionNameToPrefix contains an entry with
+     * prefix=0xAAAA and name="vendor.test.test_extension", then
+     * the operation should be interpreted as the operation 0xBBBB
+     * of the extension named vendor.test.test_extension.
+     *
+     * This is a one-to-one correspondence. That is, there must be at most one
+     * prefix corresponding to each extension name and at most one extension
+     * name corresponding to each prefix.
+     */
+    vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+
+    /**
+     * A correspondence between an extension name and a prefix of operand and
+     * operation type values.
+     */
+    struct ExtensionNameAndPrefix {
+        /**
+         * The extension name.
+         *
+         * See {@link Extension::name} for the format specification.
+         */
+        string name;
+
+        /**
+         * The unique extension identifier within the model.
+         *
+         * See {@link Model::extensionNameToPrefix}.
+         */
+        uint16_t prefix;
+    };
+
+    /**
+     * Numeric values of extension operand and operation types have the
+     * following structure:
+     * - 16 high bits represent the "prefix", which corresponds uniquely to the
+     *   extension name.
+     * - 16 low bits represent the type ID within the extension.
+     */
+    enum ExtensionTypeEncoding : uint8_t {
+        HIGH_BITS_PREFIX = 16,
+        LOW_BITS_TYPE = 16,
+    };
+};
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
new file mode 100644
index 0000000..e06f5d6
--- /dev/null
+++ b/neuralnetworks/1.3/types.t
@@ -0,0 +1,389 @@
+%% template file for generating types.hal.
+%% see frameworks/ml/nn/tools/api/README.md.
+/*
+ * 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.neuralnetworks@1.3;
+
+import @1.0::DataLocation;
+import @1.0::OperandLifeTime;
+import @1.0::PerformanceInfo;
+import @1.2::OperandType;
+import @1.2::OperationType;
+import @1.2::SymmPerChannelQuantParams;
+
+import android.hidl.safe_union@1.0::Monostate;
+
+enum OperandType : @1.2::OperandType {
+%insert Operand_1.3
+%insert OEMDeprecationAndOperandTypeRangeMaxComment
+};
+
+/**
+ * The range of operand values in the OperandType enum.
+ */
+enum OperandTypeRange : uint32_t {
+    BASE_MIN        = 0,
+    FUNDAMENTAL_MIN = 0,
+%insert Operand_1.3_MAX
+    OEM_MIN         = 10000,
+    OEM_MAX         = 10001,
+    BASE_MAX        = 0xFFFF,
+};
+
+/**
+ * Operation types.
+ *
+ * The type of an operation in a model.
+ */
+enum OperationType : int32_t {
+
+%insert Operation_1.0
+
+%insert Operation_1.1
+
+%insert Operation_1.2
+
+    /**
+     * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
+     * OEM operation and data types.
+     *
+     * This operation is OEM specific. It should only be used for OEM
+     * applications.
+     */
+    OEM_OPERATION = @1.2::OperationType:OEM_OPERATION,
+    /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF
+     * OperationTypeRange::FUNDAMENTAL_MAX.
+     */
+    /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF
+     * OperationTypeRange::OEM_MAX.
+     */
+};
+
+/**
+ * The range of values in the OperationType enum.
+ */
+enum OperationTypeRange : uint32_t {
+    BASE_MIN        = 0,
+    FUNDAMENTAL_MIN = 0,
+%insert Operation_1.3_MAX
+    OEM_MIN         = 10000,
+    OEM_MAX         = 10000,
+    BASE_MAX        = 0xFFFF,
+};
+
+
+/**
+ * The capabilities of a driver.
+ *
+ * Performance of an operation comes from the type of its first operand.
+ * This represents performance for non extension operand types.
+ */
+struct Capabilities {
+    /**
+     * Driver performance when operating on float32 data but performing
+     * calculations with range and/or precision as low as that of the IEEE
+     * 754 16-bit floating-point format.
+     */
+    PerformanceInfo relaxedFloat32toFloat16PerformanceScalar;
+    PerformanceInfo relaxedFloat32toFloat16PerformanceTensor;
+
+    /**
+     * Driver performance when operating on a particular data type.
+     * In the case of float32 data, this is used when the calculations
+     * are not relaxed.
+     */
+    struct OperandPerformance {
+        OperandType type;
+        PerformanceInfo info;
+    };
+
+    /**
+     * Performance by operand type. Must be sorted by OperandType.
+     * If a particular OperandType is not present in operandPerformance,
+     * its performance is treated as
+     * { .execTime = FLT_MAX, .powerUsage = FLT_MAX }.
+     */
+    vec<OperandPerformance> operandPerformance;
+};
+
+/**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+    /**
+     * The operation type.
+     *
+     * Besides the values listed in {@link OperationType}, any value above
+     * {@link OperationTypeRange::BASE_MAX} is possible and should be interpreted
+     * as an extension type according to {@link Model::extensionNameToPrefix}.
+     */
+    OperationType type;
+
+    /**
+     * Describes the table that contains the indexes of the inputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> inputs;
+
+    /**
+     * Describes the table that contains the indexes of the outputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> outputs;
+};
+
+/**
+ * Describes one operand of the model's graph.
+ */
+struct Operand {
+    /**
+     * The data type.
+     *
+     * Besides the values listed in {@link OperandType}, any value above
+     * {@link OperandTypeRange::BASE_MAX} is possible and should be interpreted
+     * as an extension type according to {@link Model::extensionNameToPrefix}.
+     */
+    OperandType type;
+
+    /**
+     * Dimensions of the operand.
+     *
+     * For a scalar operand, dimensions.size() must be 0.
+     *
+     * A tensor operand with all dimensions specified has "fully
+     * specified" dimensions. Whenever possible (i.e., whenever the
+     * dimensions are known at model construction time), a tensor
+     * operand should have (but is not required to have) fully
+     * specified dimensions, in order to enable the best possible
+     * performance.
+     *
+     * If a tensor operand's dimensions are not fully specified, the
+     * dimensions of the operand are deduced from the operand
+     * dimensions and values of the operation for which that operand
+     * is an output.
+     *
+     * In the following situations, a tensor operand's dimensions must
+     * be fully specified:
+     *
+     *     . The operand has lifetime CONSTANT_COPY or
+     *       CONSTANT_REFERENCE.
+     *
+     *     . The operand has lifetime MODEL_INPUT. Fully
+     *       specified dimensions must either be present in the
+     *       Operand or they must be provided in the corresponding
+     *       RequestArgument.
+     *       EXCEPTION: If the input is optional and omitted
+     *       (by setting the hasNoValue field of the corresponding
+     *       RequestArgument to true) then it need not have fully
+     *       specified dimensions.
+     *
+     * A tensor operand with some number of unspecified dimensions is
+     * represented by setting each unspecified dimension to 0.
+     *
+     * A tensor operand with unspecified rank is represented by providing
+     * an empty dimensions vector.
+     */
+    vec<uint32_t> dimensions;
+
+    /**
+     * The number of times this operand appears as an operation input.
+     *
+     * (For example, if this operand appears once in one operation's
+     * input list, and three times in another operation's input list,
+     * then numberOfConsumers = 4.)
+     */
+    uint32_t numberOfConsumers;
+
+    /**
+     * Quantized scale of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or
+     * TENSOR_INT32.
+     */
+    float scale;
+
+    /**
+     * Quantized zero-point offset of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM.
+     */
+    int32_t zeroPoint;
+
+    /**
+     * How the operand is used.
+     */
+    OperandLifeTime lifetime;
+
+    /**
+     * Where to find the data for this operand.
+     * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
+     * NO_VALUE:
+     * - All the fields must be 0.
+     * If the lifetime is CONSTANT_COPY:
+     * - location.poolIndex is 0.
+     * - location.offset is the offset in bytes into Model.operandValues.
+     * - location.length is set.
+     * If the lifetime is CONSTANT_REFERENCE:
+     * - location.poolIndex is set.
+     * - location.offset is the offset in bytes into the specified pool.
+     * - location.length is set.
+     */
+    DataLocation location;
+
+    /**
+     * Additional parameters specific to a particular operand type.
+     */
+    safe_union ExtraParams {
+       /**
+        * No additional parameters.
+        */
+       Monostate none;
+
+       /**
+        * Symmetric per-channel quantization parameters.
+        *
+        * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL.
+        */
+       SymmPerChannelQuantParams channelQuant;
+
+       /**
+        * Extension operand parameters.
+        *
+        * The framework treats this as an opaque data blob.
+        * The format is up to individual extensions.
+        */
+       vec<uint8_t> extension;
+    } extraParams;
+};
+
+/**
+ * A Neural Network Model.
+ *
+ * This includes not only the execution graph, but also constant data such as
+ * weights or scalars added at construction time. The only information that
+ * may not be known is the shape of the input tensors.
+ */
+struct Model {
+    /**
+     * All operands included in the model.
+     */
+    vec<Operand> operands;
+
+    /**
+     * All operations included in the model.
+     *
+     * The operations are sorted into execution order. Every operand
+     * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
+     * written before it is read.
+     */
+    vec<Operation> operations;
+
+    /**
+     * Input indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> inputIndexes;
+
+    /**
+     * Output indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> outputIndexes;
+
+    /**
+     * A byte buffer containing operand data that were copied into the model.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_COPY.
+     */
+    vec<uint8_t> operandValues;
+
+    /**
+     * A collection of shared memory pools containing operand values.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_REFERENCE.
+     */
+    vec<memory> pools;
+
+    /**
+     * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or
+     * precision as low as that of the IEEE 754 16-bit floating-point format.
+     * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the
+     * range and precision of the IEEE 754 32-bit floating-point format.
+     */
+    bool relaxComputationFloat32toFloat16;
+
+    /**
+     * The mapping between extension names and prefixes of operand and
+     * operation type values.
+     *
+     * An operand or operation whose numeric type value is above
+     * {@link OperandTypeRange::BASE_MAX} or
+     * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
+     * as an extension operand. The low
+     * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
+     * correspond to the type ID within the extension and the high
+     * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+     * the "prefix", which maps uniquely to the extension name.
+     *
+     * For example, if a model contains an operation whose value is
+     * 0xAAAABBBB and extensionNameToPrefix contains an entry with
+     * prefix=0xAAAA and name="vendor.test.test_extension", then
+     * the operation should be interpreted as the operation 0xBBBB
+     * of the extension named vendor.test.test_extension.
+     *
+     * This is a one-to-one correspondence. That is, there must be at most one
+     * prefix corresponding to each extension name and at most one extension
+     * name corresponding to each prefix.
+     */
+    vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+
+    /**
+     * A correspondence between an extension name and a prefix of operand and
+     * operation type values.
+     */
+    struct ExtensionNameAndPrefix {
+        /**
+         * The extension name.
+         *
+         * See {@link Extension::name} for the format specification.
+         */
+        string name;
+
+        /**
+         * The unique extension identifier within the model.
+         *
+         * See {@link Model::extensionNameToPrefix}.
+         */
+        uint16_t prefix;
+    };
+
+    /**
+     * Numeric values of extension operand and operation types have the
+     * following structure:
+     * - 16 high bits represent the "prefix", which corresponds uniquely to the
+     *   extension name.
+     * - 16 low bits represent the type ID within the extension.
+     */
+    enum ExtensionTypeEncoding : uint8_t {
+        HIGH_BITS_PREFIX = 16,
+        LOW_BITS_TYPE = 16,
+    };
+};
diff --git a/neuralnetworks/1.3/vts/OWNERS b/neuralnetworks/1.3/vts/OWNERS
new file mode 100644
index 0000000..b5a8e1f
--- /dev/null
+++ b/neuralnetworks/1.3/vts/OWNERS
@@ -0,0 +1,16 @@
+# Neuralnetworks team
+butlermichael@google.com
+dgross@google.com
+jeanluc@google.com
+levp@google.com
+miaowang@google.com
+mikie@google.com
+mks@google.com
+pszczepaniak@google.com
+slavash@google.com
+vddang@google.com
+xusongw@google.com
+
+# VTS team
+yim@google.com
+yuexima@google.com
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..e2795de
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -0,0 +1,77 @@
+//
+// 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: "VtsHalNeuralNetworksV1_3Callbacks",
+    defaults: ["VtsHalTargetTestDefaults"],
+    export_include_dirs: ["include"],
+    srcs: [
+        "Callbacks.cpp",
+    ],
+    static_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.2",
+        "android.hardware.neuralnetworks@1.3",
+    ],
+    header_libs: [
+        "libbase_headers",
+    ]
+}
+
+cc_test {
+    name: "VtsHalNeuralnetworksV1_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "BasicTests.cpp",
+        "CompilationCachingTests.cpp",
+        "GeneratedTestHarness.cpp",
+        "TestAssertions.cpp",
+        "ValidateBurst.cpp",
+        "ValidateModel.cpp",
+        "ValidateRequest.cpp",
+        "VtsHalNeuralnetworks.cpp",
+    ],
+    shared_libs: [
+        "libfmq",
+        "libnativewindow",
+    ],
+    static_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.2",
+        "android.hardware.neuralnetworks@1.3",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libgmock",
+        "libhidlmemory",
+        "libneuralnetworks_generated_test_harness",
+        "libneuralnetworks_utils",
+        "VtsHalNeuralNetworksV1_0_utils",
+        "VtsHalNeuralNetworksV1_2Callbacks",
+        "VtsHalNeuralNetworksV1_3Callbacks",
+    ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+        "neuralnetworks_generated_V1_1_example",
+        "neuralnetworks_generated_V1_2_example",
+        "neuralnetworks_generated_V1_3_example",
+    ],
+    header_libs: [
+        "libneuralnetworks_headers",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp
new file mode 100644
index 0000000..b64dc2f
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using V1_0::DeviceStatus;
+using V1_0::ErrorStatus;
+using V1_0::PerformanceInfo;
+using V1_2::Constant;
+using V1_2::DeviceType;
+using V1_2::Extension;
+
+// create device test
+TEST_P(NeuralnetworksHidlTest, CreateDevice) {}
+
+// status test
+TEST_P(NeuralnetworksHidlTest, StatusTest) {
+    Return<DeviceStatus> status = kDevice->getStatus();
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
+}
+
+// initialization
+TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+    using OperandPerformance = Capabilities::OperandPerformance;
+    Return<void> ret = kDevice->getCapabilities_1_3([](ErrorStatus status,
+                                                       const Capabilities& capabilities) {
+        EXPECT_EQ(ErrorStatus::NONE, status);
+
+        auto isPositive = [](const PerformanceInfo& perf) {
+            return perf.execTime > 0.0f && perf.powerUsage > 0.0f;
+        };
+
+        EXPECT_TRUE(isPositive(capabilities.relaxedFloat32toFloat16PerformanceScalar));
+        EXPECT_TRUE(isPositive(capabilities.relaxedFloat32toFloat16PerformanceTensor));
+        const auto& opPerf = capabilities.operandPerformance;
+        EXPECT_TRUE(std::all_of(
+                opPerf.begin(), opPerf.end(),
+                [isPositive](const OperandPerformance& a) { return isPositive(a.info); }));
+        EXPECT_TRUE(std::is_sorted(opPerf.begin(), opPerf.end(),
+                                   [](const OperandPerformance& a, const OperandPerformance& b) {
+                                       return a.type < b.type;
+                                   }));
+    });
+    EXPECT_TRUE(ret.isOk());
+}
+}  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/Callbacks.cpp b/neuralnetworks/1.3/vts/functional/Callbacks.cpp
new file mode 100644
index 0000000..4f08e72
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/Callbacks.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 "Callbacks"
+
+#include "1.3/Callbacks.h"
+
+#include <android-base/logging.h>
+
+#include <limits>
+
+namespace android::hardware::neuralnetworks::V1_3::implementation {
+
+using V1_0::ErrorStatus;
+
+// PreparedModelCallback methods begin here
+
+Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
+                                           const sp<V1_0::IPreparedModel>& preparedModel) {
+    {
+        std::lock_guard<std::mutex> hold(mMutex);
+
+        // quick-return if object has already been notified
+        if (mNotified) {
+            return Void();
+        }
+
+        // store results and mark as notified
+        mErrorStatus = errorStatus;
+        mPreparedModel = preparedModel;
+        mNotified = true;
+    }
+
+    mCondition.notify_all();
+    return Void();
+}
+
+Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus,
+                                               const sp<V1_2::IPreparedModel>& preparedModel) {
+    return notify(errorStatus, preparedModel);
+}
+
+Return<void> PreparedModelCallback::notify_1_3(ErrorStatus errorStatus,
+                                               const sp<V1_3::IPreparedModel>& preparedModel) {
+    return notify(errorStatus, preparedModel);
+}
+
+void PreparedModelCallback::wait() const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    mCondition.wait(lock, [this] { return mNotified; });
+}
+
+ErrorStatus PreparedModelCallback::getStatus() const {
+    wait();
+    return mErrorStatus;
+}
+
+sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() const {
+    wait();
+    return mPreparedModel;
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::implementation
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
new file mode 100644
index 0000000..60992d5
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -0,0 +1,1362 @@
+/*
+ * 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 "neuralnetworks_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <gtest/gtest.h>
+#include <hidlmemory/mapping.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <random>
+#include <thread>
+
+#include "1.3/Callbacks.h"
+#include "GeneratedTestHarness.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
+
+// Forward declaration of the mobilenet generated test models in
+// frameworks/ml/nn/runtime/test/generated/.
+namespace generated_tests::mobilenet_224_gender_basic_fixed {
+const test_helper::TestModel& get_test_model();
+}  // namespace generated_tests::mobilenet_224_gender_basic_fixed
+
+namespace generated_tests::mobilenet_quantized {
+const test_helper::TestModel& get_test_model();
+}  // namespace generated_tests::mobilenet_quantized
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using namespace test_helper;
+using implementation::PreparedModelCallback;
+using V1_0::ErrorStatus;
+using V1_1::ExecutionPreference;
+using V1_2::Constant;
+using V1_2::OperationType;
+
+namespace float32_model {
+
+constexpr auto get_test_model = generated_tests::mobilenet_224_gender_basic_fixed::get_test_model;
+
+}  // namespace float32_model
+
+namespace quant8_model {
+
+constexpr auto get_test_model = generated_tests::mobilenet_quantized::get_test_model;
+
+}  // namespace quant8_model
+
+namespace {
+
+enum class AccessMode { READ_WRITE, READ_ONLY, WRITE_ONLY };
+
+// Creates cache handles based on provided file groups.
+// The outer vector corresponds to handles and the inner vector is for fds held by each handle.
+void createCacheHandles(const std::vector<std::vector<std::string>>& fileGroups,
+                        const std::vector<AccessMode>& mode, hidl_vec<hidl_handle>* handles) {
+    handles->resize(fileGroups.size());
+    for (uint32_t i = 0; i < fileGroups.size(); i++) {
+        std::vector<int> fds;
+        for (const auto& file : fileGroups[i]) {
+            int fd;
+            if (mode[i] == AccessMode::READ_ONLY) {
+                fd = open(file.c_str(), O_RDONLY);
+            } else if (mode[i] == AccessMode::WRITE_ONLY) {
+                fd = open(file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+            } else if (mode[i] == AccessMode::READ_WRITE) {
+                fd = open(file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+            } else {
+                FAIL();
+            }
+            ASSERT_GE(fd, 0);
+            fds.push_back(fd);
+        }
+        native_handle_t* cacheNativeHandle = native_handle_create(fds.size(), 0);
+        ASSERT_NE(cacheNativeHandle, nullptr);
+        std::copy(fds.begin(), fds.end(), &cacheNativeHandle->data[0]);
+        (*handles)[i].setTo(cacheNativeHandle, /*shouldOwn=*/true);
+    }
+}
+
+void createCacheHandles(const std::vector<std::vector<std::string>>& fileGroups, AccessMode mode,
+                        hidl_vec<hidl_handle>* handles) {
+    createCacheHandles(fileGroups, std::vector<AccessMode>(fileGroups.size(), mode), handles);
+}
+
+// Create a chain of broadcast operations. The second operand is always constant tensor [1].
+// For simplicity, activation scalar is shared. The second operand is not shared
+// in the model to let driver maintain a non-trivial size of constant data and the corresponding
+// data locations in cache.
+//
+//                --------- activation --------
+//                ↓      ↓      ↓             ↓
+// E.g. input -> ADD -> ADD -> ADD -> ... -> ADD -> output
+//                ↑      ↑      ↑             ↑
+//               [1]    [1]    [1]           [1]
+//
+// This function assumes the operation is either ADD or MUL.
+template <typename CppType, TestOperandType operandType>
+TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) {
+    EXPECT_TRUE(op == TestOperationType::ADD || op == TestOperationType::MUL);
+
+    // Model operations and operands.
+    std::vector<TestOperation> operations(len);
+    std::vector<TestOperand> operands(len * 2 + 2);
+
+    // The activation scalar, value = 0.
+    operands[0] = {
+            .type = TestOperandType::INT32,
+            .dimensions = {},
+            .numberOfConsumers = len,
+            .scale = 0.0f,
+            .zeroPoint = 0,
+            .lifetime = TestOperandLifeTime::CONSTANT_COPY,
+            .data = TestBuffer::createFromVector<int32_t>({0}),
+    };
+
+    // The buffer value of the constant second operand. The logical value is always 1.0f.
+    CppType bufferValue;
+    // The scale of the first and second operand.
+    float scale1, scale2;
+    if (operandType == TestOperandType::TENSOR_FLOAT32) {
+        bufferValue = 1.0f;
+        scale1 = 0.0f;
+        scale2 = 0.0f;
+    } else if (op == TestOperationType::ADD) {
+        bufferValue = 1;
+        scale1 = 1.0f;
+        scale2 = 1.0f;
+    } else {
+        // To satisfy the constraint on quant8 MUL: input0.scale * input1.scale < output.scale,
+        // set input1 to have scale = 0.5f and bufferValue = 2, i.e. 1.0f in floating point.
+        bufferValue = 2;
+        scale1 = 1.0f;
+        scale2 = 0.5f;
+    }
+
+    for (uint32_t i = 0; i < len; i++) {
+        const uint32_t firstInputIndex = i * 2 + 1;
+        const uint32_t secondInputIndex = firstInputIndex + 1;
+        const uint32_t outputIndex = secondInputIndex + 1;
+
+        // The first operation input.
+        operands[firstInputIndex] = {
+                .type = operandType,
+                .dimensions = {1},
+                .numberOfConsumers = 1,
+                .scale = scale1,
+                .zeroPoint = 0,
+                .lifetime = (i == 0 ? TestOperandLifeTime::MODEL_INPUT
+                                    : TestOperandLifeTime::TEMPORARY_VARIABLE),
+                .data = (i == 0 ? TestBuffer::createFromVector<CppType>({1}) : TestBuffer()),
+        };
+
+        // The second operation input, value = 1.
+        operands[secondInputIndex] = {
+                .type = operandType,
+                .dimensions = {1},
+                .numberOfConsumers = 1,
+                .scale = scale2,
+                .zeroPoint = 0,
+                .lifetime = TestOperandLifeTime::CONSTANT_COPY,
+                .data = TestBuffer::createFromVector<CppType>({bufferValue}),
+        };
+
+        // The operation. All operations share the same activation scalar.
+        // The output operand is created as an input in the next iteration of the loop, in the case
+        // of all but the last member of the chain; and after the loop as a model output, in the
+        // case of the last member of the chain.
+        operations[i] = {
+                .type = op,
+                .inputs = {firstInputIndex, secondInputIndex, /*activation scalar*/ 0},
+                .outputs = {outputIndex},
+        };
+    }
+
+    // For TestOperationType::ADD, output = 1 + 1 * len = len + 1
+    // For TestOperationType::MUL, output = 1 * 1 ^ len = 1
+    CppType outputResult = static_cast<CppType>(op == TestOperationType::ADD ? len + 1u : 1u);
+
+    // The model output.
+    operands.back() = {
+            .type = operandType,
+            .dimensions = {1},
+            .numberOfConsumers = 0,
+            .scale = scale1,
+            .zeroPoint = 0,
+            .lifetime = TestOperandLifeTime::MODEL_OUTPUT,
+            .data = TestBuffer::createFromVector<CppType>({outputResult}),
+    };
+
+    return {
+            .operands = std::move(operands),
+            .operations = std::move(operations),
+            .inputIndexes = {1},
+            .outputIndexes = {len * 2 + 1},
+            .isRelaxed = false,
+    };
+}
+
+}  // namespace
+
+// Tag for the compilation caching tests.
+class CompilationCachingTestBase : public testing::Test {
+  protected:
+    CompilationCachingTestBase(sp<IDevice> device, OperandType type)
+        : kDevice(std::move(device)), kOperandType(type) {}
+
+    void SetUp() override {
+        testing::Test::SetUp();
+        ASSERT_NE(kDevice.get(), nullptr);
+
+        // Create cache directory. The cache directory and a temporary cache file is always created
+        // to test the behavior of prepareModelFromCache_1_3, even when caching is not supported.
+        char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX";
+        char* cacheDir = mkdtemp(cacheDirTemp);
+        ASSERT_NE(cacheDir, nullptr);
+        mCacheDir = cacheDir;
+        mCacheDir.push_back('/');
+
+        Return<void> ret = kDevice->getNumberOfCacheFilesNeeded(
+                [this](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) {
+                    EXPECT_EQ(ErrorStatus::NONE, status);
+                    mNumModelCache = numModelCache;
+                    mNumDataCache = numDataCache;
+                });
+        EXPECT_TRUE(ret.isOk());
+        mIsCachingSupported = mNumModelCache > 0 || mNumDataCache > 0;
+
+        // Create empty cache files.
+        mTmpCache = mCacheDir + "tmp";
+        for (uint32_t i = 0; i < mNumModelCache; i++) {
+            mModelCache.push_back({mCacheDir + "model" + std::to_string(i)});
+        }
+        for (uint32_t i = 0; i < mNumDataCache; i++) {
+            mDataCache.push_back({mCacheDir + "data" + std::to_string(i)});
+        }
+        // Dummy handles, use AccessMode::WRITE_ONLY for createCacheHandles to create files.
+        hidl_vec<hidl_handle> modelHandle, dataHandle, tmpHandle;
+        createCacheHandles(mModelCache, AccessMode::WRITE_ONLY, &modelHandle);
+        createCacheHandles(mDataCache, AccessMode::WRITE_ONLY, &dataHandle);
+        createCacheHandles({{mTmpCache}}, AccessMode::WRITE_ONLY, &tmpHandle);
+
+        if (!mIsCachingSupported) {
+            LOG(INFO) << "NN VTS: Early termination of test because vendor service does not "
+                         "support compilation caching.";
+            std::cout << "[          ]   Early termination of test because vendor service does not "
+                         "support compilation caching."
+                      << std::endl;
+        }
+    }
+
+    void TearDown() override {
+        // If the test passes, remove the tmp directory.  Otherwise, keep it for debugging purposes.
+        if (!testing::Test::HasFailure()) {
+            // Recursively remove the cache directory specified by mCacheDir.
+            auto callback = [](const char* entry, const struct stat*, int, struct FTW*) {
+                return remove(entry);
+            };
+            nftw(mCacheDir.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
+        }
+        testing::Test::TearDown();
+    }
+
+    // Model and examples creators. According to kOperandType, the following methods will return
+    // either float32 model/examples or the quant8 variant.
+    TestModel createTestModel() {
+        if (kOperandType == OperandType::TENSOR_FLOAT32) {
+            return float32_model::get_test_model();
+        } else {
+            return quant8_model::get_test_model();
+        }
+    }
+
+    TestModel createLargeTestModel(OperationType op, uint32_t len) {
+        if (kOperandType == OperandType::TENSOR_FLOAT32) {
+            return createLargeTestModelImpl<float, TestOperandType::TENSOR_FLOAT32>(
+                    static_cast<TestOperationType>(op), len);
+        } else {
+            return createLargeTestModelImpl<uint8_t, TestOperandType::TENSOR_QUANT8_ASYMM>(
+                    static_cast<TestOperationType>(op), len);
+        }
+    }
+
+    // See if the service can handle the model.
+    bool isModelFullySupported(const Model& model) {
+        bool fullySupportsModel = false;
+        Return<void> supportedCall = kDevice->getSupportedOperations_1_3(
+                model,
+                [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec<bool>& supported) {
+                    ASSERT_EQ(ErrorStatus::NONE, status);
+                    ASSERT_EQ(supported.size(), model.operations.size());
+                    fullySupportsModel = std::all_of(supported.begin(), supported.end(),
+                                                     [](bool valid) { return valid; });
+                });
+        EXPECT_TRUE(supportedCall.isOk());
+        return fullySupportsModel;
+    }
+
+    void saveModelToCache(const Model& model, const hidl_vec<hidl_handle>& modelCache,
+                          const hidl_vec<hidl_handle>& dataCache,
+                          sp<IPreparedModel>* preparedModel = nullptr) {
+        if (preparedModel != nullptr) *preparedModel = nullptr;
+
+        // Launch prepare model.
+        sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+        hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
+        Return<ErrorStatus> prepareLaunchStatus =
+                kDevice->prepareModel_1_3(model, ExecutionPreference::FAST_SINGLE_ANSWER,
+                                          modelCache, dataCache, cacheToken, preparedModelCallback);
+        ASSERT_TRUE(prepareLaunchStatus.isOk());
+        ASSERT_EQ(static_cast<ErrorStatus>(prepareLaunchStatus), ErrorStatus::NONE);
+
+        // Retrieve prepared model.
+        preparedModelCallback->wait();
+        ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE);
+        if (preparedModel != nullptr) {
+            *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
+                                     .withDefault(nullptr);
+        }
+    }
+
+    bool checkEarlyTermination(ErrorStatus status) {
+        if (status == ErrorStatus::GENERAL_FAILURE) {
+            LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                         "save the prepared model that it does not support.";
+            std::cout << "[          ]   Early termination of test because vendor service cannot "
+                         "save the prepared model that it does not support."
+                      << std::endl;
+            return true;
+        }
+        return false;
+    }
+
+    bool checkEarlyTermination(const Model& model) {
+        if (!isModelFullySupported(model)) {
+            LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                         "prepare model that it does not support.";
+            std::cout << "[          ]   Early termination of test because vendor service cannot "
+                         "prepare model that it does not support."
+                      << std::endl;
+            return true;
+        }
+        return false;
+    }
+
+    void prepareModelFromCache(const hidl_vec<hidl_handle>& modelCache,
+                               const hidl_vec<hidl_handle>& dataCache,
+                               sp<IPreparedModel>* preparedModel, ErrorStatus* status) {
+        // Launch prepare model from cache.
+        sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+        hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
+        Return<ErrorStatus> prepareLaunchStatus = kDevice->prepareModelFromCache_1_3(
+                modelCache, dataCache, cacheToken, preparedModelCallback);
+        ASSERT_TRUE(prepareLaunchStatus.isOk());
+        if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) {
+            *preparedModel = nullptr;
+            *status = static_cast<ErrorStatus>(prepareLaunchStatus);
+            return;
+        }
+
+        // Retrieve prepared model.
+        preparedModelCallback->wait();
+        *status = preparedModelCallback->getStatus();
+        *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
+                                 .withDefault(nullptr);
+    }
+
+    // Absolute path to the temporary cache directory.
+    std::string mCacheDir;
+
+    // Groups of file paths for model and data cache in the tmp cache directory, initialized with
+    // outer_size = mNum{Model|Data}Cache, inner_size = 1. The outer vector corresponds to handles
+    // and the inner vector is for fds held by each handle.
+    std::vector<std::vector<std::string>> mModelCache;
+    std::vector<std::vector<std::string>> mDataCache;
+
+    // A separate temporary file path in the tmp cache directory.
+    std::string mTmpCache;
+
+    uint8_t mToken[static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)] = {};
+    uint32_t mNumModelCache;
+    uint32_t mNumDataCache;
+    uint32_t mIsCachingSupported;
+
+    const sp<IDevice> kDevice;
+    // The primary data type of the testModel.
+    const OperandType kOperandType;
+};
+
+using CompilationCachingTestParam = std::tuple<NamedDevice, OperandType>;
+
+// A parameterized fixture of CompilationCachingTestBase. Every test will run twice, with the first
+// pass running with float32 models and the second pass running with quant8 models.
+class CompilationCachingTest : public CompilationCachingTestBase,
+                               public testing::WithParamInterface<CompilationCachingTestParam> {
+  protected:
+    CompilationCachingTest()
+        : CompilationCachingTestBase(getData(std::get<NamedDevice>(GetParam())),
+                                     std::get<OperandType>(GetParam())) {}
+};
+
+TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) {
+    // Create test HIDL model and compile.
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
+    sp<IPreparedModel> preparedModel = nullptr;
+
+    // Save the compilation to cache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(model, modelCache, dataCache);
+    }
+
+    // Retrieve preparedModel from cache.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (!mIsCachingSupported) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+            ASSERT_EQ(preparedModel, nullptr);
+            return;
+        } else if (checkEarlyTermination(status)) {
+            ASSERT_EQ(preparedModel, nullptr);
+            return;
+        } else {
+            ASSERT_EQ(status, ErrorStatus::NONE);
+            ASSERT_NE(preparedModel, nullptr);
+        }
+    }
+
+    // Execute and verify results.
+    EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+}
+
+TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
+    // Create test HIDL model and compile.
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
+    sp<IPreparedModel> preparedModel = nullptr;
+
+    // Save the compilation to cache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        uint8_t dummyBytes[] = {0, 0};
+        // Write a dummy integer to the cache.
+        // The driver should be able to handle non-empty cache and non-zero fd offset.
+        for (uint32_t i = 0; i < modelCache.size(); i++) {
+            ASSERT_EQ(write(modelCache[i].getNativeHandle()->data[0], &dummyBytes,
+                            sizeof(dummyBytes)),
+                      sizeof(dummyBytes));
+        }
+        for (uint32_t i = 0; i < dataCache.size(); i++) {
+            ASSERT_EQ(
+                    write(dataCache[i].getNativeHandle()->data[0], &dummyBytes, sizeof(dummyBytes)),
+                    sizeof(dummyBytes));
+        }
+        saveModelToCache(model, modelCache, dataCache);
+    }
+
+    // Retrieve preparedModel from cache.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        uint8_t dummyByte = 0;
+        // Advance the offset of each handle by one byte.
+        // The driver should be able to handle non-zero fd offset.
+        for (uint32_t i = 0; i < modelCache.size(); i++) {
+            ASSERT_GE(read(modelCache[i].getNativeHandle()->data[0], &dummyByte, 1), 0);
+        }
+        for (uint32_t i = 0; i < dataCache.size(); i++) {
+            ASSERT_GE(read(dataCache[i].getNativeHandle()->data[0], &dummyByte, 1), 0);
+        }
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (!mIsCachingSupported) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+            ASSERT_EQ(preparedModel, nullptr);
+            return;
+        } else if (checkEarlyTermination(status)) {
+            ASSERT_EQ(preparedModel, nullptr);
+            return;
+        } else {
+            ASSERT_EQ(status, ErrorStatus::NONE);
+            ASSERT_NE(preparedModel, nullptr);
+        }
+    }
+
+    // Execute and verify results.
+    EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+}
+
+TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) {
+    // Create test HIDL model and compile.
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
+
+    // Test with number of model cache files greater than mNumModelCache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an additional cache file for model cache.
+        mModelCache.push_back({mTmpCache});
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache.pop_back();
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of model cache files smaller than mNumModelCache.
+    if (mModelCache.size() > 0) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pop out the last cache file.
+        auto tmp = mModelCache.back();
+        mModelCache.pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache.push_back(tmp);
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of data cache files greater than mNumDataCache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an additional cache file for data cache.
+        mDataCache.push_back({mTmpCache});
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache.pop_back();
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of data cache files smaller than mNumDataCache.
+    if (mDataCache.size() > 0) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pop out the last cache file.
+        auto tmp = mDataCache.back();
+        mDataCache.pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache.push_back(tmp);
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumCache) {
+    // Create test HIDL model and compile.
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
+
+    // Save the compilation to cache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(model, modelCache, dataCache);
+    }
+
+    // Test with number of model cache files greater than mNumModelCache.
+    {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        mModelCache.push_back({mTmpCache});
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache.pop_back();
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of model cache files smaller than mNumModelCache.
+    if (mModelCache.size() > 0) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        auto tmp = mModelCache.back();
+        mModelCache.pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache.push_back(tmp);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of data cache files greater than mNumDataCache.
+    {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        mDataCache.push_back({mTmpCache});
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache.pop_back();
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of data cache files smaller than mNumDataCache.
+    if (mDataCache.size() > 0) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        auto tmp = mDataCache.back();
+        mDataCache.pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache.push_back(tmp);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) {
+    // Create test HIDL model and compile.
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
+
+    // Go through each handle in model cache, test with NumFd greater than 1.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an invalid number of fds for handle i.
+        mModelCache[i].push_back(mTmpCache);
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache[i].pop_back();
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in model cache, test with NumFd equal to 0.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an invalid number of fds for handle i.
+        auto tmp = mModelCache[i].back();
+        mModelCache[i].pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache[i].push_back(tmp);
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with NumFd greater than 1.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an invalid number of fds for handle i.
+        mDataCache[i].push_back(mTmpCache);
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache[i].pop_back();
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with NumFd equal to 0.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an invalid number of fds for handle i.
+        auto tmp = mDataCache[i].back();
+        mDataCache[i].pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache[i].push_back(tmp);
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) {
+    // Create test HIDL model and compile.
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
+
+    // Save the compilation to cache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(model, modelCache, dataCache);
+    }
+
+    // Go through each handle in model cache, test with NumFd greater than 1.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        mModelCache[i].push_back(mTmpCache);
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache[i].pop_back();
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in model cache, test with NumFd equal to 0.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        auto tmp = mModelCache[i].back();
+        mModelCache[i].pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache[i].push_back(tmp);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with NumFd greater than 1.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        mDataCache[i].push_back(mTmpCache);
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache[i].pop_back();
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with NumFd equal to 0.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        auto tmp = mDataCache[i].back();
+        mDataCache[i].pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache[i].push_back(tmp);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) {
+    // Create test HIDL model and compile.
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
+    std::vector<AccessMode> modelCacheMode(mNumModelCache, AccessMode::READ_WRITE);
+    std::vector<AccessMode> dataCacheMode(mNumDataCache, AccessMode::READ_WRITE);
+
+    // Go through each handle in model cache, test with invalid access mode.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        modelCacheMode[i] = AccessMode::READ_ONLY;
+        createCacheHandles(mModelCache, modelCacheMode, &modelCache);
+        createCacheHandles(mDataCache, dataCacheMode, &dataCache);
+        modelCacheMode[i] = AccessMode::READ_WRITE;
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with invalid access mode.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        dataCacheMode[i] = AccessMode::READ_ONLY;
+        createCacheHandles(mModelCache, modelCacheMode, &modelCache);
+        createCacheHandles(mDataCache, dataCacheMode, &dataCache);
+        dataCacheMode[i] = AccessMode::READ_WRITE;
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(model, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) {
+    // Create test HIDL model and compile.
+    const TestModel& testModel = createTestModel();
+    const Model model = createModel(testModel);
+    if (checkEarlyTermination(model)) return;
+    std::vector<AccessMode> modelCacheMode(mNumModelCache, AccessMode::READ_WRITE);
+    std::vector<AccessMode> dataCacheMode(mNumDataCache, AccessMode::READ_WRITE);
+
+    // Save the compilation to cache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(model, modelCache, dataCache);
+    }
+
+    // Go through each handle in model cache, test with invalid access mode.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        modelCacheMode[i] = AccessMode::WRITE_ONLY;
+        createCacheHandles(mModelCache, modelCacheMode, &modelCache);
+        createCacheHandles(mDataCache, dataCacheMode, &dataCache);
+        modelCacheMode[i] = AccessMode::READ_WRITE;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with invalid access mode.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        dataCacheMode[i] = AccessMode::WRITE_ONLY;
+        createCacheHandles(mModelCache, modelCacheMode, &modelCache);
+        createCacheHandles(mDataCache, dataCacheMode, &dataCache);
+        dataCacheMode[i] = AccessMode::READ_WRITE;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+// Copy file contents between file groups.
+// The outer vector corresponds to handles and the inner vector is for fds held by each handle.
+// The outer vector sizes must match and the inner vectors must have size = 1.
+static void copyCacheFiles(const std::vector<std::vector<std::string>>& from,
+                           const std::vector<std::vector<std::string>>& to) {
+    constexpr size_t kBufferSize = 1000000;
+    uint8_t buffer[kBufferSize];
+
+    ASSERT_EQ(from.size(), to.size());
+    for (uint32_t i = 0; i < from.size(); i++) {
+        ASSERT_EQ(from[i].size(), 1u);
+        ASSERT_EQ(to[i].size(), 1u);
+        int fromFd = open(from[i][0].c_str(), O_RDONLY);
+        int toFd = open(to[i][0].c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+        ASSERT_GE(fromFd, 0);
+        ASSERT_GE(toFd, 0);
+
+        ssize_t readBytes;
+        while ((readBytes = read(fromFd, &buffer, kBufferSize)) > 0) {
+            ASSERT_EQ(write(toFd, &buffer, readBytes), readBytes);
+        }
+        ASSERT_GE(readBytes, 0);
+
+        close(fromFd);
+        close(toFd);
+    }
+}
+
+// Number of operations in the large test model.
+constexpr uint32_t kLargeModelSize = 100;
+constexpr uint32_t kNumIterationsTOCTOU = 100;
+
+TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) {
+    if (!mIsCachingSupported) return;
+
+    // Create test models and check if fully supported by the service.
+    const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
+    const Model modelMul = createModel(testModelMul);
+    if (checkEarlyTermination(modelMul)) return;
+    const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
+    const Model modelAdd = createModel(testModelAdd);
+    if (checkEarlyTermination(modelAdd)) return;
+
+    // Save the modelMul compilation to cache.
+    auto modelCacheMul = mModelCache;
+    for (auto& cache : modelCacheMul) {
+        cache[0].append("_mul");
+    }
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(modelMul, modelCache, dataCache);
+    }
+
+    // Use a different token for modelAdd.
+    mToken[0]++;
+
+    // This test is probabilistic, so we run it multiple times.
+    for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+        // Save the modelAdd compilation to cache.
+        {
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+
+            // Spawn a thread to copy the cache content concurrently while saving to cache.
+            std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
+            saveModelToCache(modelAdd, modelCache, dataCache);
+            thread.join();
+        }
+
+        // Retrieve preparedModel from cache.
+        {
+            sp<IPreparedModel> preparedModel = nullptr;
+            ErrorStatus status;
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+
+            // The preparation may fail or succeed, but must not crash. If the preparation succeeds,
+            // the prepared model must be executed with the correct result and not crash.
+            if (status != ErrorStatus::NONE) {
+                ASSERT_EQ(preparedModel, nullptr);
+            } else {
+                ASSERT_NE(preparedModel, nullptr);
+                EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL);
+            }
+        }
+    }
+}
+
+TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) {
+    if (!mIsCachingSupported) return;
+
+    // Create test models and check if fully supported by the service.
+    const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
+    const Model modelMul = createModel(testModelMul);
+    if (checkEarlyTermination(modelMul)) return;
+    const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
+    const Model modelAdd = createModel(testModelAdd);
+    if (checkEarlyTermination(modelAdd)) return;
+
+    // Save the modelMul compilation to cache.
+    auto modelCacheMul = mModelCache;
+    for (auto& cache : modelCacheMul) {
+        cache[0].append("_mul");
+    }
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(modelMul, modelCache, dataCache);
+    }
+
+    // Use a different token for modelAdd.
+    mToken[0]++;
+
+    // This test is probabilistic, so we run it multiple times.
+    for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+        // Save the modelAdd compilation to cache.
+        {
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+            saveModelToCache(modelAdd, modelCache, dataCache);
+        }
+
+        // Retrieve preparedModel from cache.
+        {
+            sp<IPreparedModel> preparedModel = nullptr;
+            ErrorStatus status;
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+
+            // Spawn a thread to copy the cache content concurrently while preparing from cache.
+            std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
+            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+            thread.join();
+
+            // The preparation may fail or succeed, but must not crash. If the preparation succeeds,
+            // the prepared model must be executed with the correct result and not crash.
+            if (status != ErrorStatus::NONE) {
+                ASSERT_EQ(preparedModel, nullptr);
+            } else {
+                ASSERT_NE(preparedModel, nullptr);
+                EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL);
+            }
+        }
+    }
+}
+
+TEST_P(CompilationCachingTest, ReplaceSecuritySensitiveCache) {
+    if (!mIsCachingSupported) return;
+
+    // Create test models and check if fully supported by the service.
+    const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
+    const Model modelMul = createModel(testModelMul);
+    if (checkEarlyTermination(modelMul)) return;
+    const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
+    const Model modelAdd = createModel(testModelAdd);
+    if (checkEarlyTermination(modelAdd)) return;
+
+    // Save the modelMul compilation to cache.
+    auto modelCacheMul = mModelCache;
+    for (auto& cache : modelCacheMul) {
+        cache[0].append("_mul");
+    }
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(modelMul, modelCache, dataCache);
+    }
+
+    // Use a different token for modelAdd.
+    mToken[0]++;
+
+    // Save the modelAdd compilation to cache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(modelAdd, modelCache, dataCache);
+    }
+
+    // Replace the model cache of modelAdd with modelMul.
+    copyCacheFiles(modelCacheMul, mModelCache);
+
+    // Retrieve the preparedModel from cache, expect failure.
+    {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+static const auto kNamedDeviceChoices = testing::ValuesIn(getNamedDevices());
+static const auto kOperandTypeChoices =
+        testing::Values(OperandType::TENSOR_FLOAT32, OperandType::TENSOR_QUANT8_ASYMM);
+
+std::string printCompilationCachingTest(
+        const testing::TestParamInfo<CompilationCachingTestParam>& info) {
+    const auto& [namedDevice, operandType] = info.param;
+    const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8");
+    return gtestCompliantName(getName(namedDevice) + "_" + type);
+}
+
+INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest,
+                        testing::Combine(kNamedDeviceChoices, kOperandTypeChoices),
+                        printCompilationCachingTest);
+
+using CompilationCachingSecurityTestParam = std::tuple<NamedDevice, OperandType, uint32_t>;
+
+class CompilationCachingSecurityTest
+    : public CompilationCachingTestBase,
+      public testing::WithParamInterface<CompilationCachingSecurityTestParam> {
+  protected:
+    CompilationCachingSecurityTest()
+        : CompilationCachingTestBase(getData(std::get<NamedDevice>(GetParam())),
+                                     std::get<OperandType>(GetParam())) {}
+
+    void SetUp() {
+        CompilationCachingTestBase::SetUp();
+        generator.seed(kSeed);
+    }
+
+    // Get a random integer within a closed range [lower, upper].
+    template <typename T>
+    T getRandomInt(T lower, T upper) {
+        std::uniform_int_distribution<T> dis(lower, upper);
+        return dis(generator);
+    }
+
+    // Randomly flip one single bit of the cache entry.
+    void flipOneBitOfCache(const std::string& filename, bool* skip) {
+        FILE* pFile = fopen(filename.c_str(), "r+");
+        ASSERT_EQ(fseek(pFile, 0, SEEK_END), 0);
+        long int fileSize = ftell(pFile);
+        if (fileSize == 0) {
+            fclose(pFile);
+            *skip = true;
+            return;
+        }
+        ASSERT_EQ(fseek(pFile, getRandomInt(0l, fileSize - 1), SEEK_SET), 0);
+        int readByte = fgetc(pFile);
+        ASSERT_NE(readByte, EOF);
+        ASSERT_EQ(fseek(pFile, -1, SEEK_CUR), 0);
+        ASSERT_NE(fputc(static_cast<uint8_t>(readByte) ^ (1U << getRandomInt(0, 7)), pFile), EOF);
+        fclose(pFile);
+        *skip = false;
+    }
+
+    // Randomly append bytes to the cache entry.
+    void appendBytesToCache(const std::string& filename, bool* skip) {
+        FILE* pFile = fopen(filename.c_str(), "a");
+        uint32_t appendLength = getRandomInt(1, 256);
+        for (uint32_t i = 0; i < appendLength; i++) {
+            ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+        }
+        fclose(pFile);
+        *skip = false;
+    }
+
+    enum class ExpectedResult { GENERAL_FAILURE, NOT_CRASH };
+
+    // Test if the driver behaves as expected when given corrupted cache or token.
+    // The modifier will be invoked after save to cache but before prepare from cache.
+    // The modifier accepts one pointer argument "skip" as the returning value, indicating
+    // whether the test should be skipped or not.
+    void testCorruptedCache(ExpectedResult expected, std::function<void(bool*)> modifier) {
+        const TestModel& testModel = createTestModel();
+        const Model model = createModel(testModel);
+        if (checkEarlyTermination(model)) return;
+
+        // Save the compilation to cache.
+        {
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+            saveModelToCache(model, modelCache, dataCache);
+        }
+
+        bool skip = false;
+        modifier(&skip);
+        if (skip) return;
+
+        // Retrieve preparedModel from cache.
+        {
+            sp<IPreparedModel> preparedModel = nullptr;
+            ErrorStatus status;
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+
+            switch (expected) {
+                case ExpectedResult::GENERAL_FAILURE:
+                    ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+                    ASSERT_EQ(preparedModel, nullptr);
+                    break;
+                case ExpectedResult::NOT_CRASH:
+                    ASSERT_EQ(preparedModel == nullptr, status != ErrorStatus::NONE);
+                    break;
+                default:
+                    FAIL();
+            }
+        }
+    }
+
+    const uint32_t kSeed = std::get<uint32_t>(GetParam());
+    std::mt19937 generator;
+};
+
+TEST_P(CompilationCachingSecurityTest, CorruptedModelCache) {
+    if (!mIsCachingSupported) return;
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        testCorruptedCache(ExpectedResult::GENERAL_FAILURE,
+                           [this, i](bool* skip) { flipOneBitOfCache(mModelCache[i][0], skip); });
+    }
+}
+
+TEST_P(CompilationCachingSecurityTest, WrongLengthModelCache) {
+    if (!mIsCachingSupported) return;
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        testCorruptedCache(ExpectedResult::GENERAL_FAILURE,
+                           [this, i](bool* skip) { appendBytesToCache(mModelCache[i][0], skip); });
+    }
+}
+
+TEST_P(CompilationCachingSecurityTest, CorruptedDataCache) {
+    if (!mIsCachingSupported) return;
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        testCorruptedCache(ExpectedResult::NOT_CRASH,
+                           [this, i](bool* skip) { flipOneBitOfCache(mDataCache[i][0], skip); });
+    }
+}
+
+TEST_P(CompilationCachingSecurityTest, WrongLengthDataCache) {
+    if (!mIsCachingSupported) return;
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        testCorruptedCache(ExpectedResult::NOT_CRASH,
+                           [this, i](bool* skip) { appendBytesToCache(mDataCache[i][0], skip); });
+    }
+}
+
+TEST_P(CompilationCachingSecurityTest, WrongToken) {
+    if (!mIsCachingSupported) return;
+    testCorruptedCache(ExpectedResult::GENERAL_FAILURE, [this](bool* skip) {
+        // Randomly flip one single bit in mToken.
+        uint32_t ind =
+                getRandomInt(0u, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN) - 1);
+        mToken[ind] ^= (1U << getRandomInt(0, 7));
+        *skip = false;
+    });
+}
+
+std::string printCompilationCachingSecurityTest(
+        const testing::TestParamInfo<CompilationCachingSecurityTestParam>& info) {
+    const auto& [namedDevice, operandType, seed] = info.param;
+    const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8");
+    return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + std::to_string(seed));
+}
+
+INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest,
+                        testing::Combine(kNamedDeviceChoices, kOperandTypeChoices,
+                                         testing::Range(0U, 10U)),
+                        printCompilationCachingSecurityTest);
+
+}  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
new file mode 100644
index 0000000..f61240e
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -0,0 +1,527 @@
+/*
+ * 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 "GeneratedTestHarness.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <gtest/gtest.h>
+#include <hidlmemory/mapping.h>
+
+#include <algorithm>
+#include <chrono>
+#include <iostream>
+#include <numeric>
+#include <vector>
+
+#include "1.0/Utils.h"
+#include "1.2/Callbacks.h"
+#include "1.3/Callbacks.h"
+#include "ExecutionBurstController.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using namespace test_helper;
+using hidl::memory::V1_0::IMemory;
+using implementation::PreparedModelCallback;
+using V1_0::DataLocation;
+using V1_0::ErrorStatus;
+using V1_0::OperandLifeTime;
+using V1_0::Request;
+using V1_1::ExecutionPreference;
+using V1_2::Constant;
+using V1_2::MeasureTiming;
+using V1_2::OutputShape;
+using V1_2::SymmPerChannelQuantParams;
+using V1_2::Timing;
+using V1_2::implementation::ExecutionCallback;
+using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+
+namespace {
+
+enum class Executor { ASYNC, SYNC, BURST };
+
+enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
+
+struct TestConfig {
+    Executor executor;
+    MeasureTiming measureTiming;
+    OutputType outputType;
+    // `reportSkipping` indicates if a test should print an info message in case
+    // it is skipped. The field is set to true by default and is set to false in
+    // quantization coupling tests to suppress skipping a test
+    bool reportSkipping;
+    TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType)
+        : executor(executor),
+          measureTiming(measureTiming),
+          outputType(outputType),
+          reportSkipping(true) {}
+    TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType,
+               bool reportSkipping)
+        : executor(executor),
+          measureTiming(measureTiming),
+          outputType(outputType),
+          reportSkipping(reportSkipping) {}
+};
+
+}  // namespace
+
+Model createModel(const TestModel& testModel) {
+    // Model operands.
+    hidl_vec<Operand> operands(testModel.operands.size());
+    size_t constCopySize = 0, constRefSize = 0;
+    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+        const auto& op = testModel.operands[i];
+
+        DataLocation loc = {};
+        if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+            loc = {.poolIndex = 0,
+                   .offset = static_cast<uint32_t>(constCopySize),
+                   .length = static_cast<uint32_t>(op.data.size())};
+            constCopySize += op.data.alignedSize();
+        } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+            loc = {.poolIndex = 0,
+                   .offset = static_cast<uint32_t>(constRefSize),
+                   .length = static_cast<uint32_t>(op.data.size())};
+            constRefSize += op.data.alignedSize();
+        }
+
+        Operand::ExtraParams extraParams;
+        if (op.type == TestOperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) {
+            extraParams.channelQuant(SymmPerChannelQuantParams{
+                    .scales = op.channelQuant.scales, .channelDim = op.channelQuant.channelDim});
+        }
+
+        operands[i] = {.type = static_cast<OperandType>(op.type),
+                       .dimensions = op.dimensions,
+                       .numberOfConsumers = op.numberOfConsumers,
+                       .scale = op.scale,
+                       .zeroPoint = op.zeroPoint,
+                       .lifetime = static_cast<OperandLifeTime>(op.lifetime),
+                       .location = loc,
+                       .extraParams = std::move(extraParams)};
+    }
+
+    // Model operations.
+    hidl_vec<Operation> operations(testModel.operations.size());
+    std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
+                   [](const TestOperation& op) -> Operation {
+                       return {.type = static_cast<OperationType>(op.type),
+                               .inputs = op.inputs,
+                               .outputs = op.outputs};
+                   });
+
+    // Constant copies.
+    hidl_vec<uint8_t> operandValues(constCopySize);
+    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+        const auto& op = testModel.operands[i];
+        if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+            const uint8_t* begin = op.data.get<uint8_t>();
+            const uint8_t* end = begin + op.data.size();
+            std::copy(begin, end, operandValues.data() + operands[i].location.offset);
+        }
+    }
+
+    // Shared memory.
+    hidl_vec<hidl_memory> pools = {};
+    if (constRefSize > 0) {
+        hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize));
+        CHECK_NE(pools[0].size(), 0u);
+
+        // load data
+        sp<IMemory> mappedMemory = mapMemory(pools[0]);
+        CHECK(mappedMemory.get() != nullptr);
+        uint8_t* mappedPtr =
+                reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
+        CHECK(mappedPtr != nullptr);
+
+        for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+            const auto& op = testModel.operands[i];
+            if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+                const uint8_t* begin = op.data.get<uint8_t>();
+                const uint8_t* end = begin + op.data.size();
+                std::copy(begin, end, mappedPtr + operands[i].location.offset);
+            }
+        }
+    }
+
+    return {.operands = std::move(operands),
+            .operations = std::move(operations),
+            .inputIndexes = testModel.inputIndexes,
+            .outputIndexes = testModel.outputIndexes,
+            .operandValues = std::move(operandValues),
+            .pools = std::move(pools),
+            .relaxComputationFloat32toFloat16 = testModel.isRelaxed};
+}
+
+static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) {
+    const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size();
+    return byteSize > 1u;
+}
+
+static void makeOutputInsufficientSize(uint32_t outputIndex, Request* request) {
+    auto& length = request->outputs[outputIndex].location.length;
+    ASSERT_GT(length, 1u);
+    length -= 1u;
+}
+
+static void makeOutputDimensionsUnspecified(Model* model) {
+    for (auto i : model->outputIndexes) {
+        auto& dims = model->operands[i].dimensions;
+        std::fill(dims.begin(), dims.end(), 0);
+    }
+}
+
+static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
+                                                const Request& request, MeasureTiming measure,
+                                                sp<ExecutionCallback>& callback) {
+    return preparedModel->execute_1_3(request, measure, callback);
+}
+static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
+                                                const Request& request, MeasureTiming measure,
+                                                hidl_vec<OutputShape>* outputShapes,
+                                                Timing* timing) {
+    ErrorStatus result;
+    Return<void> ret = preparedModel->executeSynchronously(
+            request, measure,
+            [&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
+                                            const Timing& time) {
+                result = error;
+                *outputShapes = shapes;
+                *timing = time;
+            });
+    if (!ret.isOk()) {
+        return ErrorStatus::GENERAL_FAILURE;
+    }
+    return result;
+}
+static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst(
+        const sp<IPreparedModel>& preparedModel) {
+    return android::nn::ExecutionBurstController::create(preparedModel,
+                                                         std::chrono::microseconds{0});
+}
+
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
+                           const TestConfig& testConfig, bool* skipped = nullptr) {
+    if (skipped != nullptr) {
+        *skipped = false;
+    }
+    // If output0 does not have size larger than one byte, we can not test with insufficient buffer.
+    if (testConfig.outputType == OutputType::INSUFFICIENT &&
+        !isOutputSizeGreaterThanOne(testModel, 0)) {
+        return;
+    }
+
+    Request request = createRequest(testModel);
+    if (testConfig.outputType == OutputType::INSUFFICIENT) {
+        makeOutputInsufficientSize(/*outputIndex=*/0, &request);
+    }
+
+    ErrorStatus executionStatus;
+    hidl_vec<OutputShape> outputShapes;
+    Timing timing;
+    switch (testConfig.executor) {
+        case Executor::ASYNC: {
+            SCOPED_TRACE("asynchronous");
+
+            // launch execution
+            sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+            Return<ErrorStatus> executionLaunchStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, executionCallback);
+            ASSERT_TRUE(executionLaunchStatus.isOk());
+            EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
+
+            // retrieve execution status
+            executionCallback->wait();
+            executionStatus = executionCallback->getStatus();
+            outputShapes = executionCallback->getOutputShapes();
+            timing = executionCallback->getTiming();
+
+            break;
+        }
+        case Executor::SYNC: {
+            SCOPED_TRACE("synchronous");
+
+            // execute
+            Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, &outputShapes, &timing);
+            ASSERT_TRUE(executionReturnStatus.isOk());
+            executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
+
+            break;
+        }
+        case Executor::BURST: {
+            SCOPED_TRACE("burst");
+
+            // create burst
+            const std::shared_ptr<::android::nn::ExecutionBurstController> controller =
+                    CreateBurst(preparedModel);
+            ASSERT_NE(nullptr, controller.get());
+
+            // create memory keys
+            std::vector<intptr_t> keys(request.pools.size());
+            for (size_t i = 0; i < keys.size(); ++i) {
+                keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
+            }
+
+            // execute burst
+            int n;
+            std::tie(n, outputShapes, timing, std::ignore) =
+                    controller->compute(request, testConfig.measureTiming, keys);
+            executionStatus = nn::convertResultCodeToErrorStatus(n);
+
+            break;
+        }
+    }
+
+    if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
+        executionStatus == ErrorStatus::GENERAL_FAILURE) {
+        if (skipped != nullptr) {
+            *skipped = true;
+        }
+        if (!testConfig.reportSkipping) {
+            return;
+        }
+        LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                     "execute model that it does not support.";
+        std::cout << "[          ]   Early termination of test because vendor service cannot "
+                     "execute model that it does not support."
+                  << std::endl;
+        GTEST_SKIP();
+    }
+    if (testConfig.measureTiming == MeasureTiming::NO) {
+        EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
+        EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
+    } else {
+        if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) {
+            EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
+        }
+    }
+
+    switch (testConfig.outputType) {
+        case OutputType::FULLY_SPECIFIED:
+            // If the model output operands are fully specified, outputShapes must be either
+            // either empty, or have the same number of elements as the number of outputs.
+            ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+            ASSERT_TRUE(outputShapes.size() == 0 ||
+                        outputShapes.size() == testModel.outputIndexes.size());
+            break;
+        case OutputType::UNSPECIFIED:
+            // If the model output operands are not fully specified, outputShapes must have
+            // the same number of elements as the number of outputs.
+            ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+            ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
+            break;
+        case OutputType::INSUFFICIENT:
+            ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
+            ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
+            ASSERT_FALSE(outputShapes[0].isSufficient);
+            return;
+    }
+
+    // Go through all outputs, check returned output shapes.
+    for (uint32_t i = 0; i < outputShapes.size(); i++) {
+        EXPECT_TRUE(outputShapes[i].isSufficient);
+        const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions;
+        const std::vector<uint32_t> actual = outputShapes[i].dimensions;
+        EXPECT_EQ(expect, actual);
+    }
+
+    // Retrieve execution results.
+    const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+
+    // We want "close-enough" results.
+    checkResults(testModel, outputs);
+}
+
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
+                           TestKind testKind) {
+    std::vector<OutputType> outputTypesList;
+    std::vector<MeasureTiming> measureTimingList;
+    std::vector<Executor> executorList;
+
+    switch (testKind) {
+        case TestKind::GENERAL: {
+            outputTypesList = {OutputType::FULLY_SPECIFIED};
+            measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+            executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+        } break;
+        case TestKind::DYNAMIC_SHAPE: {
+            outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
+            measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+            executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+        } break;
+        case TestKind::QUANTIZATION_COUPLING: {
+            LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel";
+            return;
+        } break;
+    }
+
+    for (const OutputType outputType : outputTypesList) {
+        for (const MeasureTiming measureTiming : measureTimingList) {
+            for (const Executor executor : executorList) {
+                const TestConfig testConfig(executor, measureTiming, outputType);
+                EvaluatePreparedModel(preparedModel, testModel, testConfig);
+            }
+        }
+    }
+}
+
+void EvaluatePreparedCoupledModels(const sp<IPreparedModel>& preparedModel,
+                                   const TestModel& testModel,
+                                   const sp<IPreparedModel>& preparedCoupledModel,
+                                   const TestModel& coupledModel) {
+    const std::vector<OutputType> outputTypesList = {OutputType::FULLY_SPECIFIED};
+    const std::vector<MeasureTiming> measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+    const std::vector<Executor> executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+
+    for (const OutputType outputType : outputTypesList) {
+        for (const MeasureTiming measureTiming : measureTimingList) {
+            for (const Executor executor : executorList) {
+                const TestConfig testConfig(executor, measureTiming, outputType,
+                                            /*reportSkipping=*/false);
+                bool baseSkipped = false;
+                EvaluatePreparedModel(preparedModel, testModel, testConfig, &baseSkipped);
+                bool coupledSkipped = false;
+                EvaluatePreparedModel(preparedCoupledModel, coupledModel, testConfig,
+                                      &coupledSkipped);
+                ASSERT_EQ(baseSkipped, coupledSkipped);
+                if (baseSkipped) {
+                    LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                                 "execute model that it does not support.";
+                    std::cout << "[          ]   Early termination of test because vendor service "
+                                 "cannot "
+                                 "execute model that it does not support."
+                              << std::endl;
+                    GTEST_SKIP();
+                }
+            }
+        }
+    }
+}
+
+void Execute(const sp<IDevice>& device, const TestModel& testModel, TestKind testKind) {
+    Model model = createModel(testModel);
+    if (testKind == TestKind::DYNAMIC_SHAPE) {
+        makeOutputDimensionsUnspecified(&model);
+    }
+
+    sp<IPreparedModel> preparedModel;
+    switch (testKind) {
+        case TestKind::GENERAL: {
+            createPreparedModel(device, model, &preparedModel);
+            if (preparedModel == nullptr) return;
+            EvaluatePreparedModel(preparedModel, testModel, TestKind::GENERAL);
+        } break;
+        case TestKind::DYNAMIC_SHAPE: {
+            createPreparedModel(device, model, &preparedModel);
+            if (preparedModel == nullptr) return;
+            EvaluatePreparedModel(preparedModel, testModel, TestKind::DYNAMIC_SHAPE);
+        } break;
+        case TestKind::QUANTIZATION_COUPLING: {
+            ASSERT_TRUE(testModel.hasQuant8AsymmOperands());
+            createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ false);
+            TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel);
+            sp<IPreparedModel> preparedCoupledModel;
+            createPreparedModel(device, createModel(signedQuantizedModel), &preparedCoupledModel,
+                                /*reportSkipping*/ false);
+            // If we couldn't prepare a model with unsigned quantization, we must
+            // fail to prepare a model with signed quantization as well.
+            if (preparedModel == nullptr) {
+                ASSERT_EQ(preparedCoupledModel, nullptr);
+                // If we failed to prepare both of the models, we can safely skip
+                // the test.
+                LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                             "prepare model that it does not support.";
+                std::cout
+                        << "[          ]   Early termination of test because vendor service cannot "
+                           "prepare model that it does not support."
+                        << std::endl;
+                GTEST_SKIP();
+            }
+            ASSERT_NE(preparedCoupledModel, nullptr);
+            EvaluatePreparedCoupledModels(preparedModel, testModel, preparedCoupledModel,
+                                          signedQuantizedModel);
+        } break;
+    }
+}
+
+void GeneratedTestBase::SetUp() {
+    testing::TestWithParam<GeneratedTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
+}
+
+std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
+}
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
+    const auto& [namedDevice, namedModel] = info.param;
+    return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
+}
+
+// Tag for the generated tests
+class GeneratedTest : public GeneratedTestBase {};
+
+// Tag for the dynamic output shape tests
+class DynamicOutputShapeTest : public GeneratedTest {};
+
+// Tag for the dynamic output shape tests
+class DISABLED_QuantizationCouplingTest : public GeneratedTest {};
+
+TEST_P(GeneratedTest, Test) {
+    Execute(kDevice, kTestModel, /*testKind=*/TestKind::GENERAL);
+}
+
+TEST_P(DynamicOutputShapeTest, Test) {
+    Execute(kDevice, kTestModel, /*testKind=*/TestKind::DYNAMIC_SHAPE);
+}
+
+TEST_P(DISABLED_QuantizationCouplingTest, Test) {
+    Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING);
+}
+
+INSTANTIATE_GENERATED_TEST(GeneratedTest,
+                           [](const TestModel& testModel) { return !testModel.expectFailure; });
+
+INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest,
+                           [](const TestModel& testModel) { return !testModel.expectFailure; });
+
+INSTANTIATE_GENERATED_TEST(DISABLED_QuantizationCouplingTest, [](const TestModel& testModel) {
+    return testModel.hasQuant8AsymmOperands() && testModel.operations.size() == 1;
+});
+
+}  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
new file mode 100644
index 0000000..ad6323f
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H
+
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <functional>
+#include <vector>
+#include "1.0/Utils.h"
+#include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using NamedModel = Named<const test_helper::TestModel*>;
+using GeneratedTestParam = std::tuple<NamedDevice, NamedModel>;
+
+class GeneratedTestBase : public testing::TestWithParam<GeneratedTestParam> {
+  protected:
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(std::get<NamedDevice>(GetParam()));
+    const test_helper::TestModel& kTestModel = *getData(std::get<NamedModel>(GetParam()));
+};
+
+using FilterFn = std::function<bool(const test_helper::TestModel&)>;
+std::vector<NamedModel> getNamedModels(const FilterFn& filter);
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
+
+#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
+    INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite,                                    \
+                             testing::Combine(testing::ValuesIn(getNamedDevices()),       \
+                                              testing::ValuesIn(getNamedModels(filter))), \
+                             printGeneratedTest)
+
+// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp.
+// TODO: Clean up the hierarchy for ValidationTest.
+class ValidationTest : public GeneratedTestBase {};
+
+Model createModel(const test_helper::TestModel& testModel);
+
+void PrepareModel(const sp<IDevice>& device, const Model& model, sp<IPreparedModel>* preparedModel);
+
+enum class TestKind {
+    // Runs a test model and compares the results to a golden data
+    GENERAL,
+    // Same as GENERAL but sets dimensions for the output tensors to zeros
+    DYNAMIC_SHAPE,
+    // Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result
+    // (OK/SKIPPED/FAILED) as the model with all such tensors converted to
+    // TENSOR_QUANT8_ASYMM_SIGNED.
+    QUANTIZATION_COUPLING
+};
+
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel,
+                           const test_helper::TestModel& testModel, TestKind testKind);
+
+}  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
+
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H
diff --git a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
new file mode 100644
index 0000000..a7569e6
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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 <android/hardware/neuralnetworks/1.3/types.h>
+#include "TestHarness.h"
+
+namespace android::hardware::neuralnetworks::V1_3 {
+
+// Make sure that the HIDL enums are compatible with the values defined in
+// frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h.
+using namespace test_helper;
+#define CHECK_TEST_ENUM(EnumType, enumValue) \
+    static_assert(static_cast<EnumType>(Test##EnumType::enumValue) == EnumType::enumValue)
+
+CHECK_TEST_ENUM(OperandType, FLOAT32);
+CHECK_TEST_ENUM(OperandType, INT32);
+CHECK_TEST_ENUM(OperandType, UINT32);
+CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT32);
+CHECK_TEST_ENUM(OperandType, TENSOR_INT32);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM);
+CHECK_TEST_ENUM(OperandType, BOOL);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_SYMM);
+CHECK_TEST_ENUM(OperandType, TENSOR_FLOAT16);
+CHECK_TEST_ENUM(OperandType, TENSOR_BOOL8);
+CHECK_TEST_ENUM(OperandType, FLOAT16);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM_PER_CHANNEL);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_ASYMM);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM);
+CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM_SIGNED);
+
+CHECK_TEST_ENUM(OperationType, ADD);
+CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D);
+CHECK_TEST_ENUM(OperationType, CONCATENATION);
+CHECK_TEST_ENUM(OperationType, CONV_2D);
+CHECK_TEST_ENUM(OperationType, DEPTHWISE_CONV_2D);
+CHECK_TEST_ENUM(OperationType, DEPTH_TO_SPACE);
+CHECK_TEST_ENUM(OperationType, DEQUANTIZE);
+CHECK_TEST_ENUM(OperationType, EMBEDDING_LOOKUP);
+CHECK_TEST_ENUM(OperationType, FLOOR);
+CHECK_TEST_ENUM(OperationType, FULLY_CONNECTED);
+CHECK_TEST_ENUM(OperationType, HASHTABLE_LOOKUP);
+CHECK_TEST_ENUM(OperationType, L2_NORMALIZATION);
+CHECK_TEST_ENUM(OperationType, L2_POOL_2D);
+CHECK_TEST_ENUM(OperationType, LOCAL_RESPONSE_NORMALIZATION);
+CHECK_TEST_ENUM(OperationType, LOGISTIC);
+CHECK_TEST_ENUM(OperationType, LSH_PROJECTION);
+CHECK_TEST_ENUM(OperationType, LSTM);
+CHECK_TEST_ENUM(OperationType, MAX_POOL_2D);
+CHECK_TEST_ENUM(OperationType, MUL);
+CHECK_TEST_ENUM(OperationType, RELU);
+CHECK_TEST_ENUM(OperationType, RELU1);
+CHECK_TEST_ENUM(OperationType, RELU6);
+CHECK_TEST_ENUM(OperationType, RESHAPE);
+CHECK_TEST_ENUM(OperationType, RESIZE_BILINEAR);
+CHECK_TEST_ENUM(OperationType, RNN);
+CHECK_TEST_ENUM(OperationType, SOFTMAX);
+CHECK_TEST_ENUM(OperationType, SPACE_TO_DEPTH);
+CHECK_TEST_ENUM(OperationType, SVDF);
+CHECK_TEST_ENUM(OperationType, TANH);
+CHECK_TEST_ENUM(OperationType, BATCH_TO_SPACE_ND);
+CHECK_TEST_ENUM(OperationType, DIV);
+CHECK_TEST_ENUM(OperationType, MEAN);
+CHECK_TEST_ENUM(OperationType, PAD);
+CHECK_TEST_ENUM(OperationType, SPACE_TO_BATCH_ND);
+CHECK_TEST_ENUM(OperationType, SQUEEZE);
+CHECK_TEST_ENUM(OperationType, STRIDED_SLICE);
+CHECK_TEST_ENUM(OperationType, SUB);
+CHECK_TEST_ENUM(OperationType, TRANSPOSE);
+CHECK_TEST_ENUM(OperationType, ABS);
+CHECK_TEST_ENUM(OperationType, ARGMAX);
+CHECK_TEST_ENUM(OperationType, ARGMIN);
+CHECK_TEST_ENUM(OperationType, AXIS_ALIGNED_BBOX_TRANSFORM);
+CHECK_TEST_ENUM(OperationType, BIDIRECTIONAL_SEQUENCE_LSTM);
+CHECK_TEST_ENUM(OperationType, BIDIRECTIONAL_SEQUENCE_RNN);
+CHECK_TEST_ENUM(OperationType, BOX_WITH_NMS_LIMIT);
+CHECK_TEST_ENUM(OperationType, CAST);
+CHECK_TEST_ENUM(OperationType, CHANNEL_SHUFFLE);
+CHECK_TEST_ENUM(OperationType, DETECTION_POSTPROCESSING);
+CHECK_TEST_ENUM(OperationType, EQUAL);
+CHECK_TEST_ENUM(OperationType, EXP);
+CHECK_TEST_ENUM(OperationType, EXPAND_DIMS);
+CHECK_TEST_ENUM(OperationType, GATHER);
+CHECK_TEST_ENUM(OperationType, GENERATE_PROPOSALS);
+CHECK_TEST_ENUM(OperationType, GREATER);
+CHECK_TEST_ENUM(OperationType, GREATER_EQUAL);
+CHECK_TEST_ENUM(OperationType, GROUPED_CONV_2D);
+CHECK_TEST_ENUM(OperationType, HEATMAP_MAX_KEYPOINT);
+CHECK_TEST_ENUM(OperationType, INSTANCE_NORMALIZATION);
+CHECK_TEST_ENUM(OperationType, LESS);
+CHECK_TEST_ENUM(OperationType, LESS_EQUAL);
+CHECK_TEST_ENUM(OperationType, LOG);
+CHECK_TEST_ENUM(OperationType, LOGICAL_AND);
+CHECK_TEST_ENUM(OperationType, LOGICAL_NOT);
+CHECK_TEST_ENUM(OperationType, LOGICAL_OR);
+CHECK_TEST_ENUM(OperationType, LOG_SOFTMAX);
+CHECK_TEST_ENUM(OperationType, MAXIMUM);
+CHECK_TEST_ENUM(OperationType, MINIMUM);
+CHECK_TEST_ENUM(OperationType, NEG);
+CHECK_TEST_ENUM(OperationType, NOT_EQUAL);
+CHECK_TEST_ENUM(OperationType, PAD_V2);
+CHECK_TEST_ENUM(OperationType, POW);
+CHECK_TEST_ENUM(OperationType, PRELU);
+CHECK_TEST_ENUM(OperationType, QUANTIZE);
+CHECK_TEST_ENUM(OperationType, QUANTIZED_16BIT_LSTM);
+CHECK_TEST_ENUM(OperationType, RANDOM_MULTINOMIAL);
+CHECK_TEST_ENUM(OperationType, REDUCE_ALL);
+CHECK_TEST_ENUM(OperationType, REDUCE_ANY);
+CHECK_TEST_ENUM(OperationType, REDUCE_MAX);
+CHECK_TEST_ENUM(OperationType, REDUCE_MIN);
+CHECK_TEST_ENUM(OperationType, REDUCE_PROD);
+CHECK_TEST_ENUM(OperationType, REDUCE_SUM);
+CHECK_TEST_ENUM(OperationType, ROI_ALIGN);
+CHECK_TEST_ENUM(OperationType, ROI_POOLING);
+CHECK_TEST_ENUM(OperationType, RSQRT);
+CHECK_TEST_ENUM(OperationType, SELECT);
+CHECK_TEST_ENUM(OperationType, SIN);
+CHECK_TEST_ENUM(OperationType, SLICE);
+CHECK_TEST_ENUM(OperationType, SPLIT);
+CHECK_TEST_ENUM(OperationType, SQRT);
+CHECK_TEST_ENUM(OperationType, TILE);
+CHECK_TEST_ENUM(OperationType, TOPK_V2);
+CHECK_TEST_ENUM(OperationType, TRANSPOSE_CONV_2D);
+CHECK_TEST_ENUM(OperationType, UNIDIRECTIONAL_SEQUENCE_LSTM);
+CHECK_TEST_ENUM(OperationType, UNIDIRECTIONAL_SEQUENCE_RNN);
+CHECK_TEST_ENUM(OperationType, RESIZE_NEAREST_NEIGHBOR);
+
+#undef CHECK_TEST_ENUM
+
+}  // namespace android::hardware::neuralnetworks::V1_3
diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
new file mode 100644
index 0000000..7df8046
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
@@ -0,0 +1,411 @@
+/*
+ * 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 "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "1.2/Callbacks.h"
+#include "ExecutionBurstController.h"
+#include "ExecutionBurstServer.h"
+#include "GeneratedTestHarness.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <chrono>
+#include <cstring>
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using nn::ExecutionBurstController;
+using nn::RequestChannelSender;
+using nn::ResultChannelReceiver;
+using V1_0::ErrorStatus;
+using V1_0::Request;
+using V1_2::FmqRequestDatum;
+using V1_2::FmqResultDatum;
+using V1_2::IBurstCallback;
+using V1_2::IBurstContext;
+using V1_2::MeasureTiming;
+using V1_2::Timing;
+using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback;
+
+// This constant value represents the length of an FMQ that is large enough to
+// return a result from a burst execution for all of the generated test cases.
+constexpr size_t kExecutionBurstChannelLength = 1024;
+
+// This constant value represents a length of an FMQ that is not large enough
+// to return a result from a burst execution for some of the generated test
+// cases.
+constexpr size_t kExecutionBurstChannelSmallLength = 8;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static bool badTiming(Timing timing) {
+    return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX;
+}
+
+static void createBurst(const sp<IPreparedModel>& preparedModel, const sp<IBurstCallback>& callback,
+                        std::unique_ptr<RequestChannelSender>* sender,
+                        std::unique_ptr<ResultChannelReceiver>* receiver,
+                        sp<IBurstContext>* context,
+                        size_t resultChannelLength = kExecutionBurstChannelLength) {
+    ASSERT_NE(nullptr, preparedModel.get());
+    ASSERT_NE(nullptr, sender);
+    ASSERT_NE(nullptr, receiver);
+    ASSERT_NE(nullptr, context);
+
+    // create FMQ objects
+    auto [fmqRequestChannel, fmqRequestDescriptor] =
+            RequestChannelSender::create(kExecutionBurstChannelLength);
+    auto [fmqResultChannel, fmqResultDescriptor] =
+            ResultChannelReceiver::create(resultChannelLength, std::chrono::microseconds{0});
+    ASSERT_NE(nullptr, fmqRequestChannel.get());
+    ASSERT_NE(nullptr, fmqResultChannel.get());
+    ASSERT_NE(nullptr, fmqRequestDescriptor);
+    ASSERT_NE(nullptr, fmqResultDescriptor);
+
+    // configure burst
+    ErrorStatus errorStatus;
+    sp<IBurstContext> burstContext;
+    const Return<void> ret = preparedModel->configureExecutionBurst(
+            callback, *fmqRequestDescriptor, *fmqResultDescriptor,
+            [&errorStatus, &burstContext](ErrorStatus status, const sp<IBurstContext>& context) {
+                errorStatus = status;
+                burstContext = context;
+            });
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_EQ(ErrorStatus::NONE, errorStatus);
+    ASSERT_NE(nullptr, burstContext.get());
+
+    // return values
+    *sender = std::move(fmqRequestChannel);
+    *receiver = std::move(fmqResultChannel);
+    *context = burstContext;
+}
+
+static void createBurstWithResultChannelLength(
+        const sp<IPreparedModel>& preparedModel, size_t resultChannelLength,
+        std::shared_ptr<ExecutionBurstController>* controller) {
+    ASSERT_NE(nullptr, preparedModel.get());
+    ASSERT_NE(nullptr, controller);
+
+    // create FMQ objects
+    std::unique_ptr<RequestChannelSender> sender;
+    std::unique_ptr<ResultChannelReceiver> receiver;
+    sp<ExecutionBurstCallback> callback = new ExecutionBurstCallback();
+    sp<IBurstContext> context;
+    ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context,
+                                        resultChannelLength));
+    ASSERT_NE(nullptr, sender.get());
+    ASSERT_NE(nullptr, receiver.get());
+    ASSERT_NE(nullptr, context.get());
+
+    // return values
+    *controller = std::make_shared<ExecutionBurstController>(std::move(sender), std::move(receiver),
+                                                             context, callback);
+}
+
+// Primary validation function. This function will take a valid serialized
+// request, apply a mutation to it to invalidate the serialized request, then
+// pass it to interface calls that use the serialized request. Note that the
+// serialized request here is passed by value, and any mutation to the
+// serialized request does not leave this function.
+static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiver,
+                     const std::string& message, std::vector<FmqRequestDatum> serialized,
+                     const std::function<void(std::vector<FmqRequestDatum>*)>& mutation) {
+    mutation(&serialized);
+
+    // skip if packet is too large to send
+    if (serialized.size() > kExecutionBurstChannelLength) {
+        return;
+    }
+
+    SCOPED_TRACE(message);
+
+    // send invalid packet
+    ASSERT_TRUE(sender->sendPacket(serialized));
+
+    // receive error
+    auto results = receiver->getBlocking();
+    ASSERT_TRUE(results.has_value());
+    const auto [status, outputShapes, timing] = std::move(*results);
+    EXPECT_NE(ErrorStatus::NONE, status);
+    EXPECT_EQ(0u, outputShapes.size());
+    EXPECT_TRUE(badTiming(timing));
+}
+
+// For validation, valid packet entries are mutated to invalid packet entries,
+// or invalid packet entries are inserted into valid packets. This function
+// creates pre-set invalid packet entries for convenience.
+static std::vector<FmqRequestDatum> createBadRequestPacketEntries() {
+    const FmqRequestDatum::PacketInformation packetInformation = {
+            /*.packetSize=*/10, /*.numberOfInputOperands=*/10, /*.numberOfOutputOperands=*/10,
+            /*.numberOfPools=*/10};
+    const FmqRequestDatum::OperandInformation operandInformation = {
+            /*.hasNoValue=*/false, /*.location=*/{}, /*.numberOfDimensions=*/10};
+    const int32_t invalidPoolIdentifier = std::numeric_limits<int32_t>::max();
+    std::vector<FmqRequestDatum> bad(7);
+    bad[0].packetInformation(packetInformation);
+    bad[1].inputOperandInformation(operandInformation);
+    bad[2].inputOperandDimensionValue(0);
+    bad[3].outputOperandInformation(operandInformation);
+    bad[4].outputOperandDimensionValue(0);
+    bad[5].poolIdentifier(invalidPoolIdentifier);
+    bad[6].measureTiming(MeasureTiming::YES);
+    return bad;
+}
+
+// For validation, valid packet entries are mutated to invalid packet entries,
+// or invalid packet entries are inserted into valid packets. This function
+// retrieves pre-set invalid packet entries for convenience. This function
+// caches these data so they can be reused on subsequent validation checks.
+static const std::vector<FmqRequestDatum>& getBadRequestPacketEntries() {
+    static const std::vector<FmqRequestDatum> bad = createBadRequestPacketEntries();
+    return bad;
+}
+
+///////////////////////// REMOVE DATUM ////////////////////////////////////
+
+static void removeDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver,
+                            const std::vector<FmqRequestDatum>& serialized) {
+    for (size_t index = 0; index < serialized.size(); ++index) {
+        const std::string message = "removeDatum: removed datum at index " + std::to_string(index);
+        validate(sender, receiver, message, serialized,
+                 [index](std::vector<FmqRequestDatum>* serialized) {
+                     serialized->erase(serialized->begin() + index);
+                 });
+    }
+}
+
+///////////////////////// ADD DATUM ////////////////////////////////////
+
+static void addDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver,
+                         const std::vector<FmqRequestDatum>& serialized) {
+    const std::vector<FmqRequestDatum>& extra = getBadRequestPacketEntries();
+    for (size_t index = 0; index <= serialized.size(); ++index) {
+        for (size_t type = 0; type < extra.size(); ++type) {
+            const std::string message = "addDatum: added datum type " + std::to_string(type) +
+                                        " at index " + std::to_string(index);
+            validate(sender, receiver, message, serialized,
+                     [index, type, &extra](std::vector<FmqRequestDatum>* serialized) {
+                         serialized->insert(serialized->begin() + index, extra[type]);
+                     });
+        }
+    }
+}
+
+///////////////////////// MUTATE DATUM ////////////////////////////////////
+
+static bool interestingCase(const FmqRequestDatum& lhs, const FmqRequestDatum& rhs) {
+    using Discriminator = FmqRequestDatum::hidl_discriminator;
+
+    const bool differentValues = (lhs != rhs);
+    const bool sameDiscriminator = (lhs.getDiscriminator() == rhs.getDiscriminator());
+    const auto discriminator = rhs.getDiscriminator();
+    const bool isDimensionValue = (discriminator == Discriminator::inputOperandDimensionValue ||
+                                   discriminator == Discriminator::outputOperandDimensionValue);
+
+    return differentValues && !(sameDiscriminator && isDimensionValue);
+}
+
+static void mutateDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver,
+                            const std::vector<FmqRequestDatum>& serialized) {
+    const std::vector<FmqRequestDatum>& change = getBadRequestPacketEntries();
+    for (size_t index = 0; index < serialized.size(); ++index) {
+        for (size_t type = 0; type < change.size(); ++type) {
+            if (interestingCase(serialized[index], change[type])) {
+                const std::string message = "mutateDatum: changed datum at index " +
+                                            std::to_string(index) + " to datum type " +
+                                            std::to_string(type);
+                validate(sender, receiver, message, serialized,
+                         [index, type, &change](std::vector<FmqRequestDatum>* serialized) {
+                             (*serialized)[index] = change[type];
+                         });
+            }
+        }
+    }
+}
+
+///////////////////////// BURST VALIATION TESTS ////////////////////////////////////
+
+static void validateBurstSerialization(const sp<IPreparedModel>& preparedModel,
+                                       const Request& request) {
+    // create burst
+    std::unique_ptr<RequestChannelSender> sender;
+    std::unique_ptr<ResultChannelReceiver> receiver;
+    sp<ExecutionBurstCallback> callback = new ExecutionBurstCallback();
+    sp<IBurstContext> context;
+    ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context));
+    ASSERT_NE(nullptr, sender.get());
+    ASSERT_NE(nullptr, receiver.get());
+    ASSERT_NE(nullptr, context.get());
+
+    // load memory into callback slots
+    std::vector<intptr_t> keys;
+    keys.reserve(request.pools.size());
+    std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys),
+                   [](const auto& pool) { return reinterpret_cast<intptr_t>(&pool); });
+    const std::vector<int32_t> slots = callback->getSlots(request.pools, keys);
+
+    // ensure slot std::numeric_limits<int32_t>::max() doesn't exist (for
+    // subsequent slot validation testing)
+    ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) {
+        return slot != std::numeric_limits<int32_t>::max();
+    }));
+
+    // serialize the request
+    const auto serialized = android::nn::serialize(request, MeasureTiming::YES, slots);
+
+    // validations
+    removeDatumTest(sender.get(), receiver.get(), serialized);
+    addDatumTest(sender.get(), receiver.get(), serialized);
+    mutateDatumTest(sender.get(), receiver.get(), serialized);
+}
+
+// This test validates that when the Result message size exceeds length of the
+// result FMQ, the service instance gracefully fails and returns an error.
+static void validateBurstFmqLength(const sp<IPreparedModel>& preparedModel,
+                                   const Request& request) {
+    // create regular burst
+    std::shared_ptr<ExecutionBurstController> controllerRegular;
+    ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength(
+            preparedModel, kExecutionBurstChannelLength, &controllerRegular));
+    ASSERT_NE(nullptr, controllerRegular.get());
+
+    // create burst with small output channel
+    std::shared_ptr<ExecutionBurstController> controllerSmall;
+    ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength(
+            preparedModel, kExecutionBurstChannelSmallLength, &controllerSmall));
+    ASSERT_NE(nullptr, controllerSmall.get());
+
+    // load memory into callback slots
+    std::vector<intptr_t> keys(request.pools.size());
+    for (size_t i = 0; i < keys.size(); ++i) {
+        keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
+    }
+
+    // collect serialized result by running regular burst
+    const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] =
+            controllerRegular->compute(request, MeasureTiming::NO, keys);
+    const ErrorStatus statusRegular = nn::convertResultCodeToErrorStatus(nRegular);
+    EXPECT_FALSE(fallbackRegular);
+
+    // skip test if regular burst output isn't useful for testing a failure
+    // caused by having too small of a length for the result FMQ
+    const std::vector<FmqResultDatum> serialized =
+            android::nn::serialize(statusRegular, outputShapesRegular, timingRegular);
+    if (statusRegular != ErrorStatus::NONE ||
+        serialized.size() <= kExecutionBurstChannelSmallLength) {
+        return;
+    }
+
+    // by this point, execution should fail because the result channel isn't
+    // large enough to return the serialized result
+    const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] =
+            controllerSmall->compute(request, MeasureTiming::NO, keys);
+    const ErrorStatus statusSmall = nn::convertResultCodeToErrorStatus(nSmall);
+    EXPECT_NE(ErrorStatus::NONE, statusSmall);
+    EXPECT_EQ(0u, outputShapesSmall.size());
+    EXPECT_TRUE(badTiming(timingSmall));
+    EXPECT_FALSE(fallbackSmall);
+}
+
+static bool isSanitized(const FmqResultDatum& datum) {
+    using Discriminator = FmqResultDatum::hidl_discriminator;
+
+    // check to ensure the padding values in the returned
+    // FmqResultDatum::OperandInformation are initialized to 0
+    if (datum.getDiscriminator() == Discriminator::operandInformation) {
+        static_assert(
+                offsetof(FmqResultDatum::OperandInformation, isSufficient) == 0,
+                "unexpected value for offset of FmqResultDatum::OperandInformation::isSufficient");
+        static_assert(
+                sizeof(FmqResultDatum::OperandInformation::isSufficient) == 1,
+                "unexpected value for size of FmqResultDatum::OperandInformation::isSufficient");
+        static_assert(offsetof(FmqResultDatum::OperandInformation, numberOfDimensions) == 4,
+                      "unexpected value for offset of "
+                      "FmqResultDatum::OperandInformation::numberOfDimensions");
+        static_assert(sizeof(FmqResultDatum::OperandInformation::numberOfDimensions) == 4,
+                      "unexpected value for size of "
+                      "FmqResultDatum::OperandInformation::numberOfDimensions");
+        static_assert(sizeof(FmqResultDatum::OperandInformation) == 8,
+                      "unexpected value for size of "
+                      "FmqResultDatum::OperandInformation");
+
+        constexpr size_t paddingOffset =
+                offsetof(FmqResultDatum::OperandInformation, isSufficient) +
+                sizeof(FmqResultDatum::OperandInformation::isSufficient);
+        constexpr size_t paddingSize =
+                offsetof(FmqResultDatum::OperandInformation, numberOfDimensions) - paddingOffset;
+
+        FmqResultDatum::OperandInformation initialized{};
+        std::memset(&initialized, 0, sizeof(initialized));
+
+        const char* initializedPaddingStart =
+                reinterpret_cast<const char*>(&initialized) + paddingOffset;
+        const char* datumPaddingStart =
+                reinterpret_cast<const char*>(&datum.operandInformation()) + paddingOffset;
+
+        return std::memcmp(datumPaddingStart, initializedPaddingStart, paddingSize) == 0;
+    }
+
+    // there are no other padding initialization checks required, so return true
+    // for any sum-type that isn't FmqResultDatum::OperandInformation
+    return true;
+}
+
+static void validateBurstSanitized(const sp<IPreparedModel>& preparedModel,
+                                   const Request& request) {
+    // create burst
+    std::unique_ptr<RequestChannelSender> sender;
+    std::unique_ptr<ResultChannelReceiver> receiver;
+    sp<ExecutionBurstCallback> callback = new ExecutionBurstCallback();
+    sp<IBurstContext> context;
+    ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context));
+    ASSERT_NE(nullptr, sender.get());
+    ASSERT_NE(nullptr, receiver.get());
+    ASSERT_NE(nullptr, context.get());
+
+    // load memory into callback slots
+    std::vector<intptr_t> keys;
+    keys.reserve(request.pools.size());
+    std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys),
+                   [](const auto& pool) { return reinterpret_cast<intptr_t>(&pool); });
+    const std::vector<int32_t> slots = callback->getSlots(request.pools, keys);
+
+    // send valid request
+    ASSERT_TRUE(sender->send(request, MeasureTiming::YES, slots));
+
+    // receive valid result
+    auto serialized = receiver->getPacketBlocking();
+    ASSERT_TRUE(serialized.has_value());
+
+    // sanitize result
+    ASSERT_TRUE(std::all_of(serialized->begin(), serialized->end(), isSanitized))
+            << "The result serialized data is not properly sanitized";
+}
+
+///////////////////////////// ENTRY POINT //////////////////////////////////
+
+void validateBurst(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, request));
+    ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, request));
+    ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request));
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
new file mode 100644
index 0000000..242e12e
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
+
+#include "1.0/Utils.h"
+#include "1.3/Callbacks.h"
+#include "GeneratedTestHarness.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using implementation::PreparedModelCallback;
+using V1_0::ErrorStatus;
+using V1_0::OperandLifeTime;
+using V1_1::ExecutionPreference;
+using V1_2::OperationTypeRange;
+using V1_2::SymmPerChannelQuantParams;
+using HidlToken =
+        hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
+                                           const Model& model) {
+    SCOPED_TRACE(message + " [getSupportedOperations_1_3]");
+
+    Return<void> ret = device->getSupportedOperations_1_3(
+            model, [&](ErrorStatus status, const hidl_vec<bool>&) {
+                EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+            });
+    EXPECT_TRUE(ret.isOk());
+}
+
+static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
+                                 const Model& model, ExecutionPreference preference) {
+    SCOPED_TRACE(message + " [prepareModel_1_3]");
+
+    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+    Return<ErrorStatus> prepareLaunchStatus =
+            device->prepareModel_1_3(model, preference, hidl_vec<hidl_handle>(),
+                                     hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
+    ASSERT_TRUE(prepareLaunchStatus.isOk());
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+    preparedModelCallback->wait();
+    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
+    sp<IPreparedModel> preparedModel = getPreparedModel_1_3(preparedModelCallback);
+    ASSERT_EQ(nullptr, preparedModel.get());
+}
+
+static bool validExecutionPreference(ExecutionPreference preference) {
+    return preference == ExecutionPreference::LOW_POWER ||
+           preference == ExecutionPreference::FAST_SINGLE_ANSWER ||
+           preference == ExecutionPreference::SUSTAINED_SPEED;
+}
+
+// Primary validation function. This function will take a valid model, apply a
+// mutation to it to invalidate the model, then pass it to interface calls that
+// use the model. Note that the model here is passed by value, and any mutation
+// to the model does not leave this function.
+static void validate(const sp<IDevice>& device, const std::string& message, Model model,
+                     const std::function<void(Model*)>& mutation,
+                     ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
+    mutation(&model);
+    if (validExecutionPreference(preference)) {
+        validateGetSupportedOperations(device, message, model);
+    }
+    validatePrepareModel(device, message, model, preference);
+}
+
+static uint32_t addOperand(Model* model) {
+    return hidl_vec_push_back(&model->operands,
+                              {
+                                      .type = OperandType::INT32,
+                                      .dimensions = {},
+                                      .numberOfConsumers = 0,
+                                      .scale = 0.0f,
+                                      .zeroPoint = 0,
+                                      .lifetime = OperandLifeTime::MODEL_INPUT,
+                                      .location = {.poolIndex = 0, .offset = 0, .length = 0},
+                              });
+}
+
+static uint32_t addOperand(Model* model, OperandLifeTime lifetime) {
+    uint32_t index = addOperand(model);
+    model->operands[index].numberOfConsumers = 1;
+    model->operands[index].lifetime = lifetime;
+    return index;
+}
+
+///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
+
+static const uint32_t invalidOperandTypes[] = {
+        static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MIN) - 1,
+        static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MAX) + 1,
+        static_cast<uint32_t>(OperandTypeRange::OEM_MIN) - 1,
+        static_cast<uint32_t>(OperandTypeRange::OEM_MAX) + 1,
+};
+
+static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        for (uint32_t invalidOperandType : invalidOperandTypes) {
+            const std::string message = "mutateOperandTypeTest: operand " +
+                                        std::to_string(operand) + " set to value " +
+                                        std::to_string(invalidOperandType);
+            validate(device, message, model, [operand, invalidOperandType](Model* model) {
+                model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE OPERAND RANK /////////////////////////
+
+static uint32_t getInvalidRank(OperandType type) {
+    switch (type) {
+        case OperandType::FLOAT16:
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+        case OperandType::BOOL:
+            return 1;
+        case OperandType::TENSOR_BOOL8:
+        case OperandType::TENSOR_FLOAT16:
+        case OperandType::TENSOR_FLOAT32:
+        case OperandType::TENSOR_INT32:
+        case OperandType::TENSOR_QUANT8_ASYMM:
+        case OperandType::TENSOR_QUANT8_SYMM:
+        case OperandType::TENSOR_QUANT16_ASYMM:
+        case OperandType::TENSOR_QUANT16_SYMM:
+        case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
+            return 0;
+        default:
+            return 0;
+    }
+}
+
+static void mutateOperandRankTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
+        if (invalidRank == 0) {
+            continue;
+        }
+        const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
+                                    " has rank of " + std::to_string(invalidRank);
+        validate(device, message, model, [operand, invalidRank](Model* model) {
+            model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+        });
+    }
+}
+
+///////////////////////// VALIDATE OPERAND SCALE /////////////////////////
+
+static float getInvalidScale(OperandType type) {
+    switch (type) {
+        case OperandType::FLOAT16:
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+        case OperandType::BOOL:
+        case OperandType::TENSOR_BOOL8:
+        case OperandType::TENSOR_FLOAT16:
+        case OperandType::TENSOR_FLOAT32:
+        case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
+            return 1.0f;
+        case OperandType::TENSOR_INT32:
+            return -1.0f;
+        case OperandType::TENSOR_QUANT8_SYMM:
+        case OperandType::TENSOR_QUANT8_ASYMM:
+        case OperandType::TENSOR_QUANT16_ASYMM:
+        case OperandType::TENSOR_QUANT16_SYMM:
+            return 0.0f;
+        default:
+            return 0.0f;
+    }
+}
+
+static void mutateOperandScaleTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const float invalidScale = getInvalidScale(model.operands[operand].type);
+        const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
+                                    " has scale of " + std::to_string(invalidScale);
+        validate(device, message, model, [operand, invalidScale](Model* model) {
+            model->operands[operand].scale = invalidScale;
+        });
+    }
+}
+
+///////////////////////// VALIDATE OPERAND ZERO POINT /////////////////////////
+
+static std::vector<int32_t> getInvalidZeroPoints(OperandType type) {
+    switch (type) {
+        case OperandType::FLOAT16:
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+        case OperandType::BOOL:
+        case OperandType::TENSOR_BOOL8:
+        case OperandType::TENSOR_FLOAT16:
+        case OperandType::TENSOR_FLOAT32:
+        case OperandType::TENSOR_INT32:
+        case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
+            return {1};
+        case OperandType::TENSOR_QUANT8_ASYMM:
+            return {-1, 256};
+        case OperandType::TENSOR_QUANT8_SYMM:
+            return {-129, -1, 1, 128};
+        case OperandType::TENSOR_QUANT16_ASYMM:
+            return {-1, 65536};
+        case OperandType::TENSOR_QUANT16_SYMM:
+            return {-32769, -1, 1, 32768};
+        default:
+            return {};
+    }
+}
+
+static void mutateOperandZeroPointTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const std::vector<int32_t> invalidZeroPoints =
+                getInvalidZeroPoints(model.operands[operand].type);
+        for (int32_t invalidZeroPoint : invalidZeroPoints) {
+            const std::string message = "mutateOperandZeroPointTest: operand " +
+                                        std::to_string(operand) + " has zero point of " +
+                                        std::to_string(invalidZeroPoint);
+            validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
+                model->operands[operand].zeroPoint = invalidZeroPoint;
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE EXTRA ??? /////////////////////////
+
+// TODO: Operand::lifetime
+// TODO: Operand::location
+
+///////////////////////// VALIDATE OPERATION OPERAND TYPE /////////////////////////
+
+static void mutateOperand(Operand* operand, OperandType type) {
+    Operand newOperand = *operand;
+    newOperand.type = type;
+    switch (type) {
+        case OperandType::FLOAT16:
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+        case OperandType::BOOL:
+            newOperand.dimensions = hidl_vec<uint32_t>();
+            newOperand.scale = 0.0f;
+            newOperand.zeroPoint = 0;
+            break;
+        case OperandType::TENSOR_BOOL8:
+        case OperandType::TENSOR_FLOAT16:
+        case OperandType::TENSOR_FLOAT32:
+            newOperand.dimensions =
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+            newOperand.scale = 0.0f;
+            newOperand.zeroPoint = 0;
+            break;
+        case OperandType::TENSOR_INT32:
+            newOperand.dimensions =
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+            newOperand.zeroPoint = 0;
+            break;
+        case OperandType::TENSOR_QUANT8_ASYMM:
+        case OperandType::TENSOR_QUANT8_SYMM:
+        case OperandType::TENSOR_QUANT16_ASYMM:
+        case OperandType::TENSOR_QUANT16_SYMM:
+            newOperand.dimensions =
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+            newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
+            break;
+        case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: {
+            newOperand.dimensions =
+                    operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+            newOperand.scale = 0.0f;
+            newOperand.zeroPoint = 0;
+
+            SymmPerChannelQuantParams channelQuant;
+            channelQuant.channelDim = 0;
+            channelQuant.scales = hidl_vec<float>(
+                    operand->dimensions.size() > 0 ? static_cast<size_t>(operand->dimensions[0])
+                                                   : 0);
+            for (size_t i = 0; i < channelQuant.scales.size(); ++i) {
+                channelQuant.scales[i] = 1.0f;
+            }
+            newOperand.extraParams.channelQuant(std::move(channelQuant));
+        } break;
+        case OperandType::OEM:
+        case OperandType::TENSOR_OEM_BYTE:
+        default:
+            break;
+    }
+    *operand = newOperand;
+}
+
+static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, const Model& model) {
+    // Do not test OEM types
+    if (type == model.operands[operand].type || type == OperandType::OEM ||
+        type == OperandType::TENSOR_OEM_BYTE) {
+        return true;
+    }
+    for (const Operation& operation : model.operations) {
+        // Skip mutateOperationOperandTypeTest for the following operations.
+        // - LSH_PROJECTION's second argument is allowed to have any type.
+        // - ARGMIN and ARGMAX's first argument can be any of
+        // TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM).
+        // - CAST's argument can be any of TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM).
+        // - RANDOM_MULTINOMIAL's argument can be either TENSOR_FLOAT16 or TENSOR_FLOAT32.
+        // - DEQUANTIZE input can be any of
+        // TENSOR_(QUANT8_ASYMM|QUANT8_SYMM|QUANT8_SYMM_PER_CHANNEL), output can
+        // be of either TENSOR_FLOAT16 or TENSOR_FLOAT32.
+        // - QUANTIZE input can be either TENSOR_FLOAT16 or TENSOR_FLOAT32
+        // - CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
+        // - DEPTHWISE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
+        // - GROUPED_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
+        // - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
+        switch (operation.type) {
+            case OperationType::LSH_PROJECTION: {
+                if (operand == operation.inputs[1]) {
+                    return true;
+                }
+            } break;
+            case OperationType::CAST:
+            case OperationType::ARGMAX:
+            case OperationType::ARGMIN: {
+                if (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32 ||
+                    type == OperandType::TENSOR_INT32 || type == OperandType::TENSOR_QUANT8_ASYMM) {
+                    return true;
+                }
+            } break;
+            case OperationType::QUANTIZE: {
+                if (operand == operation.inputs[0] &&
+                    (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) {
+                    return true;
+                }
+                if (operand == operation.outputs[0] &&
+                    (type == OperandType::TENSOR_QUANT8_ASYMM ||
+                     type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)) {
+                    return true;
+                }
+            } break;
+            case OperationType::RANDOM_MULTINOMIAL: {
+                if (operand == operation.inputs[0] &&
+                    (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) {
+                    return true;
+                }
+            } break;
+            case OperationType::DEQUANTIZE: {
+                if (operand == operation.inputs[0] &&
+                    (type == OperandType::TENSOR_QUANT8_ASYMM ||
+                     type == OperandType::TENSOR_QUANT8_SYMM ||
+                     type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) {
+                    return true;
+                }
+                if (operand == operation.outputs[0] &&
+                    (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32)) {
+                    return true;
+                }
+            } break;
+            case OperationType::TRANSPOSE_CONV_2D:
+            case OperationType::GROUPED_CONV_2D:
+            case OperationType::DEPTHWISE_CONV_2D:
+            case OperationType::CONV_2D: {
+                if (operand == operation.inputs[1] &&
+                    (type == OperandType::TENSOR_QUANT8_ASYMM ||
+                     type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) {
+                    return true;
+                }
+            } break;
+            default:
+                break;
+        }
+    }
+    return false;
+}
+
+static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        for (OperandType invalidOperandType : hidl_enum_range<OperandType>{}) {
+            if (mutateOperationOperandTypeSkip(operand, invalidOperandType, model)) {
+                continue;
+            }
+            const std::string message = "mutateOperationOperandTypeTest: operand " +
+                                        std::to_string(operand) + " set to type " +
+                                        toString(invalidOperandType);
+            validate(device, message, model, [operand, invalidOperandType](Model* model) {
+                mutateOperand(&model->operands[operand], invalidOperandType);
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
+
+static const uint32_t invalidOperationTypes[] = {
+        static_cast<uint32_t>(OperationTypeRange::FUNDAMENTAL_MAX) + 1,
+        static_cast<uint32_t>(OperationTypeRange::OEM_MIN) - 1,
+        static_cast<uint32_t>(OperationTypeRange::OEM_MAX) + 1,
+};
+
+static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        for (uint32_t invalidOperationType : invalidOperationTypes) {
+            const std::string message = "mutateOperationTypeTest: operation " +
+                                        std::to_string(operation) + " set to value " +
+                                        std::to_string(invalidOperationType);
+            validate(device, message, model, [operation, invalidOperationType](Model* model) {
+                model->operations[operation].type =
+                        static_cast<OperationType>(invalidOperationType);
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
+
+static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const uint32_t invalidOperand = model.operands.size();
+        for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+            const std::string message = "mutateOperationInputOperandIndexTest: operation " +
+                                        std::to_string(operation) + " input " +
+                                        std::to_string(input);
+            validate(device, message, model, [operation, input, invalidOperand](Model* model) {
+                model->operations[operation].inputs[input] = invalidOperand;
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
+
+static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const uint32_t invalidOperand = model.operands.size();
+        for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+            const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
+                                        std::to_string(operation) + " output " +
+                                        std::to_string(output);
+            validate(device, message, model, [operation, output, invalidOperand](Model* model) {
+                model->operations[operation].outputs[output] = invalidOperand;
+            });
+        }
+    }
+}
+
+///////////////////////// REMOVE OPERAND FROM EVERYTHING /////////////////////////
+
+static void removeValueAndDecrementGreaterValues(hidl_vec<uint32_t>* vec, uint32_t value) {
+    if (vec) {
+        // remove elements matching "value"
+        auto last = std::remove(vec->begin(), vec->end(), value);
+        vec->resize(std::distance(vec->begin(), last));
+
+        // decrement elements exceeding "value"
+        std::transform(vec->begin(), vec->end(), vec->begin(),
+                       [value](uint32_t v) { return v > value ? v-- : v; });
+    }
+}
+
+static void removeOperand(Model* model, uint32_t index) {
+    hidl_vec_removeAt(&model->operands, index);
+    for (Operation& operation : model->operations) {
+        removeValueAndDecrementGreaterValues(&operation.inputs, index);
+        removeValueAndDecrementGreaterValues(&operation.outputs, index);
+    }
+    removeValueAndDecrementGreaterValues(&model->inputIndexes, index);
+    removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
+}
+
+static bool removeOperandSkip(size_t operand, const Model& model) {
+    for (const Operation& operation : model.operations) {
+        // Skip removeOperandTest for the following operations.
+        // - SPLIT's outputs are not checked during prepareModel.
+        if (operation.type == OperationType::SPLIT) {
+            for (const size_t outOprand : operation.outputs) {
+                if (operand == outOprand) {
+                    return true;
+                }
+            }
+        }
+        // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have either one or two
+        // outputs depending on their mergeOutputs parameter.
+        if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM ||
+            operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) {
+            for (const size_t outOprand : operation.outputs) {
+                if (operand == outOprand) {
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+static void removeOperandTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        if (removeOperandSkip(operand, model)) {
+            continue;
+        }
+        const std::string message = "removeOperandTest: operand " + std::to_string(operand);
+        validate(device, message, model,
+                 [operand](Model* model) { removeOperand(model, operand); });
+    }
+}
+
+///////////////////////// REMOVE OPERATION /////////////////////////
+
+static void removeOperation(Model* model, uint32_t index) {
+    for (uint32_t operand : model->operations[index].inputs) {
+        model->operands[operand].numberOfConsumers--;
+    }
+    hidl_vec_removeAt(&model->operations, index);
+}
+
+static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const std::string message = "removeOperationTest: operation " + std::to_string(operation);
+        validate(device, message, model,
+                 [operation](Model* model) { removeOperation(model, operation); });
+    }
+}
+
+///////////////////////// REMOVE OPERATION INPUT /////////////////////////
+
+static bool removeOperationInputSkip(const Operation& op, size_t input) {
+    // Skip removeOperationInputTest for the following operations.
+    // - CONCATENATION has at least 2 inputs, with the last element being INT32.
+    // - CONV_2D, DEPTHWISE_CONV_2D, MAX_POOL_2D, AVERAGE_POOL_2D, L2_POOL_2D, RESIZE_BILINEAR,
+    //   SPACE_TO_DEPTH, SPACE_TO_DEPTH, SPACE_TO_BATCH_ND, BATCH_TO_SPACE_ND can have an optional
+    //   layout parameter.
+    // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional axis
+    //   parameter.
+    switch (op.type) {
+        case OperationType::CONCATENATION: {
+            if (op.inputs.size() > 2 && input != op.inputs.size() - 1) {
+                return true;
+            }
+        } break;
+        case OperationType::DEPTHWISE_CONV_2D: {
+            if ((op.inputs.size() == 12 && input == 11) || (op.inputs.size() == 9 && input == 8)) {
+                return true;
+            }
+        } break;
+        case OperationType::CONV_2D:
+        case OperationType::AVERAGE_POOL_2D:
+        case OperationType::MAX_POOL_2D:
+        case OperationType::L2_POOL_2D: {
+            if ((op.inputs.size() == 11 && input == 10) || (op.inputs.size() == 8 && input == 7)) {
+                return true;
+            }
+        } break;
+        case OperationType::RESIZE_BILINEAR: {
+            if (op.inputs.size() == 4 && input == 3) {
+                return true;
+            }
+        } break;
+        case OperationType::SPACE_TO_DEPTH:
+        case OperationType::DEPTH_TO_SPACE:
+        case OperationType::BATCH_TO_SPACE_ND: {
+            if (op.inputs.size() == 3 && input == 2) {
+                return true;
+            }
+        } break;
+        case OperationType::SPACE_TO_BATCH_ND: {
+            if (op.inputs.size() == 4 && input == 3) {
+                return true;
+            }
+        } break;
+        case OperationType::L2_NORMALIZATION: {
+            if (op.inputs.size() == 2 && input == 1) {
+                return true;
+            }
+        } break;
+        case OperationType::LOCAL_RESPONSE_NORMALIZATION: {
+            if (op.inputs.size() == 6 && input == 5) {
+                return true;
+            }
+        } break;
+        case OperationType::SOFTMAX: {
+            if (op.inputs.size() == 3 && input == 2) {
+                return true;
+            }
+        } break;
+        default:
+            break;
+    }
+    return false;
+}
+
+static void removeOperationInputTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+            const Operation& op = model.operations[operation];
+            if (removeOperationInputSkip(op, input)) {
+                continue;
+            }
+            const std::string message = "removeOperationInputTest: operation " +
+                                        std::to_string(operation) + ", input " +
+                                        std::to_string(input);
+            validate(device, message, model, [operation, input](Model* model) {
+                uint32_t operand = model->operations[operation].inputs[input];
+                model->operands[operand].numberOfConsumers--;
+                hidl_vec_removeAt(&model->operations[operation].inputs, input);
+            });
+        }
+    }
+}
+
+///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
+
+static void removeOperationOutputTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+            const std::string message = "removeOperationOutputTest: operation " +
+                                        std::to_string(operation) + ", output " +
+                                        std::to_string(output);
+            validate(device, message, model, [operation, output](Model* model) {
+                hidl_vec_removeAt(&model->operations[operation].outputs, output);
+            });
+        }
+    }
+}
+
+///////////////////////// MODEL VALIDATION /////////////////////////
+
+// TODO: remove model input
+// TODO: remove model output
+// TODO: add unused operation
+
+///////////////////////// ADD OPERATION INPUT /////////////////////////
+
+static bool addOperationInputSkip(const Operation& op) {
+    // Skip addOperationInputTest for the following operations.
+    // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional INT32 axis
+    //   parameter.
+    if ((op.type == OperationType::L2_NORMALIZATION && op.inputs.size() == 1) ||
+        (op.type == OperationType::LOCAL_RESPONSE_NORMALIZATION && op.inputs.size() == 5) ||
+        (op.type == OperationType::SOFTMAX && op.inputs.size() == 2)) {
+        return true;
+    }
+    return false;
+}
+
+static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        if (addOperationInputSkip(model.operations[operation])) {
+            continue;
+        }
+        const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
+        validate(device, message, model, [operation](Model* model) {
+            uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
+            hidl_vec_push_back(&model->operations[operation].inputs, index);
+            hidl_vec_push_back(&model->inputIndexes, index);
+        });
+    }
+}
+
+///////////////////////// ADD OPERATION OUTPUT /////////////////////////
+
+static void addOperationOutputTest(const sp<IDevice>& device, const Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const std::string message =
+                "addOperationOutputTest: operation " + std::to_string(operation);
+        validate(device, message, model, [operation](Model* model) {
+            uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
+            hidl_vec_push_back(&model->operations[operation].outputs, index);
+            hidl_vec_push_back(&model->outputIndexes, index);
+        });
+    }
+}
+
+///////////////////////// VALIDATE EXECUTION PREFERENCE /////////////////////////
+
+static const int32_t invalidExecutionPreferences[] = {
+        static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1,        // lower bound
+        static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1,  // upper bound
+};
+
+static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
+    for (int32_t preference : invalidExecutionPreferences) {
+        const std::string message =
+                "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
+        validate(
+                device, message, model, [](Model*) {},
+                static_cast<ExecutionPreference>(preference));
+    }
+}
+
+////////////////////////// ENTRY POINT //////////////////////////////
+
+void validateModel(const sp<IDevice>& device, const Model& model) {
+    mutateOperandTypeTest(device, model);
+    mutateOperandRankTest(device, model);
+    mutateOperandScaleTest(device, model);
+    mutateOperandZeroPointTest(device, model);
+    mutateOperationOperandTypeTest(device, model);
+    mutateOperationTypeTest(device, model);
+    mutateOperationInputOperandIndexTest(device, model);
+    mutateOperationOutputOperandIndexTest(device, model);
+    removeOperandTest(device, model);
+    removeOperationTest(device, model);
+    removeOperationInputTest(device, model);
+    removeOperationOutputTest(device, model);
+    addOperationInputTest(device, model);
+    addOperationOutputTest(device, model);
+    mutateExecutionPreferenceTest(device, model);
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
new file mode 100644
index 0000000..2cf30d5
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
+
+#include <chrono>
+#include "1.0/Utils.h"
+#include "1.2/Callbacks.h"
+#include "ExecutionBurstController.h"
+#include "GeneratedTestHarness.h"
+#include "TestHarness.h"
+#include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using V1_0::ErrorStatus;
+using V1_0::Request;
+using V1_2::MeasureTiming;
+using V1_2::OutputShape;
+using V1_2::Timing;
+using V1_2::implementation::ExecutionCallback;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static bool badTiming(Timing timing) {
+    return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX;
+}
+
+// Primary validation function. This function will take a valid request, apply a
+// mutation to it to invalidate the request, then pass it to interface calls
+// that use the request. Note that the request here is passed by value, and any
+// mutation to the request does not leave this function.
+static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
+                     Request request, const std::function<void(Request*)>& mutation) {
+    mutation(&request);
+
+    // We'd like to test both with timing requested and without timing
+    // requested. Rather than running each test both ways, we'll decide whether
+    // to request timing by hashing the message. We do not use std::hash because
+    // it is not guaranteed stable across executions.
+    char hash = 0;
+    for (auto c : message) {
+        hash ^= c;
+    };
+    MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO;
+
+    // asynchronous
+    {
+        SCOPED_TRACE(message + " [execute_1_3]");
+
+        sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+        Return<ErrorStatus> executeLaunchStatus =
+                preparedModel->execute_1_3(request, measure, executionCallback);
+        ASSERT_TRUE(executeLaunchStatus.isOk());
+        ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
+
+        executionCallback->wait();
+        ErrorStatus executionReturnStatus = executionCallback->getStatus();
+        const auto& outputShapes = executionCallback->getOutputShapes();
+        Timing timing = executionCallback->getTiming();
+        ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
+        ASSERT_EQ(outputShapes.size(), 0);
+        ASSERT_TRUE(badTiming(timing));
+    }
+
+    // synchronous
+    {
+        SCOPED_TRACE(message + " [executeSynchronously]");
+
+        Return<void> executeStatus = preparedModel->executeSynchronously(
+                request, measure,
+                [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
+                   const Timing& timing) {
+                    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+                    EXPECT_EQ(outputShapes.size(), 0);
+                    EXPECT_TRUE(badTiming(timing));
+                });
+        ASSERT_TRUE(executeStatus.isOk());
+    }
+
+    // burst
+    {
+        SCOPED_TRACE(message + " [burst]");
+
+        // create burst
+        std::shared_ptr<::android::nn::ExecutionBurstController> burst =
+                android::nn::ExecutionBurstController::create(preparedModel,
+                                                              std::chrono::microseconds{0});
+        ASSERT_NE(nullptr, burst.get());
+
+        // create memory keys
+        std::vector<intptr_t> keys(request.pools.size());
+        for (size_t i = 0; i < keys.size(); ++i) {
+            keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
+        }
+
+        // execute and verify
+        const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys);
+        const ErrorStatus status = nn::convertResultCodeToErrorStatus(n);
+        EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+        EXPECT_EQ(outputShapes.size(), 0);
+        EXPECT_TRUE(badTiming(timing));
+        EXPECT_FALSE(fallback);
+
+        // additional burst testing
+        if (request.pools.size() > 0) {
+            // valid free
+            burst->freeMemory(keys.front());
+
+            // negative test: invalid free of unknown (blank) memory
+            burst->freeMemory(intptr_t{});
+
+            // negative test: double free of memory
+            burst->freeMemory(keys.front());
+        }
+    }
+}
+
+///////////////////////// REMOVE INPUT ////////////////////////////////////
+
+static void removeInputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    for (size_t input = 0; input < request.inputs.size(); ++input) {
+        const std::string message = "removeInput: removed input " + std::to_string(input);
+        validate(preparedModel, message, request,
+                 [input](Request* request) { hidl_vec_removeAt(&request->inputs, input); });
+    }
+}
+
+///////////////////////// REMOVE OUTPUT ////////////////////////////////////
+
+static void removeOutputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    for (size_t output = 0; output < request.outputs.size(); ++output) {
+        const std::string message = "removeOutput: removed Output " + std::to_string(output);
+        validate(preparedModel, message, request,
+                 [output](Request* request) { hidl_vec_removeAt(&request->outputs, output); });
+    }
+}
+
+///////////////////////////// ENTRY POINT //////////////////////////////////
+
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    removeInputTest(preparedModel, request);
+    removeOutputTest(preparedModel, request);
+}
+
+void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    SCOPED_TRACE("Expecting request to fail [executeSynchronously]");
+    Return<void> executeStatus = preparedModel->executeSynchronously(
+            request, MeasureTiming::NO,
+            [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
+                ASSERT_NE(ErrorStatus::NONE, error);
+                EXPECT_EQ(outputShapes.size(), 0);
+                EXPECT_TRUE(badTiming(timing));
+            });
+    ASSERT_TRUE(executeStatus.isOk());
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
new file mode 100644
index 0000000..92d8fa7
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+#include <android-base/logging.h>
+#include <hidl/ServiceManagement.h>
+#include <string>
+#include <utility>
+#include "1.0/Utils.h"
+#include "1.3/Callbacks.h"
+#include "GeneratedTestHarness.h"
+#include "TestHarness.h"
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using HidlToken =
+        hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+using implementation::PreparedModelCallback;
+using V1_0::ErrorStatus;
+using V1_0::Request;
+using V1_1::ExecutionPreference;
+
+// internal helper function
+void createPreparedModel(const sp<IDevice>& device, const Model& model,
+                         sp<IPreparedModel>* preparedModel, bool reportSkipping) {
+    ASSERT_NE(nullptr, preparedModel);
+    *preparedModel = nullptr;
+
+    // see if service can handle model
+    bool fullySupportsModel = false;
+    const Return<void> supportedCall = device->getSupportedOperations_1_3(
+            model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
+                ASSERT_EQ(ErrorStatus::NONE, status);
+                ASSERT_NE(0ul, supported.size());
+                fullySupportsModel = std::all_of(supported.begin(), supported.end(),
+                                                 [](bool valid) { return valid; });
+            });
+    ASSERT_TRUE(supportedCall.isOk());
+
+    // launch prepare model
+    const sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+    const Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3(
+            model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(),
+            hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
+    ASSERT_TRUE(prepareLaunchStatus.isOk());
+    ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+    // retrieve prepared model
+    preparedModelCallback->wait();
+    const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    *preparedModel = getPreparedModel_1_3(preparedModelCallback);
+
+    // The getSupportedOperations_1_3 call returns a list of operations that are
+    // guaranteed not to fail if prepareModel_1_3 is called, and
+    // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
+    // If a driver has any doubt that it can prepare an operation, it must
+    // return false. So here, if a driver isn't sure if it can support an
+    // operation, but reports that it successfully prepared the model, the test
+    // can continue.
+    if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
+        ASSERT_EQ(nullptr, preparedModel->get());
+        if (!reportSkipping) {
+            return;
+        }
+        LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare "
+                     "model that it does not support.";
+        std::cout << "[          ]   Early termination of test because vendor service cannot "
+                     "prepare model that it does not support."
+                  << std::endl;
+        GTEST_SKIP();
+    }
+    ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+    ASSERT_NE(nullptr, preparedModel->get());
+}
+
+void NeuralnetworksHidlTest::SetUp() {
+    testing::TestWithParam<NeuralnetworksHidlTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
+}
+
+static NamedDevice makeNamedDevice(const std::string& name) {
+    return {name, IDevice::getService(name)};
+}
+
+static std::vector<NamedDevice> getNamedDevicesImpl() {
+    // Retrieves the name of all service instances that implement IDevice,
+    // including any Lazy HAL instances.
+    const std::vector<std::string> names = hardware::getAllHalInstanceNames(IDevice::descriptor);
+
+    // Get a handle to each device and pair it with its name.
+    std::vector<NamedDevice> namedDevices;
+    namedDevices.reserve(names.size());
+    std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice);
+    return namedDevices;
+}
+
+const std::vector<NamedDevice>& getNamedDevices() {
+    const static std::vector<NamedDevice> devices = getNamedDevicesImpl();
+    return devices;
+}
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info) {
+    return gtestCompliantName(getName(info.param));
+}
+
+INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest);
+
+// Forward declaration from ValidateModel.cpp
+void validateModel(const sp<IDevice>& device, const Model& model);
+// Forward declaration from ValidateRequest.cpp
+void validateRequest(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+// Forward declaration from ValidateRequest.cpp
+void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+// Forward declaration from ValidateBurst.cpp
+void validateBurst(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+
+void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request) {
+    validateModel(device, model);
+
+    // Create IPreparedModel.
+    sp<IPreparedModel> preparedModel;
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
+
+    validateRequest(preparedModel, request);
+    validateBurst(preparedModel, request);
+}
+
+void validateFailure(const sp<IDevice>& device, const Model& model, const Request& request) {
+    // TODO: Should this always succeed?
+    //       What if the invalid input is part of the model (i.e., a parameter).
+    validateModel(device, model);
+
+    // Create IPreparedModel.
+    sp<IPreparedModel> preparedModel;
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
+
+    validateRequestFailure(preparedModel, request);
+}
+
+TEST_P(ValidationTest, Test) {
+    const Model model = createModel(kTestModel);
+    const Request request = createRequest(kTestModel);
+    if (kTestModel.expectFailure) {
+        validateFailure(kDevice, model, request);
+    } else {
+        validateEverything(kDevice, model, request);
+    }
+}
+
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+
+sp<IPreparedModel> getPreparedModel_1_3(const sp<PreparedModelCallback>& callback) {
+    sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
+    return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
new file mode 100644
index 0000000..4e51052
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H
+
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <gtest/gtest.h>
+#include "1.0/Utils.h"
+#include "1.3/Callbacks.h"
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using NamedDevice = Named<sp<IDevice>>;
+using NeuralnetworksHidlTestParam = NamedDevice;
+
+class NeuralnetworksHidlTest : public testing::TestWithParam<NeuralnetworksHidlTestParam> {
+  protected:
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(GetParam());
+};
+
+const std::vector<NamedDevice>& getNamedDevices();
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info);
+
+#define INSTANTIATE_DEVICE_TEST(TestSuite)                                                 \
+    INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \
+                             printNeuralnetworksHidlTest)
+
+// Create an IPreparedModel object. If the model cannot be prepared,
+// "preparedModel" will be nullptr instead.
+void createPreparedModel(const sp<IDevice>& device, const Model& model,
+                         sp<IPreparedModel>* preparedModel, bool reportSkipping = true);
+
+// Utility function to get PreparedModel from callback and downcast to V1_2.
+sp<IPreparedModel> getPreparedModel_1_3(const sp<implementation::PreparedModelCallback>& callback);
+
+}  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
+
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H
diff --git a/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h b/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h
new file mode 100644
index 0000000..fb19a84
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_CALLBACKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_CALLBACKS_H
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
+#include <hidl/Status.h>
+#include <condition_variable>
+#include <mutex>
+
+/*
+ * The Callback classes are used internally by the NeuralNetworks runtime to
+ * synchronize between different threads. An asynchronous task is launched
+ * paired with a callback object. When a client thread requires the output being
+ * generated by the asynchronous task, the client thread can wait for the result
+ * and be blocked until it has completed. Any wait may safely be called
+ * concurrently, even on the same callback object. When the asynchronous task
+ * has finished its workload, it must immediately call "notify*". If the
+ * asynchronous task has failed to launch, the function that tried to launch the
+ * asynchronous task must immediately call "notify*". This "notify*" call
+ * awakens any client threads waiting on the callback object.
+ *
+ * These classes exist to enable synchronization across HIDL. When
+ * synchronization is only required in the same process, consider using
+ * std::future, std::mutex, std::condition_variable, or std::experimental::latch
+ * instead.
+ */
+
+namespace android::hardware::neuralnetworks::V1_3::implementation {
+
+/**
+ * The PreparedModelCallback class is used to receive the error status of
+ * preparing a model as well as the prepared model from a task executing
+ * asynchronously with respect to the runtime. If a calling thread calls wait
+ * or get* on a PreparedModelCallback object and the corresponding asynchronous
+ * task has not finished preparing the model, the calling thread will block
+ * until the asynchronous task has called notify*.
+ *
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify* are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IDevice::prepareModel*.
+ */
+class PreparedModelCallback : public IPreparedModelCallback {
+  public:
+    /**
+     * IPreparedModelCallback::notify marks the callback object with the return
+     * status of the asynchronous model preparation along with the prepared
+     * model, and allows all prior and future wait calls on the
+     * PreparedModelCallback object to proceed.
+     *
+     * One of IPreparedModelCallback::notify, IPreparedModelCallback::notify_1_2,
+     * or IPreparedModelCallback::notify_1_3 must be called on a given
+     * PreparedModelCallback object.
+     *
+     * If the callback object is notified more than once, only the results of
+     * the first call to notify* are used, and the results from subsequent calls
+     * are discarded.
+     *
+     * @param status Error status returned from asynchronously preparing the
+     *     model; will be:
+     *     - NONE if the asynchronous preparation was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if the input model is invalid
+     * @param preparedModel Returned model that has been prepared for execution,
+     *     nullptr if the model was unable to be prepared.
+     */
+    Return<void> notify(V1_0::ErrorStatus status,
+                        const sp<V1_0::IPreparedModel>& preparedModel) override;
+
+    /**
+     * IPreparedModelCallback::notify_1_2 marks the callback object with the
+     * return status of the asynchronous model preparation along with the
+     * prepared model, and allows all prior and future wait calls on the
+     * PreparedModelCallback object to proceed.
+     *
+     * One of IPreparedModelCallback::notify, IPreparedModelCallback::notify_1_2,
+     * or IPreparedModelCallback::notify_1_3 must be called on a given
+     * PreparedModelCallback object.
+     *
+     * If the callback object is notified more than once, only the results of
+     * the first call to notify* are used, and the results from subsequent calls
+     * are discarded.
+     *
+     * @param status Error status returned from asynchronously preparing the
+     *     model; will be:
+     *     - NONE if the asynchronous preparation was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if the input model is invalid
+     * @param preparedModel Returned model that has been prepared for execution,
+     *     nullptr if the model was unable to be prepared.
+     */
+    Return<void> notify_1_2(V1_0::ErrorStatus status,
+                            const sp<V1_2::IPreparedModel>& preparedModel) override;
+
+    /**
+     * IPreparedModelCallback::notify_1_3 marks the callback object with the
+     * return status of the asynchronous model preparation along with the
+     * prepared model, and allows all prior and future wait calls on the
+     * PreparedModelCallback object to proceed.
+     *
+     * One of IPreparedModelCallback::notify, IPreparedModelCallback::notify_1_2,
+     * or IPreparedModelCallback::notify_1_3 must be called on a given
+     * PreparedModelCallback object.
+     *
+     * If the callback object is notified more than once, only the results of
+     * the first call to notify* are used, and the results from subsequent calls
+     * are discarded.
+     *
+     * @param status Error status returned from asynchronously preparing the
+     *     model; will be:
+     *     - NONE if the asynchronous preparation was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if the input model is invalid
+     * @param preparedModel Returned model that has been prepared for execution,
+     *     nullptr if the model was unable to be prepared.
+     */
+    Return<void> notify_1_3(V1_0::ErrorStatus status,
+                            const sp<V1_3::IPreparedModel>& preparedModel) override;
+
+    /**
+     * PreparedModelCallback::wait blocks until notify* has been called on the
+     * callback object.
+     */
+    void wait() const;
+
+    /**
+     * Retrieves the error status returned from the asynchronous task launched
+     * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished
+     * asynchronously preparing the model, this call will block until the
+     * asynchronous task notifies the object.
+     *
+     * @return status Error status returned from asynchronously preparing the
+     *     model; will be:
+     *     - NONE if the asynchronous preparation was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if the input model is invalid
+     */
+    V1_0::ErrorStatus getStatus() const;
+
+    /**
+     * Retrieves the model that has been prepared for execution from the
+     * asynchronous task launched by IDevice::prepareModel*. If
+     * IDevice::prepareModel* has not finished asynchronously preparing the
+     * model, this call will block until the asynchronous task notifies the
+     * object.
+     *
+     * @return preparedModel Returned model that has been prepared for
+     *     execution, nullptr if the model was unable to be prepared.
+     */
+    sp<V1_0::IPreparedModel> getPreparedModel() const;
+
+  private:
+    mutable std::mutex mMutex;
+    mutable std::condition_variable mCondition;
+    bool mNotified GUARDED_BY(mMutex) = false;
+    V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE;
+    sp<V1_0::IPreparedModel> mPreparedModel;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_3::implementation
+
+#endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_CALLBACKS_H
diff --git a/neuralnetworks/TEST_MAPPING b/neuralnetworks/TEST_MAPPING
index 50b6c19..0cefffa 100644
--- a/neuralnetworks/TEST_MAPPING
+++ b/neuralnetworks/TEST_MAPPING
@@ -1,26 +1,46 @@
 {
   "presubmit": [
     {
-      "name": "PresubmitHalNeuralnetworksV1_0TargetTest",
+      "name": "VtsHalNeuralnetworksV1_0TargetTest",
       "options": [
         {
-          "native-test-flag": "--hal_service_instance=android.hardware.neuralnetworks@1.0::IDevice/sample-all"
+          // Do not use any sample driver except sample-all in order to reduce
+          // testing time. The other sample drivers (fast-float, quant, etc.)
+          // are subsets of sample-all.
+          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
         }
       ]
     },
     {
-      "name": "PresubmitHalNeuralnetworksV1_1TargetTest",
+      "name": "VtsHalNeuralnetworksV1_1TargetTest",
       "options": [
         {
-          "native-test-flag": "--hal_service_instance=android.hardware.neuralnetworks@1.1::IDevice/sample-all"
+          // Do not use any sample driver except sample-all in order to reduce
+          // testing time. The other sample drivers (fast-float, quant, etc.)
+          // are subsets of sample-all.
+          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
         }
       ]
     },
     {
-      "name": "PresubmitHalNeuralnetworksV1_2TargetTest",
+      "name": "VtsHalNeuralnetworksV1_2TargetTest",
       "options": [
         {
-          "native-test-flag": "--hal_service_instance=android.hardware.neuralnetworks@1.2::IDevice/sample-all"
+          // Do not use any sample driver except sample-all in order to reduce
+          // testing time. The other sample drivers (fast-float, quant, etc.)
+          // are subsets of sample-all.
+          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
+        }
+      ]
+    },
+    {
+      "name": "VtsHalNeuralnetworksV1_3TargetTest",
+      "options": [
+        {
+          // Do not use any sample driver except sample-all in order to reduce
+          // testing time. The other sample drivers (fast-float, quant, etc.)
+          // are subsets of sample-all.
+          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
         }
       ]
     }
diff --git a/nfc/1.0/Android.bp b/nfc/1.0/Android.bp
index e0625d0..bd64907 100644
--- a/nfc/1.0/Android.bp
+++ b/nfc/1.0/Android.bp
@@ -17,4 +17,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/nfc/1.0/default/Android.bp b/nfc/1.0/default/Android.bp
index 3b53d16..9827edd 100644
--- a/nfc/1.0/default/Android.bp
+++ b/nfc/1.0/default/Android.bp
@@ -12,7 +12,6 @@
         "libcutils",
         "libutils",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.nfc@1.0",
     ],
 }
@@ -33,7 +32,6 @@
         "libutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.nfc@1.0",
     ],
 
diff --git a/nfc/1.0/default/android.hardware.nfc@1.0-service.rc b/nfc/1.0/default/android.hardware.nfc@1.0-service.rc
index 3a5c776..27e35d2 100644
--- a/nfc/1.0/default/android.hardware.nfc@1.0-service.rc
+++ b/nfc/1.0/default/android.hardware.nfc@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.nfc_hal_service /vendor/bin/hw/android.hardware.nfc@1.0-service
+    interface android.hardware.nfc@1.0::INfc default
     class hal
     user nfc
     group nfc
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/Android.bp b/nfc/1.1/Android.bp
index bbf49b2..1f8789f 100644
--- a/nfc/1.1/Android.bp
+++ b/nfc/1.1/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
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/Android.bp b/nfc/1.2/Android.bp
index cfb8b85..aa68d2f 100644
--- a/nfc/1.2/Android.bp
+++ b/nfc/1.2/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/nfc/1.2/vts/OWNERS b/nfc/1.2/vts/OWNERS
new file mode 100644
index 0000000..21d4df1
--- /dev/null
+++ b/nfc/1.2/vts/OWNERS
@@ -0,0 +1,3 @@
+zachoverflow@google.com
+jackcwyu@google.com
+georgekgchang@google.com
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/oemlock/1.0/Android.bp b/oemlock/1.0/Android.bp
index 894188b..e784be0 100644
--- a/oemlock/1.0/Android.bp
+++ b/oemlock/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/oemlock/1.0/vts/functional/Android.bp b/oemlock/1.0/vts/functional/Android.bp
index 28d6bf6..90de347 100644
--- a/oemlock/1.0/vts/functional/Android.bp
+++ b/oemlock/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalOemLockV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.oemlock@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp b/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp
index 05462a8..bafe87d 100644
--- a/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp
+++ b/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 #include <android/hardware/oemlock/1.0/IOemLock.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 using ::android::hardware::oemlock::V1_0::IOemLock;
 using ::android::hardware::oemlock::V1_0::OemLockStatus;
@@ -25,22 +25,9 @@
 using ::android::hardware::hidl_vec;
 using ::android::sp;
 
-// Test environment for OemLock HIDL HAL.
-class OemLockHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static OemLockHidlEnvironment* Instance() {
-        static OemLockHidlEnvironment* instance = new OemLockHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IOemLock>(); }
-};
-
-struct OemLockHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+struct OemLockHidlTest : public ::testing::TestWithParam<std::string> {
     virtual void SetUp() override {
-        oemlock = ::testing::VtsHalHidlTargetTestBase::getService<IOemLock>(
-            OemLockHidlEnvironment::Instance()->getServiceName<IOemLock>());
+        oemlock = IOemLock::getService(GetParam());
         ASSERT_NE(oemlock, nullptr);
     }
 
@@ -52,7 +39,7 @@
 /*
  * Check the name can be retrieved
  */
-TEST_F(OemLockHidlTest, GetName) {
+TEST_P(OemLockHidlTest, GetName) {
     std::string name;
     OemLockStatus status;
 
@@ -72,7 +59,7 @@
 /*
  * Check the unlock allowed by device state can be queried
  */
-TEST_F(OemLockHidlTest, QueryUnlockAllowedByDevice) {
+TEST_P(OemLockHidlTest, QueryUnlockAllowedByDevice) {
     bool allowed;
     OemLockStatus status;
 
@@ -92,7 +79,7 @@
 /*
  * Check unlock allowed by device state can be toggled
  */
-TEST_F(OemLockHidlTest, AllowedByDeviceCanBeToggled) {
+TEST_P(OemLockHidlTest, AllowedByDeviceCanBeToggled) {
     bool allowed;
     OemLockStatus status;
 
@@ -129,7 +116,7 @@
 /*
  * Check the unlock allowed by device state can be queried
  */
-TEST_F(OemLockHidlTest, QueryUnlockAllowedByCarrier) {
+TEST_P(OemLockHidlTest, QueryUnlockAllowedByCarrier) {
     bool allowed;
     OemLockStatus status;
 
@@ -153,7 +140,7 @@
  * is a valid implementation so the test will pass. If there is no signature
  * required, the test will toggle the value.
  */
-TEST_F(OemLockHidlTest, CarrierUnlock) {
+TEST_P(OemLockHidlTest, CarrierUnlock) {
     const hidl_vec<uint8_t> noSignature = {};
     bool allowed;
     OemLockStatus status;
@@ -201,11 +188,7 @@
     ASSERT_EQ(allowed, originallyAllowed);
 };
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(OemLockHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    OemLockHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, OemLockHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IOemLock::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/power/1.0/Android.bp b/power/1.0/Android.bp
index dbc0a36..6ba1d78 100644
--- a/power/1.0/Android.bp
+++ b/power/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/power/1.0/default/Android.bp b/power/1.0/default/Android.bp
index 4f43b95..1d152ee 100644
--- a/power/1.0/default/Android.bp
+++ b/power/1.0/default/Android.bp
@@ -28,7 +28,6 @@
         "liblog",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.power@1.0",
     ],
@@ -54,7 +53,6 @@
         "libutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.power@1.0",
     ],
 
diff --git a/power/1.0/default/android.hardware.power@1.0-service.rc b/power/1.0/default/android.hardware.power@1.0-service.rc
index 657c733..f3fd303 100644
--- a/power/1.0/default/android.hardware.power@1.0-service.rc
+++ b/power/1.0/default/android.hardware.power@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.power-hal-1-0 /vendor/bin/hw/android.hardware.power@1.0-service
+    interface android.hardware.power@1.0::IPower default
     class hal
     user system
     group system
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/Android.bp b/power/1.1/Android.bp
index de55396..6b133cc 100644
--- a/power/1.1/Android.bp
+++ b/power/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
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/Android.bp b/power/1.2/Android.bp
index 284e736..296965b 100644
--- a/power/1.2/Android.bp
+++ b/power/1.2/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
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/Android.bp b/power/1.3/Android.bp
index 320f1e6..00ca750 100644
--- a/power/1.3/Android.bp
+++ b/power/1.3/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-
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/Android.bp b/power/stats/1.0/Android.bp
index 9cf24cf..c592006 100644
--- a/power/stats/1.0/Android.bp
+++ b/power/stats/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/power/stats/1.0/default/Android.bp b/power/stats/1.0/default/Android.bp
index 7a09639..0321da1 100644
--- a/power/stats/1.0/default/Android.bp
+++ b/power/stats/1.0/default/Android.bp
@@ -25,7 +25,6 @@
         "libcutils",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.power.stats@1.0",
diff --git a/power/stats/1.0/default/PowerStats.cpp b/power/stats/1.0/default/PowerStats.cpp
index 78766f2..68275ce 100644
--- a/power/stats/1.0/default/PowerStats.cpp
+++ b/power/stats/1.0/default/PowerStats.cpp
@@ -87,7 +87,7 @@
     std::string railFileName;
     std::string spsFileName;
     uint32_t index = 0;
-    uint32_t samplingRate;
+    unsigned long samplingRate;
     for (const auto& path : mPm.devicePaths) {
         railFileName = path + "/enabled_rails";
         spsFileName = path + "/sampling_rate";
@@ -109,10 +109,11 @@
         while (std::getline(railNames, line)) {
             std::vector<std::string> words = android::base::Split(line, ":");
             if (words.size() == 2) {
-                mPm.railsInfo.emplace(words[0], RailData{.devicePath = path,
-                                                         .index = index,
-                                                         .subsysName = words[1],
-                                                         .samplingRate = samplingRate});
+                mPm.railsInfo.emplace(
+                        words[0], RailData{.devicePath = path,
+                                           .index = index,
+                                           .subsysName = words[1],
+                                           .samplingRate = static_cast<uint32_t>(samplingRate)});
                 index++;
             } else {
                 ALOGW("Unexpected format in file: %s", railFileName.c_str());
diff --git a/power/stats/1.0/vts/functional/Android.bp b/power/stats/1.0/vts/functional/Android.bp
index 4f0b325..ab47061 100644
--- a/power/stats/1.0/vts/functional/Android.bp
+++ b/power/stats/1.0/vts/functional/Android.bp
@@ -31,8 +31,7 @@
         "liblog",
         "libhidlbase",
         "libfmq",
-        "libhidltransport",
-        "libhwbinder",
         "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/prebuilt_hashes/28.txt b/prebuilt_hashes/28.txt
index cc15322..8a45ca5 100644
--- a/prebuilt_hashes/28.txt
+++ b/prebuilt_hashes/28.txt
@@ -348,6 +348,8 @@
 5e278fcaa3287d397d8eebe1c22aaa28150f5caae1cf9381cd6dc32cb37899c5 android.hardware.nfc@1.1::types
 163e115e833fc1d77cdd4a8cf0c833bb8b8d74fe35c880fe693101d17774926f android.hardware.power@1.2::IPower
 7899b9305587b2d5cd74a3cc87e9090f58bf4ae74256ce3ee36e7ec011822840 android.hardware.power@1.2::types
+5a464e6db53fad223986d655028a18185b73db8e2bfa9663f9042c9623eb0aa0 android.hardware.power@1.3::IPower
+a54a28d39b892d27a3cb06829181c038edcdd9e8eef359543b01e4313ae59aa0 android.hardware.power@1.3::types
 ab132c990a62f0aca35871c092c22fb9c85d478e22124ef6a4d0a2302da76a9f android.hardware.radio@1.2::IRadio
 cda752aeabaabc20486a82ac57a3dd107785c006094a349bc5e224e8aa22a17c android.hardware.radio@1.2::IRadioIndication
 da8c6ae991c6a4b284cc6e445332e064e28ee8a09482ed5afff9d159ec6694b7 android.hardware.radio@1.2::IRadioResponse
diff --git a/radio/1.0/Android.bp b/radio/1.0/Android.bp
index f023471..6765b4d 100644
--- a/radio/1.0/Android.bp
+++ b/radio/1.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/1.0/vts/functional/Android.bp b/radio/1.0/vts/functional/Android.bp
index 9dec2f2..2351d90 100644
--- a/radio/1.0/vts/functional/Android.bp
+++ b/radio/1.0/vts/functional/Android.bp
@@ -33,7 +33,8 @@
     static_libs: [
         "android.hardware.radio@1.0",
     ],
-    test_suites: ["general-tests"],
+    test_config: "vts_hal_radio_target_test.xml",
+    test_suites: ["general-tests", "vts-core"],
 }
 
 cc_test {
@@ -47,7 +48,8 @@
     static_libs: [
         "android.hardware.radio@1.0",
     ],
-    test_suites: ["general-tests"],
+    test_config: "vts_hal_sap_target_test.xml",
+    test_suites: ["general-tests", "vts-core"],
 }
 
 cc_library_static {
diff --git a/radio/1.0/vts/functional/VtsHalRadioV1_0TargetTest.cpp b/radio/1.0/vts/functional/VtsHalRadioV1_0TargetTest.cpp
index d53c062..9d61b52 100644
--- a/radio/1.0/vts/functional/VtsHalRadioV1_0TargetTest.cpp
+++ b/radio/1.0/vts/functional/VtsHalRadioV1_0TargetTest.cpp
@@ -14,12 +14,18 @@
  * limitations under the License.
  */
 
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <radio_hidl_hal_utils_v1_0.h>
 
+INSTANTIATE_TEST_SUITE_P(PerInstance, RadioHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 ::android::hardware::radio::V1_0::IRadio::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
+
 int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
-    RadioHidlEnvironment::Instance()->init(&argc, argv);
 
     // setup seed for rand function
     int seedSrand = time(NULL);
diff --git a/radio/1.0/vts/functional/VtsHalSapV1_0TargetTest.cpp b/radio/1.0/vts/functional/VtsHalSapV1_0TargetTest.cpp
index 859e6fb..b80b971 100644
--- a/radio/1.0/vts/functional/VtsHalSapV1_0TargetTest.cpp
+++ b/radio/1.0/vts/functional/VtsHalSapV1_0TargetTest.cpp
@@ -14,12 +14,18 @@
  * limitations under the License.
  */
 
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <sap_hidl_hal_utils.h>
 
+INSTANTIATE_TEST_SUITE_P(PerInstance, SapHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 ::android::hardware::radio::V1_0::ISap::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
+
 int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(SapHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
-    SapHidlEnvironment::Instance()->init(&argc, argv);
 
     // setup seed for rand function
     int seedSrand = time(NULL);
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp b/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp
index 2c1eb60..125ea0c 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp
@@ -21,7 +21,7 @@
 /*
  * Test IRadio.setGsmBroadcastConfig() for the response returned.
  */
-TEST_F(RadioHidlTest, setGsmBroadcastConfig) {
+TEST_P(RadioHidlTest, setGsmBroadcastConfig) {
     serial = GetRandomSerialNumber();
 
     // Create GsmBroadcastSmsConfigInfo #1
@@ -84,7 +84,7 @@
 /*
  * Test IRadio.getGsmBroadcastConfig() for the response returned.
  */
-TEST_F(RadioHidlTest, getGsmBroadcastConfig) {
+TEST_P(RadioHidlTest, getGsmBroadcastConfig) {
     serial = GetRandomSerialNumber();
 
     radio->getGsmBroadcastConfig(serial);
@@ -104,7 +104,7 @@
 /*
  * Test IRadio.setCdmaBroadcastConfig() for the response returned.
  */
-TEST_F(RadioHidlTest, setCdmaBroadcastConfig) {
+TEST_P(RadioHidlTest, setCdmaBroadcastConfig) {
     serial = GetRandomSerialNumber();
 
     CdmaBroadcastSmsConfigInfo cbSmsConfig;
@@ -131,7 +131,7 @@
 /*
  * Test IRadio.getCdmaBroadcastConfig() for the response returned.
  */
-TEST_F(RadioHidlTest, getCdmaBroadcastConfig) {
+TEST_P(RadioHidlTest, getCdmaBroadcastConfig) {
     serial = GetRandomSerialNumber();
 
     radio->getCdmaBroadcastConfig(serial);
@@ -149,7 +149,7 @@
 /*
  * Test IRadio.setCdmaBroadcastActivation() for the response returned.
  */
-TEST_F(RadioHidlTest, setCdmaBroadcastActivation) {
+TEST_P(RadioHidlTest, setCdmaBroadcastActivation) {
     serial = GetRandomSerialNumber();
     bool activate = false;
 
@@ -169,7 +169,7 @@
 /*
  * Test IRadio.setGsmBroadcastActivation() for the response returned.
  */
-TEST_F(RadioHidlTest, setGsmBroadcastActivation) {
+TEST_P(RadioHidlTest, setGsmBroadcastActivation) {
     serial = GetRandomSerialNumber();
     bool activate = false;
 
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_data.cpp b/radio/1.0/vts/functional/radio_hidl_hal_data.cpp
index eaef3ed..d937d74 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_data.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_data.cpp
@@ -21,7 +21,7 @@
 /*
  * Test IRadio.getDataRegistrationState() for the response returned.
  */
-TEST_F(RadioHidlTest, getDataRegistrationState) {
+TEST_P(RadioHidlTest, getDataRegistrationState) {
     serial = GetRandomSerialNumber();
 
     radio->getDataRegistrationState(serial);
@@ -99,7 +99,7 @@
 /*
  * Test IRadio.setupDataCall() for the response returned.
  */
-TEST_F(RadioHidlTest, setupDataCall) {
+TEST_P(RadioHidlTest, setupDataCall) {
     serial = GetRandomSerialNumber();
 
     RadioTechnology radioTechnology = RadioTechnology::LTE;
@@ -147,7 +147,7 @@
 /*
  * Test IRadio.deactivateDataCall() for the response returned.
  */
-TEST_F(RadioHidlTest, deactivateDataCall) {
+TEST_P(RadioHidlTest, deactivateDataCall) {
     serial = GetRandomSerialNumber();
     int cid = 1;
     bool reasonRadioShutDown = false;
@@ -169,7 +169,7 @@
 /*
  * Test IRadio.getDataCallList() for the response returned.
  */
-TEST_F(RadioHidlTest, getDataCallList) {
+TEST_P(RadioHidlTest, getDataCallList) {
     serial = GetRandomSerialNumber();
 
     radio->getDataCallList(serial);
@@ -188,7 +188,7 @@
 /*
  * Test IRadio.setInitialAttachApn() for the response returned.
  */
-TEST_F(RadioHidlTest, setInitialAttachApn) {
+TEST_P(RadioHidlTest, setInitialAttachApn) {
     serial = GetRandomSerialNumber();
 
     DataProfileInfo dataProfileInfo;
@@ -231,7 +231,7 @@
 /*
  * Test IRadio.setDataAllowed() for the response returned.
  */
-TEST_F(RadioHidlTest, setDataAllowed) {
+TEST_P(RadioHidlTest, setDataAllowed) {
     serial = GetRandomSerialNumber();
     bool allow = true;
 
@@ -249,7 +249,7 @@
 /*
  * Test IRadio.setDataProfile() for the response returned.
  */
-TEST_F(RadioHidlTest, setDataProfile) {
+TEST_P(RadioHidlTest, setDataProfile) {
     serial = GetRandomSerialNumber();
 
     // Create a dataProfileInfo
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp
index 2670d96..60cb2fe 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp
@@ -19,7 +19,7 @@
 /*
  * Test IRadio.getIccCardStatus() for the response returned.
  */
-TEST_F(RadioHidlTest, getIccCardStatus) {
+TEST_P(RadioHidlTest, getIccCardStatus) {
     EXPECT_LE(cardStatus.applications.size(), (unsigned int)RadioConst::CARD_MAX_APPS);
     EXPECT_LT(cardStatus.gsmUmtsSubscriptionAppIndex, (int)RadioConst::CARD_MAX_APPS);
     EXPECT_LT(cardStatus.cdmaSubscriptionAppIndex, (int)RadioConst::CARD_MAX_APPS);
@@ -29,7 +29,7 @@
 /*
  * Test IRadio.supplyIccPinForApp() for the response returned
  */
-TEST_F(RadioHidlTest, supplyIccPinForApp) {
+TEST_P(RadioHidlTest, supplyIccPinForApp) {
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -54,7 +54,7 @@
 /*
  * Test IRadio.supplyIccPukForApp() for the response returned.
  */
-TEST_F(RadioHidlTest, supplyIccPukForApp) {
+TEST_P(RadioHidlTest, supplyIccPukForApp) {
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -78,7 +78,7 @@
 /*
  * Test IRadio.supplyIccPin2ForApp() for the response returned.
  */
-TEST_F(RadioHidlTest, supplyIccPin2ForApp) {
+TEST_P(RadioHidlTest, supplyIccPin2ForApp) {
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -104,7 +104,7 @@
 /*
  * Test IRadio.supplyIccPuk2ForApp() for the response returned.
  */
-TEST_F(RadioHidlTest, supplyIccPuk2ForApp) {
+TEST_P(RadioHidlTest, supplyIccPuk2ForApp) {
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -128,7 +128,7 @@
 /*
  * Test IRadio.changeIccPinForApp() for the response returned.
  */
-TEST_F(RadioHidlTest, changeIccPinForApp) {
+TEST_P(RadioHidlTest, changeIccPinForApp) {
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -153,7 +153,7 @@
 /*
  * Test IRadio.changeIccPin2ForApp() for the response returned.
  */
-TEST_F(RadioHidlTest, changeIccPin2ForApp) {
+TEST_P(RadioHidlTest, changeIccPin2ForApp) {
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -179,7 +179,7 @@
 /*
  * Test IRadio.getImsiForApp() for the response returned.
  */
-TEST_F(RadioHidlTest, getImsiForApp) {
+TEST_P(RadioHidlTest, getImsiForApp) {
     serial = GetRandomSerialNumber();
 
     // Check success returned while getting imsi for 3GPP and 3GPP2 apps only
@@ -208,7 +208,7 @@
 /*
  * Test IRadio.iccIOForApp() for the response returned.
  */
-TEST_F(RadioHidlTest, iccIOForApp) {
+TEST_P(RadioHidlTest, iccIOForApp) {
     serial = GetRandomSerialNumber();
 
     for (int i = 0; i < (int)cardStatus.applications.size(); i++) {
@@ -233,7 +233,7 @@
 /*
  * Test IRadio.iccTransmitApduBasicChannel() for the response returned.
  */
-TEST_F(RadioHidlTest, iccTransmitApduBasicChannel) {
+TEST_P(RadioHidlTest, iccTransmitApduBasicChannel) {
     serial = GetRandomSerialNumber();
     SimApdu msg;
     memset(&msg, 0, sizeof(msg));
@@ -250,7 +250,7 @@
 /*
  * Test IRadio.iccOpenLogicalChannel() for the response returned.
  */
-TEST_F(RadioHidlTest, iccOpenLogicalChannel) {
+TEST_P(RadioHidlTest, iccOpenLogicalChannel) {
     serial = GetRandomSerialNumber();
     int p2 = 0x04;
     // Specified in ISO 7816-4 clause 7.1.1 0x04 means that FCP template is requested.
@@ -265,7 +265,7 @@
 /*
  * Test IRadio.iccCloseLogicalChannel() for the response returned.
  */
-TEST_F(RadioHidlTest, iccCloseLogicalChannel) {
+TEST_P(RadioHidlTest, iccCloseLogicalChannel) {
     serial = GetRandomSerialNumber();
     // Try closing invalid channel and check INVALID_ARGUMENTS returned as error
     radio->iccCloseLogicalChannel(serial, 0);
@@ -279,7 +279,7 @@
 /*
  * Test IRadio.iccTransmitApduLogicalChannel() for the response returned.
  */
-TEST_F(RadioHidlTest, iccTransmitApduLogicalChannel) {
+TEST_P(RadioHidlTest, iccTransmitApduLogicalChannel) {
     serial = GetRandomSerialNumber();
     SimApdu msg;
     memset(&msg, 0, sizeof(msg));
@@ -296,7 +296,7 @@
 /*
  * Test IRadio.requestIccSimAuthentication() for the response returned.
  */
-TEST_F(RadioHidlTest, requestIccSimAuthentication) {
+TEST_P(RadioHidlTest, requestIccSimAuthentication) {
     serial = GetRandomSerialNumber();
 
     // Pass wrong challenge string and check RadioError::INVALID_ARGUMENTS
@@ -315,7 +315,7 @@
 /*
  * Test IRadio.supplyNetworkDepersonalization() for the response returned.
  */
-TEST_F(RadioHidlTest, supplyNetworkDepersonalization) {
+TEST_P(RadioHidlTest, supplyNetworkDepersonalization) {
     serial = GetRandomSerialNumber();
 
     radio->supplyNetworkDepersonalization(serial, hidl_string("test"));
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp b/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp
index 4331c06..e253dcf 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp
@@ -21,7 +21,7 @@
 /*
  * Test IRadio.getClir() for the response returned.
  */
-TEST_F(RadioHidlTest, getClir) {
+TEST_P(RadioHidlTest, getClir) {
     serial = GetRandomSerialNumber();
 
     radio->getClir(serial);
@@ -39,7 +39,7 @@
 /*
  * Test IRadio.setClir() for the response returned.
  */
-TEST_F(RadioHidlTest, setClir) {
+TEST_P(RadioHidlTest, setClir) {
     serial = GetRandomSerialNumber();
     int32_t status = 1;
 
@@ -57,7 +57,7 @@
 /*
  * Test IRadio.getFacilityLockForApp() for the response returned.
  */
-TEST_F(RadioHidlTest, getFacilityLockForApp) {
+TEST_P(RadioHidlTest, getFacilityLockForApp) {
     serial = GetRandomSerialNumber();
     std::string facility = "";
     std::string password = "";
@@ -80,7 +80,7 @@
 /*
  * Test IRadio.setFacilityLockForApp() for the response returned.
  */
-TEST_F(RadioHidlTest, setFacilityLockForApp) {
+TEST_P(RadioHidlTest, setFacilityLockForApp) {
     serial = GetRandomSerialNumber();
     std::string facility = "";
     bool lockState = false;
@@ -104,7 +104,7 @@
 /*
  * Test IRadio.setBarringPassword() for the response returned.
  */
-TEST_F(RadioHidlTest, setBarringPassword) {
+TEST_P(RadioHidlTest, setBarringPassword) {
     serial = GetRandomSerialNumber();
     std::string facility = "";
     std::string oldPassword = "";
@@ -127,7 +127,7 @@
 /*
  * Test IRadio.getClip() for the response returned.
  */
-TEST_F(RadioHidlTest, getClip) {
+TEST_P(RadioHidlTest, getClip) {
     serial = GetRandomSerialNumber();
 
     radio->getClip(serial);
@@ -145,7 +145,7 @@
 /*
  * Test IRadio.setSuppServiceNotifications() for the response returned.
  */
-TEST_F(RadioHidlTest, setSuppServiceNotifications) {
+TEST_P(RadioHidlTest, setSuppServiceNotifications) {
     serial = GetRandomSerialNumber();
     bool enable = false;
 
@@ -164,7 +164,7 @@
 /*
  * Test IRadio.requestIsimAuthentication() for the response returned.
  */
-TEST_F(RadioHidlTest, requestIsimAuthentication) {
+TEST_P(RadioHidlTest, requestIsimAuthentication) {
     serial = GetRandomSerialNumber();
     std::string challenge = "";
 
@@ -186,7 +186,7 @@
 /*
  * Test IRadio.getImsRegistrationState() for the response returned.
  */
-TEST_F(RadioHidlTest, getImsRegistrationState) {
+TEST_P(RadioHidlTest, getImsRegistrationState) {
     serial = GetRandomSerialNumber();
 
     radio->getImsRegistrationState(serial);
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
index 3499762..d04cb36 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
@@ -19,7 +19,7 @@
 /*
  * Test IRadio.getSignalStrength() for the response returned.
  */
-TEST_F(RadioHidlTest, getSignalStrength) {
+TEST_P(RadioHidlTest, getSignalStrength) {
     serial = GetRandomSerialNumber();
 
     radio->getSignalStrength(serial);
@@ -35,7 +35,7 @@
 /*
  * Test IRadio.getVoiceRegistrationState() for the response returned.
  */
-TEST_F(RadioHidlTest, getVoiceRegistrationState) {
+TEST_P(RadioHidlTest, getVoiceRegistrationState) {
     serial = GetRandomSerialNumber();
 
     radio->getVoiceRegistrationState(serial);
@@ -51,7 +51,7 @@
 /*
  * Test IRadio.getOperator() for the response returned.
  */
-TEST_F(RadioHidlTest, getOperator) {
+TEST_P(RadioHidlTest, getOperator) {
     serial = GetRandomSerialNumber();
 
     radio->getOperator(serial);
@@ -67,7 +67,7 @@
 /*
  * Test IRadio.setRadioPower() for the response returned.
  */
-TEST_F(RadioHidlTest, setRadioPower) {
+TEST_P(RadioHidlTest, setRadioPower) {
     serial = GetRandomSerialNumber();
 
     radio->setRadioPower(serial, 1);
@@ -83,7 +83,7 @@
 /*
  * Test IRadio.getNetworkSelectionMode() for the response returned.
  */
-TEST_F(RadioHidlTest, getNetworkSelectionMode) {
+TEST_P(RadioHidlTest, getNetworkSelectionMode) {
     serial = GetRandomSerialNumber();
 
     radio->getNetworkSelectionMode(serial);
@@ -99,7 +99,7 @@
 /*
  * Test IRadio.setNetworkSelectionModeAutomatic() for the response returned.
  */
-TEST_F(RadioHidlTest, setNetworkSelectionModeAutomatic) {
+TEST_P(RadioHidlTest, setNetworkSelectionModeAutomatic) {
     serial = GetRandomSerialNumber();
 
     radio->setNetworkSelectionModeAutomatic(serial);
@@ -118,7 +118,7 @@
 /*
  * Test IRadio.setNetworkSelectionModeManual() for the response returned.
  */
-TEST_F(RadioHidlTest, setNetworkSelectionModeManual) {
+TEST_P(RadioHidlTest, setNetworkSelectionModeManual) {
     serial = GetRandomSerialNumber();
 
     radio->setNetworkSelectionModeManual(serial, "123456");
@@ -137,7 +137,7 @@
 /*
  * Test IRadio.getAvailableNetworks() for the response returned.
  */
-TEST_F(RadioHidlTest, getAvailableNetworks) {
+TEST_P(RadioHidlTest, getAvailableNetworks) {
     serial = GetRandomSerialNumber();
 
     radio->getAvailableNetworks(serial);
@@ -158,7 +158,7 @@
 /*
  * Test IRadio.getBasebandVersion() for the response returned.
  */
-TEST_F(RadioHidlTest, getBasebandVersion) {
+TEST_P(RadioHidlTest, getBasebandVersion) {
     serial = GetRandomSerialNumber();
 
     radio->getBasebandVersion(serial);
@@ -174,7 +174,7 @@
 /*
  * Test IRadio.setBandMode() for the response returned.
  */
-TEST_F(RadioHidlTest, setBandMode) {
+TEST_P(RadioHidlTest, setBandMode) {
     serial = GetRandomSerialNumber();
 
     radio->setBandMode(serial, RadioBandMode::BAND_MODE_USA);
@@ -191,7 +191,7 @@
 /*
  * Test IRadio.getAvailableBandModes() for the response returned.
  */
-TEST_F(RadioHidlTest, getAvailableBandModes) {
+TEST_P(RadioHidlTest, getAvailableBandModes) {
     serial = GetRandomSerialNumber();
 
     radio->getAvailableBandModes(serial);
@@ -207,7 +207,7 @@
 /*
  * Test IRadio.setPreferredNetworkType() for the response returned.
  */
-TEST_F(RadioHidlTest, setPreferredNetworkType) {
+TEST_P(RadioHidlTest, setPreferredNetworkType) {
     serial = GetRandomSerialNumber();
 
     radio->setPreferredNetworkType(serial, PreferredNetworkType::GSM_ONLY);
@@ -224,7 +224,7 @@
 /*
  * Test IRadio.getPreferredNetworkType() for the response returned.
  */
-TEST_F(RadioHidlTest, getPreferredNetworkType) {
+TEST_P(RadioHidlTest, getPreferredNetworkType) {
     serial = GetRandomSerialNumber();
 
     radio->getPreferredNetworkType(serial);
@@ -240,7 +240,7 @@
 /*
  * Test IRadio.getNeighboringCids() for the response returned.
  */
-TEST_F(RadioHidlTest, getNeighboringCids) {
+TEST_P(RadioHidlTest, getNeighboringCids) {
     serial = GetRandomSerialNumber();
 
     radio->getNeighboringCids(serial);
@@ -258,7 +258,7 @@
 /*
  * Test IRadio.setLocationUpdates() for the response returned.
  */
-TEST_F(RadioHidlTest, setLocationUpdates) {
+TEST_P(RadioHidlTest, setLocationUpdates) {
     serial = GetRandomSerialNumber();
 
     radio->setLocationUpdates(serial, true);
@@ -275,7 +275,7 @@
 /*
  * Test IRadio.setCdmaRoamingPreference() for the response returned.
  */
-TEST_F(RadioHidlTest, setCdmaRoamingPreference) {
+TEST_P(RadioHidlTest, setCdmaRoamingPreference) {
     serial = GetRandomSerialNumber();
 
     radio->setCdmaRoamingPreference(serial, CdmaRoamingType::HOME_NETWORK);
@@ -293,7 +293,7 @@
 /*
  * Test IRadio.getCdmaRoamingPreference() for the response returned.
  */
-TEST_F(RadioHidlTest, getCdmaRoamingPreference) {
+TEST_P(RadioHidlTest, getCdmaRoamingPreference) {
     serial = GetRandomSerialNumber();
 
     radio->getCdmaRoamingPreference(serial);
@@ -312,7 +312,7 @@
 /*
  * Test IRadio.getTTYMode() for the response returned.
  */
-TEST_F(RadioHidlTest, getTTYMode) {
+TEST_P(RadioHidlTest, getTTYMode) {
     serial = GetRandomSerialNumber();
 
     radio->getTTYMode(serial);
@@ -328,7 +328,7 @@
 /*
  * Test IRadio.setTTYMode() for the response returned.
  */
-TEST_F(RadioHidlTest, setTTYMode) {
+TEST_P(RadioHidlTest, setTTYMode) {
     serial = GetRandomSerialNumber();
 
     radio->setTTYMode(serial, TtyMode::OFF);
@@ -344,7 +344,7 @@
 /*
  * Test IRadio.setPreferredVoicePrivacy() for the response returned.
  */
-TEST_F(RadioHidlTest, setPreferredVoicePrivacy) {
+TEST_P(RadioHidlTest, setPreferredVoicePrivacy) {
     serial = GetRandomSerialNumber();
 
     radio->setPreferredVoicePrivacy(serial, true);
@@ -361,7 +361,7 @@
 /*
  * Test IRadio.getPreferredVoicePrivacy() for the response returned.
  */
-TEST_F(RadioHidlTest, getPreferredVoicePrivacy) {
+TEST_P(RadioHidlTest, getPreferredVoicePrivacy) {
     serial = GetRandomSerialNumber();
 
     radio->getPreferredVoicePrivacy(serial);
@@ -378,7 +378,7 @@
 /*
  * Test IRadio.getCDMASubscription() for the response returned.
  */
-TEST_F(RadioHidlTest, getCDMASubscription) {
+TEST_P(RadioHidlTest, getCDMASubscription) {
     serial = GetRandomSerialNumber();
 
     radio->getCDMASubscription(serial);
@@ -396,7 +396,7 @@
 /*
  * Test IRadio.getDeviceIdentity() for the response returned.
  */
-TEST_F(RadioHidlTest, getDeviceIdentity) {
+TEST_P(RadioHidlTest, getDeviceIdentity) {
     serial = GetRandomSerialNumber();
 
     radio->getDeviceIdentity(serial);
@@ -413,7 +413,7 @@
 /*
  * Test IRadio.exitEmergencyCallbackMode() for the response returned.
  */
-TEST_F(RadioHidlTest, exitEmergencyCallbackMode) {
+TEST_P(RadioHidlTest, exitEmergencyCallbackMode) {
     serial = GetRandomSerialNumber();
 
     radio->exitEmergencyCallbackMode(serial);
@@ -431,7 +431,7 @@
 /*
  * Test IRadio.getCdmaSubscriptionSource() for the response returned.
  */
-TEST_F(RadioHidlTest, getCdmaSubscriptionSource) {
+TEST_P(RadioHidlTest, getCdmaSubscriptionSource) {
     serial = GetRandomSerialNumber();
 
     radio->getCdmaSubscriptionSource(serial);
@@ -449,7 +449,7 @@
 /*
  * Test IRadio.setCdmaSubscriptionSource() for the response returned.
  */
-TEST_F(RadioHidlTest, setCdmaSubscriptionSource) {
+TEST_P(RadioHidlTest, setCdmaSubscriptionSource) {
     serial = GetRandomSerialNumber();
 
     radio->setCdmaSubscriptionSource(serial, CdmaSubscriptionSource::RUIM_SIM);
@@ -468,7 +468,7 @@
 /*
  * Test IRadio.getVoiceRadioTechnology() for the response returned.
  */
-TEST_F(RadioHidlTest, getVoiceRadioTechnology) {
+TEST_P(RadioHidlTest, getVoiceRadioTechnology) {
     serial = GetRandomSerialNumber();
 
     radio->getVoiceRadioTechnology(serial);
@@ -484,7 +484,7 @@
 /*
  * Test IRadio.getCellInfoList() for the response returned.
  */
-TEST_F(RadioHidlTest, getCellInfoList) {
+TEST_P(RadioHidlTest, getCellInfoList) {
     serial = GetRandomSerialNumber();
 
     radio->getCellInfoList(serial);
@@ -502,7 +502,7 @@
 /*
  * Test IRadio.setCellInfoListRate() for the response returned.
  */
-TEST_F(RadioHidlTest, setCellInfoListRate) {
+TEST_P(RadioHidlTest, setCellInfoListRate) {
     serial = GetRandomSerialNumber();
 
     // TODO(sanketpadawe): RIL crashes with value of rate = 10
@@ -520,7 +520,7 @@
 /*
  * Test IRadio.nvReadItem() for the response returned.
  */
-TEST_F(RadioHidlTest, nvReadItem) {
+TEST_P(RadioHidlTest, nvReadItem) {
     serial = GetRandomSerialNumber();
 
     radio->nvReadItem(serial, NvItem::LTE_BAND_ENABLE_25);
@@ -537,7 +537,7 @@
 /*
  * Test IRadio.nvWriteItem() for the response returned.
  */
-TEST_F(RadioHidlTest, nvWriteItem) {
+TEST_P(RadioHidlTest, nvWriteItem) {
     serial = GetRandomSerialNumber();
     NvWriteItem item;
     memset(&item, 0, sizeof(item));
@@ -557,7 +557,7 @@
 /*
  * Test IRadio.nvWriteCdmaPrl() for the response returned.
  */
-TEST_F(RadioHidlTest, nvWriteCdmaPrl) {
+TEST_P(RadioHidlTest, nvWriteCdmaPrl) {
     serial = GetRandomSerialNumber();
     std::vector<uint8_t> prl = {1, 2, 3, 4, 5};
 
@@ -575,7 +575,7 @@
 /*
  * Test IRadio.nvResetConfig() for the response returned.
  */
-TEST_F(RadioHidlTest, nvResetConfig) {
+TEST_P(RadioHidlTest, nvResetConfig) {
     serial = GetRandomSerialNumber();
 
     radio->nvResetConfig(serial, ResetNvType::ERASE);
@@ -592,7 +592,7 @@
 /*
  * Test IRadio.setUiccSubscription() for the response returned.
  */
-TEST_F(RadioHidlTest, setUiccSubscription) {
+TEST_P(RadioHidlTest, setUiccSubscription) {
     serial = GetRandomSerialNumber();
     SelectUiccSub item;
     memset(&item, 0, sizeof(item));
@@ -614,7 +614,7 @@
 /*
  * Test IRadio.getHardwareConfig() for the response returned.
  */
-TEST_F(RadioHidlTest, getHardwareConfig) {
+TEST_P(RadioHidlTest, getHardwareConfig) {
     serial = GetRandomSerialNumber();
 
     radio->getHardwareConfig(serial);
@@ -631,7 +631,7 @@
 /*
  * Test IRadio.requestShutdown() for the response returned.
  */
-TEST_F(RadioHidlTest, requestShutdown) {
+TEST_P(RadioHidlTest, requestShutdown) {
     serial = GetRandomSerialNumber();
 
     radio->requestShutdown(serial);
@@ -648,7 +648,7 @@
 /*
  * Test IRadio.getRadioCapability() for the response returned.
  */
-TEST_F(RadioHidlTest, getRadioCapability) {
+TEST_P(RadioHidlTest, getRadioCapability) {
     serial = GetRandomSerialNumber();
 
     radio->getRadioCapability(serial);
@@ -664,7 +664,7 @@
 /*
  * Test IRadio.setRadioCapability() for the response returned.
  */
-TEST_F(RadioHidlTest, setRadioCapability) {
+TEST_P(RadioHidlTest, setRadioCapability) {
     serial = GetRandomSerialNumber();
     RadioCapability rc;
     memset(&rc, 0, sizeof(rc));
@@ -685,7 +685,7 @@
 /*
  * Test IRadio.startLceService() for the response returned.
  */
-TEST_F(RadioHidlTest, startLceService) {
+TEST_P(RadioHidlTest, startLceService) {
     serial = GetRandomSerialNumber();
 
     radio->startLceService(serial, 5, true);
@@ -704,7 +704,7 @@
 /*
  * Test IRadio.stopLceService() for the response returned.
  */
-TEST_F(RadioHidlTest, stopLceService) {
+TEST_P(RadioHidlTest, stopLceService) {
     serial = GetRandomSerialNumber();
 
     radio->stopLceService(serial);
@@ -722,7 +722,7 @@
 /*
  * Test IRadio.pullLceData() for the response returned.
  */
-TEST_F(RadioHidlTest, pullLceData) {
+TEST_P(RadioHidlTest, pullLceData) {
     serial = GetRandomSerialNumber();
 
     radio->pullLceData(serial);
@@ -741,7 +741,7 @@
 /*
  * Test IRadio.getModemActivityInfo() for the response returned.
  */
-TEST_F(RadioHidlTest, getModemActivityInfo) {
+TEST_P(RadioHidlTest, getModemActivityInfo) {
     serial = GetRandomSerialNumber();
 
     radio->getModemActivityInfo(serial);
@@ -758,7 +758,7 @@
 /*
  * Test IRadio.setAllowedCarriers() for the response returned.
  */
-TEST_F(RadioHidlTest, setAllowedCarriers) {
+TEST_P(RadioHidlTest, setAllowedCarriers) {
     serial = GetRandomSerialNumber();
     CarrierRestrictions carriers;
     memset(&carriers, 0, sizeof(carriers));
@@ -835,7 +835,7 @@
 /*
  * Test IRadio.getAllowedCarriers() for the response returned.
  */
-TEST_F(RadioHidlTest, getAllowedCarriers) {
+TEST_P(RadioHidlTest, getAllowedCarriers) {
     serial = GetRandomSerialNumber();
 
     radio->getAllowedCarriers(serial);
@@ -852,7 +852,7 @@
 /*
  * Test IRadio.sendDeviceState() for the response returned.
  */
-TEST_F(RadioHidlTest, sendDeviceState) {
+TEST_P(RadioHidlTest, sendDeviceState) {
     serial = GetRandomSerialNumber();
 
     radio->sendDeviceState(serial, DeviceStateType::POWER_SAVE_MODE, true);
@@ -871,7 +871,7 @@
 /*
  * Test IRadio.setIndicationFilter() for the response returned.
  */
-TEST_F(RadioHidlTest, setIndicationFilter) {
+TEST_P(RadioHidlTest, setIndicationFilter) {
     serial = GetRandomSerialNumber();
 
     radio->setIndicationFilter(serial, 1);
@@ -890,7 +890,7 @@
 /*
  * Test IRadio.setSimCardPower() for the response returned.
  */
-TEST_F(RadioHidlTest, setSimCardPower) {
+TEST_P(RadioHidlTest, setSimCardPower) {
     serial = GetRandomSerialNumber();
 
     radio->setSimCardPower(serial, true);
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp b/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp
index 9e41429..58c3bbd 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp
@@ -21,7 +21,7 @@
 /*
  * Test IRadio.sendSms() for the response returned.
  */
-TEST_F(RadioHidlTest, sendSms) {
+TEST_P(RadioHidlTest, sendSms) {
     serial = GetRandomSerialNumber();
     GsmSmsMessage msg;
     msg.smscPdu = "";
@@ -45,7 +45,7 @@
 /*
  * Test IRadio.sendSMSExpectMore() for the response returned.
  */
-TEST_F(RadioHidlTest, sendSMSExpectMore) {
+TEST_P(RadioHidlTest, sendSMSExpectMore) {
     serial = GetRandomSerialNumber();
     GsmSmsMessage msg;
     msg.smscPdu = "";
@@ -71,7 +71,7 @@
 /*
  * Test IRadio.acknowledgeLastIncomingGsmSms() for the response returned.
  */
-TEST_F(RadioHidlTest, acknowledgeLastIncomingGsmSms) {
+TEST_P(RadioHidlTest, acknowledgeLastIncomingGsmSms) {
     serial = GetRandomSerialNumber();
     bool success = true;
 
@@ -92,7 +92,7 @@
 /*
  * Test IRadio.acknowledgeIncomingGsmSmsWithPdu() for the response returned.
  */
-TEST_F(RadioHidlTest, acknowledgeIncomingGsmSmsWithPdu) {
+TEST_P(RadioHidlTest, acknowledgeIncomingGsmSmsWithPdu) {
     serial = GetRandomSerialNumber();
     bool success = true;
     std::string ackPdu = "";
@@ -111,7 +111,7 @@
 /*
  * Test IRadio.sendCdmaSms() for the response returned.
  */
-TEST_F(RadioHidlTest, sendCdmaSms) {
+TEST_P(RadioHidlTest, sendCdmaSms) {
     serial = GetRandomSerialNumber();
 
     // Create a CdmaSmsAddress
@@ -155,7 +155,7 @@
 /*
  * Test IRadio.acknowledgeLastIncomingCdmaSms() for the response returned.
  */
-TEST_F(RadioHidlTest, acknowledgeLastIncomingCdmaSms) {
+TEST_P(RadioHidlTest, acknowledgeLastIncomingCdmaSms) {
     serial = GetRandomSerialNumber();
 
     // Create a CdmaSmsAck
@@ -179,7 +179,7 @@
 /*
  * Test IRadio.sendImsSms() for the response returned.
  */
-TEST_F(RadioHidlTest, sendImsSms) {
+TEST_P(RadioHidlTest, sendImsSms) {
     serial = GetRandomSerialNumber();
 
     // Create a CdmaSmsAddress
@@ -229,7 +229,7 @@
 /*
  * Test IRadio.getSmscAddress() for the response returned.
  */
-TEST_F(RadioHidlTest, getSmscAddress) {
+TEST_P(RadioHidlTest, getSmscAddress) {
     serial = GetRandomSerialNumber();
 
     radio->getSmscAddress(serial);
@@ -249,7 +249,7 @@
 /*
  * Test IRadio.setSmscAddress() for the response returned.
  */
-TEST_F(RadioHidlTest, setSmscAddress) {
+TEST_P(RadioHidlTest, setSmscAddress) {
     serial = GetRandomSerialNumber();
     hidl_string address = hidl_string("smscAddress");
 
@@ -270,7 +270,7 @@
 /*
  * Test IRadio.writeSmsToSim() for the response returned.
  */
-TEST_F(RadioHidlTest, writeSmsToSim) {
+TEST_P(RadioHidlTest, writeSmsToSim) {
     serial = GetRandomSerialNumber();
     SmsWriteArgs smsWriteArgs;
     smsWriteArgs.status = SmsWriteArgsStatus::REC_UNREAD;
@@ -296,7 +296,7 @@
 /*
  * Test IRadio.deleteSmsOnSim() for the response returned.
  */
-TEST_F(RadioHidlTest, deleteSmsOnSim) {
+TEST_P(RadioHidlTest, deleteSmsOnSim) {
     serial = GetRandomSerialNumber();
     int index = 1;
 
@@ -319,7 +319,7 @@
 /*
  * Test IRadio.writeSmsToRuim() for the response returned.
  */
-TEST_F(RadioHidlTest, writeSmsToRuim) {
+TEST_P(RadioHidlTest, writeSmsToRuim) {
     serial = GetRandomSerialNumber();
 
     // Create a CdmaSmsAddress
@@ -370,7 +370,7 @@
 /*
  * Test IRadio.deleteSmsOnRuim() for the response returned.
  */
-TEST_F(RadioHidlTest, deleteSmsOnRuim) {
+TEST_P(RadioHidlTest, deleteSmsOnRuim) {
     serial = GetRandomSerialNumber();
     int index = 1;
 
@@ -421,7 +421,7 @@
 /*
  * Test IRadio.reportSmsMemoryStatus() for the response returned.
  */
-TEST_F(RadioHidlTest, reportSmsMemoryStatus) {
+TEST_P(RadioHidlTest, reportSmsMemoryStatus) {
     serial = GetRandomSerialNumber();
     bool available = true;
 
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp b/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp
index a3b5029..1170111 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp
@@ -21,7 +21,7 @@
 /*
  * Test IRadio.sendEnvelope() for the response returned.
  */
-TEST_F(RadioHidlTest, sendEnvelope) {
+TEST_P(RadioHidlTest, sendEnvelope) {
     serial = GetRandomSerialNumber();
 
     // Test with sending empty string
@@ -44,7 +44,7 @@
 /*
  * Test IRadio.sendTerminalResponseToSim() for the response returned.
  */
-TEST_F(RadioHidlTest, sendTerminalResponseToSim) {
+TEST_P(RadioHidlTest, sendTerminalResponseToSim) {
     serial = GetRandomSerialNumber();
 
     // Test with sending empty string
@@ -67,7 +67,7 @@
 /*
  * Test IRadio.handleStkCallSetupRequestFromSim() for the response returned.
  */
-TEST_F(RadioHidlTest, handleStkCallSetupRequestFromSim) {
+TEST_P(RadioHidlTest, handleStkCallSetupRequestFromSim) {
     serial = GetRandomSerialNumber();
     bool accept = false;
 
@@ -88,7 +88,7 @@
 /*
  * Test IRadio.reportStkServiceIsRunning() for the response returned.
  */
-TEST_F(RadioHidlTest, reportStkServiceIsRunning) {
+TEST_P(RadioHidlTest, reportStkServiceIsRunning) {
     serial = GetRandomSerialNumber();
 
     radio->reportStkServiceIsRunning(serial);
@@ -107,7 +107,7 @@
  * Test IRadio.sendEnvelopeWithStatus() for the response returned with empty
  * string.
  */
-TEST_F(RadioHidlTest, sendEnvelopeWithStatus) {
+TEST_P(RadioHidlTest, sendEnvelopeWithStatus) {
     serial = GetRandomSerialNumber();
 
     // Test with sending empty string
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_test.cpp b/radio/1.0/vts/functional/radio_hidl_hal_test.cpp
index 96719d6..3c833c0 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_test.cpp
@@ -17,13 +17,10 @@
 #include <radio_hidl_hal_utils_v1_0.h>
 
 void RadioHidlTest::SetUp() {
-    radio = ::testing::VtsHalHidlTargetTestBase::getService<IRadio>(
-        RadioHidlEnvironment::Instance()->getServiceName<IRadio>(hidl_string(RADIO_SERVICE_NAME)));
+    radio = IRadio::getService(GetParam());
     if (radio == NULL) {
         sleep(60);
-        radio = ::testing::VtsHalHidlTargetTestBase::getService<IRadio>(
-            RadioHidlEnvironment::Instance()->getServiceName<IRadio>(
-                hidl_string(RADIO_SERVICE_NAME)));
+        radio = IRadio::getService(GetParam());
     }
     ASSERT_NE(nullptr, radio.get());
 
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_utils_v1_0.h b/radio/1.0/vts/functional/radio_hidl_hal_utils_v1_0.h
index 23bc434..8a551f7 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_utils_v1_0.h
+++ b/radio/1.0/vts/functional/radio_hidl_hal_utils_v1_0.h
@@ -16,8 +16,6 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -26,6 +24,7 @@
 #include <android/hardware/radio/1.0/IRadioIndication.h>
 #include <android/hardware/radio/1.0/IRadioResponse.h>
 #include <android/hardware/radio/1.0/types.h>
+#include <gtest/gtest.h>
 
 #include "vts_test_util.h"
 
@@ -515,23 +514,9 @@
                             const ::android::hardware::hidl_string& reason);
 };
 
-// Test environment for Radio HIDL HAL.
-class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static RadioHidlEnvironment* Instance() {
-        static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override { registerTestService<IRadio>(); }
-
-   private:
-    RadioHidlEnvironment() {}
-};
-
 // The main test class for Radio HIDL.
-class RadioHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class RadioHidlTest : public ::testing::TestWithParam<std::string> {
+  protected:
     std::mutex mtx;
     std::condition_variable cv;
     int count;
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
index 1fce470..a192a33 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
@@ -19,7 +19,7 @@
 /*
  * Test IRadio.getCurrentCalls() for the response returned.
  */
-TEST_F(RadioHidlTest, getCurrentCalls) {
+TEST_P(RadioHidlTest, getCurrentCalls) {
     serial = GetRandomSerialNumber();
 
     radio->getCurrentCalls(serial);
@@ -35,7 +35,7 @@
 /*
  * Test IRadio.dial() for the response returned.
  */
-TEST_F(RadioHidlTest, dial) {
+TEST_P(RadioHidlTest, dial) {
     serial = GetRandomSerialNumber();
 
     Dial dialInfo;
@@ -62,7 +62,7 @@
 /*
  * Test IRadio.hangup() for the response returned.
  */
-TEST_F(RadioHidlTest, hangup) {
+TEST_P(RadioHidlTest, hangup) {
     serial = GetRandomSerialNumber();
 
     radio->hangup(serial, 1);
@@ -81,7 +81,7 @@
 /*
  * Test IRadio.hangupWaitingOrBackground() for the response returned.
  */
-TEST_F(RadioHidlTest, hangupWaitingOrBackground) {
+TEST_P(RadioHidlTest, hangupWaitingOrBackground) {
     serial = GetRandomSerialNumber();
 
     radio->hangupWaitingOrBackground(serial);
@@ -99,7 +99,7 @@
 /*
  * Test IRadio.hangupForegroundResumeBackground() for the response returned.
  */
-TEST_F(RadioHidlTest, hangupForegroundResumeBackground) {
+TEST_P(RadioHidlTest, hangupForegroundResumeBackground) {
     serial = GetRandomSerialNumber();
 
     radio->hangupForegroundResumeBackground(serial);
@@ -117,7 +117,7 @@
 /*
  * Test IRadio.switchWaitingOrHoldingAndActive() for the response returned.
  */
-TEST_F(RadioHidlTest, switchWaitingOrHoldingAndActive) {
+TEST_P(RadioHidlTest, switchWaitingOrHoldingAndActive) {
     serial = GetRandomSerialNumber();
 
     radio->switchWaitingOrHoldingAndActive(serial);
@@ -135,7 +135,7 @@
 /*
  * Test IRadio.conference() for the response returned.
  */
-TEST_F(RadioHidlTest, conference) {
+TEST_P(RadioHidlTest, conference) {
     serial = GetRandomSerialNumber();
 
     radio->conference(serial);
@@ -153,7 +153,7 @@
 /*
  * Test IRadio.rejectCall() for the response returned.
  */
-TEST_F(RadioHidlTest, rejectCall) {
+TEST_P(RadioHidlTest, rejectCall) {
     serial = GetRandomSerialNumber();
 
     radio->rejectCall(serial);
@@ -171,7 +171,7 @@
 /*
  * Test IRadio.getLastCallFailCause() for the response returned.
  */
-TEST_F(RadioHidlTest, getLastCallFailCause) {
+TEST_P(RadioHidlTest, getLastCallFailCause) {
     serial = GetRandomSerialNumber();
 
     radio->getLastCallFailCause(serial);
@@ -188,7 +188,7 @@
 /*
  * Test IRadio.sendUssd() for the response returned.
  */
-TEST_F(RadioHidlTest, sendUssd) {
+TEST_P(RadioHidlTest, sendUssd) {
     serial = GetRandomSerialNumber();
     radio->sendUssd(serial, hidl_string("test"));
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -206,7 +206,7 @@
 /*
  * Test IRadio.cancelPendingUssd() for the response returned.
  */
-TEST_F(RadioHidlTest, cancelPendingUssd) {
+TEST_P(RadioHidlTest, cancelPendingUssd) {
     serial = GetRandomSerialNumber();
 
     radio->cancelPendingUssd(serial);
@@ -225,7 +225,7 @@
 /*
  * Test IRadio.getCallForwardStatus() for the response returned.
  */
-TEST_F(RadioHidlTest, getCallForwardStatus) {
+TEST_P(RadioHidlTest, getCallForwardStatus) {
     serial = GetRandomSerialNumber();
     CallForwardInfo callInfo;
     memset(&callInfo, 0, sizeof(callInfo));
@@ -247,7 +247,7 @@
 /*
  * Test IRadio.setCallForward() for the response returned.
  */
-TEST_F(RadioHidlTest, setCallForward) {
+TEST_P(RadioHidlTest, setCallForward) {
     serial = GetRandomSerialNumber();
     CallForwardInfo callInfo;
     memset(&callInfo, 0, sizeof(callInfo));
@@ -269,7 +269,7 @@
 /*
  * Test IRadio.getCallWaiting() for the response returned.
  */
-TEST_F(RadioHidlTest, getCallWaiting) {
+TEST_P(RadioHidlTest, getCallWaiting) {
     serial = GetRandomSerialNumber();
 
     radio->getCallWaiting(serial, 1);
@@ -288,7 +288,7 @@
 /*
  * Test IRadio.setCallWaiting() for the response returned.
  */
-TEST_F(RadioHidlTest, setCallWaiting) {
+TEST_P(RadioHidlTest, setCallWaiting) {
     serial = GetRandomSerialNumber();
 
     radio->setCallWaiting(serial, true, 1);
@@ -307,7 +307,7 @@
 /*
  * Test IRadio.acceptCall() for the response returned.
  */
-TEST_F(RadioHidlTest, acceptCall) {
+TEST_P(RadioHidlTest, acceptCall) {
     serial = GetRandomSerialNumber();
 
     radio->acceptCall(serial);
@@ -325,7 +325,7 @@
 /*
  * Test IRadio.separateConnection() for the response returned.
  */
-TEST_F(RadioHidlTest, separateConnection) {
+TEST_P(RadioHidlTest, separateConnection) {
     serial = GetRandomSerialNumber();
 
     radio->separateConnection(serial, 1);
@@ -344,7 +344,7 @@
 /*
  * Test IRadio.explicitCallTransfer() for the response returned.
  */
-TEST_F(RadioHidlTest, explicitCallTransfer) {
+TEST_P(RadioHidlTest, explicitCallTransfer) {
     serial = GetRandomSerialNumber();
 
     radio->explicitCallTransfer(serial);
@@ -362,7 +362,7 @@
 /*
  * Test IRadio.sendCDMAFeatureCode() for the response returned.
  */
-TEST_F(RadioHidlTest, sendCDMAFeatureCode) {
+TEST_P(RadioHidlTest, sendCDMAFeatureCode) {
     serial = GetRandomSerialNumber();
 
     radio->sendCDMAFeatureCode(serial, hidl_string());
@@ -382,7 +382,7 @@
 /*
  * Test IRadio.sendDtmf() for the response returned.
  */
-TEST_F(RadioHidlTest, sendDtmf) {
+TEST_P(RadioHidlTest, sendDtmf) {
     serial = GetRandomSerialNumber();
 
     radio->sendDtmf(serial, "1");
@@ -402,7 +402,7 @@
 /*
  * Test IRadio.startDtmf() for the response returned.
  */
-TEST_F(RadioHidlTest, startDtmf) {
+TEST_P(RadioHidlTest, startDtmf) {
     serial = GetRandomSerialNumber();
 
     radio->startDtmf(serial, "1");
@@ -422,7 +422,7 @@
 /*
  * Test IRadio.stopDtmf() for the response returned.
  */
-TEST_F(RadioHidlTest, stopDtmf) {
+TEST_P(RadioHidlTest, stopDtmf) {
     serial = GetRandomSerialNumber();
 
     radio->stopDtmf(serial);
@@ -441,7 +441,7 @@
 /*
  * Test IRadio.setMute() for the response returned.
  */
-TEST_F(RadioHidlTest, setMute) {
+TEST_P(RadioHidlTest, setMute) {
     serial = GetRandomSerialNumber();
 
     radio->setMute(serial, true);
@@ -459,7 +459,7 @@
 /*
  * Test IRadio.getMute() for the response returned.
  */
-TEST_F(RadioHidlTest, getMute) {
+TEST_P(RadioHidlTest, getMute) {
     serial = GetRandomSerialNumber();
 
     radio->getMute(serial);
@@ -475,7 +475,7 @@
 /*
  * Test IRadio.sendBurstDtmf() for the response returned.
  */
-TEST_F(RadioHidlTest, sendBurstDtmf) {
+TEST_P(RadioHidlTest, sendBurstDtmf) {
     serial = GetRandomSerialNumber();
 
     radio->sendBurstDtmf(serial, "1", 0, 0);
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_api.cpp b/radio/1.0/vts/functional/sap_hidl_hal_api.cpp
index 1d79ff6..6bd2c88 100644
--- a/radio/1.0/vts/functional/sap_hidl_hal_api.cpp
+++ b/radio/1.0/vts/functional/sap_hidl_hal_api.cpp
@@ -19,7 +19,7 @@
 /*
  * Test ISap.connectReq() for the response returned.
  */
-TEST_F(SapHidlTest, connectReq) {
+TEST_P(SapHidlTest, connectReq) {
     token = GetRandomSerialNumber();
     int32_t maxMsgSize = 100;
 
@@ -35,7 +35,7 @@
 /*
  * Test IRadio.disconnectReq() for the response returned
  */
-TEST_F(SapHidlTest, disconnectReq) {
+TEST_P(SapHidlTest, disconnectReq) {
     token = GetRandomSerialNumber();
 
     sap->disconnectReq(token);
@@ -46,7 +46,7 @@
 /*
  * Test IRadio.apduReq() for the response returned.
  */
-TEST_F(SapHidlTest, apduReq) {
+TEST_P(SapHidlTest, apduReq) {
     token = GetRandomSerialNumber();
     SapApduType sapApduType = SapApduType::APDU;
     android::hardware::hidl_vec<uint8_t> command = {};
@@ -64,7 +64,7 @@
 /*
  * Test IRadio.transferAtrReq() for the response returned.
  */
-TEST_F(SapHidlTest, transferAtrReq) {
+TEST_P(SapHidlTest, transferAtrReq) {
     token = GetRandomSerialNumber();
 
     sap->transferAtrReq(token);
@@ -80,7 +80,7 @@
 /*
  * Test IRadio.powerReq() for the response returned.
  */
-TEST_F(SapHidlTest, powerReq) {
+TEST_P(SapHidlTest, powerReq) {
     token = GetRandomSerialNumber();
     bool state = true;
 
@@ -97,7 +97,7 @@
 /*
  * Test IRadio.resetSimReq() for the response returned.
  */
-TEST_F(SapHidlTest, resetSimReq) {
+TEST_P(SapHidlTest, resetSimReq) {
     token = GetRandomSerialNumber();
 
     sap->resetSimReq(token);
@@ -113,7 +113,7 @@
 /*
  * Test IRadio.transferCardReaderStatusReq() for the response returned.
  */
-TEST_F(SapHidlTest, transferCardReaderStatusReq) {
+TEST_P(SapHidlTest, transferCardReaderStatusReq) {
     token = GetRandomSerialNumber();
 
     sap->transferCardReaderStatusReq(token);
@@ -127,7 +127,7 @@
 /*
  * Test IRadio.setTransferProtocolReq() for the response returned.
  */
-TEST_F(SapHidlTest, setTransferProtocolReq) {
+TEST_P(SapHidlTest, setTransferProtocolReq) {
     token = GetRandomSerialNumber();
     SapTransferProtocol sapTransferProtocol = SapTransferProtocol::T0;
 
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_test.cpp b/radio/1.0/vts/functional/sap_hidl_hal_test.cpp
index 65b344b..fe10587 100644
--- a/radio/1.0/vts/functional/sap_hidl_hal_test.cpp
+++ b/radio/1.0/vts/functional/sap_hidl_hal_test.cpp
@@ -17,8 +17,7 @@
 #include <sap_hidl_hal_utils.h>
 
 void SapHidlTest::SetUp() {
-    sap = ::testing::VtsHalHidlTargetTestBase::getService<ISap>(
-        SapHidlEnvironment::Instance()->getServiceName<ISap>(hidl_string(SAP_SERVICE_NAME)));
+    sap = ISap::getService(GetParam());
     ASSERT_NE(sap, nullptr);
 
     sapCb = new SapCallback(*this);
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_utils.h b/radio/1.0/vts/functional/sap_hidl_hal_utils.h
index f432932..2fc9ae3 100644
--- a/radio/1.0/vts/functional/sap_hidl_hal_utils.h
+++ b/radio/1.0/vts/functional/sap_hidl_hal_utils.h
@@ -16,8 +16,6 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -25,6 +23,7 @@
 #include <android/hardware/radio/1.0/ISap.h>
 #include <android/hardware/radio/1.0/ISapCallback.h>
 #include <android/hardware/radio/1.0/types.h>
+#include <gtest/gtest.h>
 
 #include "vts_test_util.h"
 
@@ -80,23 +79,9 @@
     Return<void> transferProtocolResponse(int32_t token, SapResultCode resultCode);
 };
 
-// Test environment for Sap HIDL HAL.
-class SapHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static SapHidlEnvironment* Instance() {
-        static SapHidlEnvironment* instance = new SapHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override { registerTestService<ISap>(); }
-
-   private:
-    SapHidlEnvironment() {}
-};
-
 // The main test class for Sap HIDL.
-class SapHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   private:
+class SapHidlTest : public ::testing::TestWithParam<std::string> {
+  private:
     std::mutex mtx;
     std::condition_variable cv;
     int count;
diff --git a/radio/1.0/vts/functional/vts_hal_radio_target_test.xml b/radio/1.0/vts/functional/vts_hal_radio_target_test.xml
new file mode 100644
index 0000000..5e4a1cd
--- /dev/null
+++ b/radio/1.0/vts/functional/vts_hal_radio_target_test.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 VtsHalRadioV1_0TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
+    <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="VtsHalRadioV1_0TargetTest->/data/local/tmp/VtsHalRadioV1_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="VtsHalRadioV1_0TargetTest" />
+    </test>
+</configuration>
diff --git a/radio/1.0/vts/functional/vts_hal_sap_target_test.xml b/radio/1.0/vts/functional/vts_hal_sap_target_test.xml
new file mode 100644
index 0000000..457d700
--- /dev/null
+++ b/radio/1.0/vts/functional/vts_hal_sap_target_test.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 VtsHalSapV1_0TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
+    <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="VtsHalSapV1_0TargetTest->/data/local/tmp/VtsHalSapV1_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="VtsHalSapV1_0TargetTest" />
+    </test>
+</configuration>
diff --git a/radio/1.0/vts/functional/vts_test_util.h b/radio/1.0/vts/functional/vts_test_util.h
index 826f0de..05b47c9 100644
--- a/radio/1.0/vts/functional/vts_test_util.h
+++ b/radio/1.0/vts/functional/vts_test_util.h
@@ -16,9 +16,8 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 #include <android/hardware/radio/1.0/types.h>
+#include <gtest/gtest.h>
 
 using ::android::hardware::radio::V1_0::RadioError;
 using ::android::hardware::radio::V1_0::SapResultCode;
diff --git a/radio/1.1/Android.bp b/radio/1.1/Android.bp
index 4375d8c..28388b0 100644
--- a/radio/1.1/Android.bp
+++ b/radio/1.1/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/1.1/vts/functional/Android.bp b/radio/1.1/vts/functional/Android.bp
index 5695c6b..58aa67e 100644
--- a/radio/1.1/vts/functional/Android.bp
+++ b/radio/1.1/vts/functional/Android.bp
@@ -30,5 +30,5 @@
     header_libs: [
         "radio.util.header@1.0",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/radio/1.1/vts/functional/AndroidTest.xml b/radio/1.1/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..5badadd
--- /dev/null
+++ b/radio/1.1/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 VtsHalRadioV1_1TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
+    <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="VtsHalRadioV1_1TargetTest->/data/local/tmp/VtsHalRadioV1_1TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalRadioV1_1TargetTest" />
+    </test>
+</configuration>
diff --git a/radio/1.1/vts/functional/VtsHalRadioV1_1TargetTest.cpp b/radio/1.1/vts/functional/VtsHalRadioV1_1TargetTest.cpp
index 83564ee..98dbf62 100644
--- a/radio/1.1/vts/functional/VtsHalRadioV1_1TargetTest.cpp
+++ b/radio/1.1/vts/functional/VtsHalRadioV1_1TargetTest.cpp
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <radio_hidl_hal_utils_v1_1.h>
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    RadioHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(PerInstance, RadioHidlTest_v1_1,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 ::android::hardware::radio::V1_1::IRadio::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
index 33347c5..75abbbf 100644
--- a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
@@ -20,7 +20,7 @@
 /*
  * Test IRadio.setSimCardPower() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_1, setSimCardPower_1_1) {
+TEST_P(RadioHidlTest_v1_1, setSimCardPower_1_1) {
     /* Record the sim card state for the testing environment */
     CardState cardStateForTest = cardStatus.cardState;
 
@@ -81,7 +81,7 @@
 /*
  * Test IRadio.startNetworkScan() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_1, startNetworkScan) {
+TEST_P(RadioHidlTest_v1_1, startNetworkScan) {
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request;
@@ -115,7 +115,7 @@
 /*
  * Test IRadio.startNetworkScan() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_1, startNetworkScan_InvalidArgument) {
+TEST_P(RadioHidlTest_v1_1, startNetworkScan_InvalidArgument) {
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request;
@@ -139,7 +139,7 @@
 /*
  * Test IRadio.stopNetworkScan() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_1, stopNetworkScan) {
+TEST_P(RadioHidlTest_v1_1, stopNetworkScan) {
     serial = GetRandomSerialNumber();
 
     radio_v1_1->stopNetworkScan(serial);
@@ -158,7 +158,7 @@
 /*
  * Test IRadio.setCarrierInfoForImsiEncryption() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_1, setCarrierInfoForImsiEncryption) {
+TEST_P(RadioHidlTest_v1_1, setCarrierInfoForImsiEncryption) {
     serial = GetRandomSerialNumber();
     ImsiEncryptionInfo imsiInfo;
     imsiInfo.mcc = "310";
@@ -181,7 +181,7 @@
 /*
  * Test IRadio.startKeepalive() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_1, startKeepalive) {
+TEST_P(RadioHidlTest_v1_1, startKeepalive) {
     std::vector<KeepaliveRequest> requests = {
         {
             // Invalid IPv4 source address
@@ -279,7 +279,7 @@
 /*
  * Test IRadio.stopKeepalive() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_1, stopKeepalive) {
+TEST_P(RadioHidlTest_v1_1, stopKeepalive) {
     serial = GetRandomSerialNumber();
 
     radio_v1_1->stopKeepalive(serial, 0xBAD);
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_test.cpp b/radio/1.1/vts/functional/radio_hidl_hal_test.cpp
index 2f657b4..020168e 100644
--- a/radio/1.1/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.1/vts/functional/radio_hidl_hal_test.cpp
@@ -17,18 +17,10 @@
 #include <radio_hidl_hal_utils_v1_1.h>
 
 void RadioHidlTest_v1_1::SetUp() {
-    radio_v1_1 =
-        ::testing::VtsHalHidlTargetTestBase::getService<::android::hardware::radio::V1_1::IRadio>(
-            RadioHidlEnvironment::Instance()
-                ->getServiceName<::android::hardware::radio::V1_1::IRadio>(
-                    hidl_string(RADIO_SERVICE_NAME)));
+    radio_v1_1 = ::android::hardware::radio::V1_1::IRadio::getService(GetParam());
     if (radio_v1_1 == NULL) {
         sleep(60);
-        radio_v1_1 = ::testing::VtsHalHidlTargetTestBase::getService<
-            ::android::hardware::radio::V1_1::IRadio>(
-            RadioHidlEnvironment::Instance()
-                ->getServiceName<::android::hardware::radio::V1_1::IRadio>(
-                    hidl_string(RADIO_SERVICE_NAME)));
+        radio_v1_1 = ::android::hardware::radio::V1_1::IRadio::getService(GetParam());
     }
     ASSERT_NE(nullptr, radio_v1_1.get());
 
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_utils_v1_1.h b/radio/1.1/vts/functional/radio_hidl_hal_utils_v1_1.h
index 925f4fc..b81ee13 100644
--- a/radio/1.1/vts/functional/radio_hidl_hal_utils_v1_1.h
+++ b/radio/1.1/vts/functional/radio_hidl_hal_utils_v1_1.h
@@ -16,8 +16,7 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <log/log.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -26,6 +25,7 @@
 #include <android/hardware/radio/1.1/IRadioIndication.h>
 #include <android/hardware/radio/1.1/IRadioResponse.h>
 #include <android/hardware/radio/1.1/types.h>
+#include <gtest/gtest.h>
 
 #include "vts_test_util.h"
 
@@ -535,25 +535,9 @@
                             const ::android::hardware::hidl_string& reason);
 };
 
-// Test environment for Radio HIDL HAL.
-class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static RadioHidlEnvironment* Instance() {
-        static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::radio::V1_1::IRadio>();
-    }
-
-   private:
-    RadioHidlEnvironment() {}
-};
-
 // The main test class for Radio HIDL.
-class RadioHidlTest_v1_1 : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class RadioHidlTest_v1_1 : public ::testing::TestWithParam<std::string> {
+  protected:
     std::mutex mtx;
     std::condition_variable cv;
     int count;
diff --git a/radio/1.2/Android.bp b/radio/1.2/Android.bp
index b7364a8..28e6b26 100644
--- a/radio/1.2/Android.bp
+++ b/radio/1.2/Android.bp
@@ -20,4 +20,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/1.2/default/Android.bp b/radio/1.2/default/Android.bp
index f8ff4c7..74fcf11 100644
--- a/radio/1.2/default/Android.bp
+++ b/radio/1.2/default/Android.bp
@@ -9,7 +9,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.radio@1.2",
@@ -29,7 +28,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.radio@1.2",
diff --git a/radio/1.2/default/android.hardware.radio@1.2-radio-service.rc b/radio/1.2/default/android.hardware.radio@1.2-radio-service.rc
index e126cd8..eab37ec 100644
--- a/radio/1.2/default/android.hardware.radio@1.2-radio-service.rc
+++ b/radio/1.2/default/android.hardware.radio@1.2-radio-service.rc
@@ -1,4 +1,13 @@
 service vendor.radio-1-2 /vendor/bin/hw/android.hardware.radio@1.2-radio-service
+    interface android.hardware.radio@1.0::IRadio slot1
+    interface android.hardware.radio@1.0::IRadio slot2
+    interface android.hardware.radio@1.0::IRadio slot3
+    interface android.hardware.radio@1.1::IRadio slot1
+    interface android.hardware.radio@1.1::IRadio slot2
+    interface android.hardware.radio@1.1::IRadio slot3
+    interface android.hardware.radio@1.2::IRadio slot1
+    interface android.hardware.radio@1.2::IRadio slot2
+    interface android.hardware.radio@1.2::IRadio slot3
     class hal
     user system
     group system
diff --git a/radio/1.2/default/android.hardware.radio@1.2-sap-service.rc b/radio/1.2/default/android.hardware.radio@1.2-sap-service.rc
index 845e6e5..9f163f6 100644
--- a/radio/1.2/default/android.hardware.radio@1.2-sap-service.rc
+++ b/radio/1.2/default/android.hardware.radio@1.2-sap-service.rc
@@ -1,4 +1,7 @@
 service vendor.sap-1-2 /vendor/bin/hw/android.hardware.radio@1.2-sap-service
+    interface android.hardware.radio@1.0::ISap slot1
+    interface android.hardware.radio@1.1::ISap slot1
+    interface android.hardware.radio@1.2::ISap slot1
     class hal
     user system
     group system
diff --git a/radio/1.2/types.hal b/radio/1.2/types.hal
index dffebd3..f10d753 100644
--- a/radio/1.2/types.hal
+++ b/radio/1.2/types.hal
@@ -161,7 +161,8 @@
     ScanType type;
 
     /**
-     * Time interval in seconds between periodic scans, only valid when type = PERIODIC
+     * Time interval in seconds between the completion of one scan and the start of a subsequent scan.
+     * This field is only valid when 'type' is 'PERIODIC'.
      * Range: ScanIntervalRange:MIN to ScanIntervalRange:MAX
      */
     int32_t interval;
diff --git a/radio/1.2/vts/functional/Android.bp b/radio/1.2/vts/functional/Android.bp
index c5838a8..f7189a8 100644
--- a/radio/1.2/vts/functional/Android.bp
+++ b/radio/1.2/vts/functional/Android.bp
@@ -34,5 +34,5 @@
         "android.hardware.radio.config@1.1",
     ],
     header_libs: ["radio.util.header@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/radio/1.2/vts/functional/AndroidTest.xml b/radio/1.2/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..5d92248
--- /dev/null
+++ b/radio/1.2/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 VtsHalRadioV1_2TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
+    <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="VtsHalRadioV1_2TargetTest->/data/local/tmp/VtsHalRadioV1_2TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalRadioV1_2TargetTest" />
+    </test>
+</configuration>
diff --git a/radio/1.2/vts/functional/VtsHalRadioV1_2TargetTest.cpp b/radio/1.2/vts/functional/VtsHalRadioV1_2TargetTest.cpp
index c1a2f3d..400e394 100644
--- a/radio/1.2/vts/functional/VtsHalRadioV1_2TargetTest.cpp
+++ b/radio/1.2/vts/functional/VtsHalRadioV1_2TargetTest.cpp
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <radio_hidl_hal_utils_v1_2.h>
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    RadioHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(PerInstance, RadioHidlTest_v1_2,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 ::android::hardware::radio::V1_2::IRadio::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
index 5184ef9..7464307 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
@@ -31,7 +31,7 @@
 /*
  * Test IRadio.startNetworkScan() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_2, startNetworkScan) {
+TEST_P(RadioHidlTest_v1_2, startNetworkScan) {
     serial = GetRandomSerialNumber();
 
     if (radioConfig != NULL && DDS_LOGICAL_SLOT_INDEX != logicalSlotId) {
@@ -46,7 +46,10 @@
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
             .type = ScanType::ONE_SHOT,
             .interval = 60,
-            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850}};
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
@@ -79,7 +82,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid specifier.
  */
-TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidArgument) {
+TEST_P(RadioHidlTest_v1_2, startNetworkScan_InvalidArgument) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {.type = ScanType::ONE_SHOT,
@@ -106,7 +109,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid interval (lower boundary).
  */
-TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidInterval1) {
+TEST_P(RadioHidlTest_v1_2, startNetworkScan_InvalidInterval1) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
@@ -138,7 +141,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid interval (upper boundary).
  */
-TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidInterval2) {
+TEST_P(RadioHidlTest_v1_2, startNetworkScan_InvalidInterval2) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
@@ -170,7 +173,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid max search time (lower boundary).
  */
-TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidMaxSearchTime1) {
+TEST_P(RadioHidlTest_v1_2, startNetworkScan_InvalidMaxSearchTime1) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
@@ -202,7 +205,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid max search time (upper boundary).
  */
-TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidMaxSearchTime2) {
+TEST_P(RadioHidlTest_v1_2, startNetworkScan_InvalidMaxSearchTime2) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
@@ -234,7 +237,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid periodicity (lower boundary).
  */
-TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidPeriodicity1) {
+TEST_P(RadioHidlTest_v1_2, startNetworkScan_InvalidPeriodicity1) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
@@ -266,7 +269,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid periodicity (upper boundary).
  */
-TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidPeriodicity2) {
+TEST_P(RadioHidlTest_v1_2, startNetworkScan_InvalidPeriodicity2) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
@@ -298,7 +301,7 @@
 /*
  * Test IRadio.startNetworkScan() with valid periodicity
  */
-TEST_F(RadioHidlTest_v1_2, startNetworkScan_GoodRequest1) {
+TEST_P(RadioHidlTest_v1_2, startNetworkScan_GoodRequest1) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
@@ -332,7 +335,7 @@
 /*
  * Test IRadio.startNetworkScan() with valid periodicity and plmns
  */
-TEST_F(RadioHidlTest_v1_2, startNetworkScan_GoodRequest2) {
+TEST_P(RadioHidlTest_v1_2, startNetworkScan_GoodRequest2) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
@@ -367,7 +370,7 @@
 /*
  * Test IRadio.setIndicationFilter_1_2()
  */
-TEST_F(RadioHidlTest_v1_2, setIndicationFilter_1_2) {
+TEST_P(RadioHidlTest_v1_2, setIndicationFilter_1_2) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setIndicationFilter_1_2(
@@ -385,7 +388,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria() with invalid hysteresisDb
  */
-TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_invalidHysteresisDb) {
+TEST_P(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_invalidHysteresisDb) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
@@ -405,7 +408,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria() with empty parameters
  */
-TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_EmptyParams) {
+TEST_P(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_EmptyParams) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
@@ -423,7 +426,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria() for GERAN
  */
-TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Geran) {
+TEST_P(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Geran) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
@@ -442,7 +445,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria() for UTRAN
  */
-TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Utran) {
+TEST_P(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Utran) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
@@ -461,7 +464,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria() for EUTRAN
  */
-TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Eutran) {
+TEST_P(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Eutran) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
@@ -480,7 +483,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria() for CDMA2000
  */
-TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Cdma2000) {
+TEST_P(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Cdma2000) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
@@ -499,7 +502,7 @@
 /*
  * Test IRadio.setLinkCapacityReportingCriteria() invalid hysteresisDlKbps
  */
-TEST_F(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_invalidHysteresisDlKbps) {
+TEST_P(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_invalidHysteresisDlKbps) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setLinkCapacityReportingCriteria(
@@ -524,7 +527,7 @@
 /*
  * Test IRadio.setLinkCapacityReportingCriteria() invalid hysteresisUlKbps
  */
-TEST_F(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_invalidHysteresisUlKbps) {
+TEST_P(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_invalidHysteresisUlKbps) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setLinkCapacityReportingCriteria(
@@ -549,7 +552,7 @@
 /*
  * Test IRadio.setLinkCapacityReportingCriteria() empty params
  */
-TEST_F(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_emptyParams) {
+TEST_P(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_emptyParams) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setLinkCapacityReportingCriteria(
@@ -570,7 +573,7 @@
 /*
  * Test IRadio.setLinkCapacityReportingCriteria() GERAN
  */
-TEST_F(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_Geran) {
+TEST_P(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_Geran) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->setLinkCapacityReportingCriteria(
@@ -592,7 +595,7 @@
 /*
  * Test IRadio.setupDataCall_1_2() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_2, setupDataCall_1_2) {
+TEST_P(RadioHidlTest_v1_2, setupDataCall_1_2) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::AccessNetwork accessNetwork =
@@ -652,7 +655,7 @@
 /*
  * Test IRadio.deactivateDataCall_1_2() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_2, deactivateDataCall_1_2) {
+TEST_P(RadioHidlTest_v1_2, deactivateDataCall_1_2) {
     serial = GetRandomSerialNumber();
     int cid = 1;
     ::android::hardware::radio::V1_2::DataRequestReason reason =
@@ -683,7 +686,7 @@
 /*
  * Test IRadio.getCellInfoList() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_2, getCellInfoList_1_2) {
+TEST_P(RadioHidlTest_v1_2, getCellInfoList_1_2) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->getCellInfoList(serial);
@@ -701,7 +704,7 @@
 /*
  * Test IRadio.getVoiceRegistrationState() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_2, getVoiceRegistrationState) {
+TEST_P(RadioHidlTest_v1_2, getVoiceRegistrationState) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->getVoiceRegistrationState(serial);
@@ -719,7 +722,7 @@
 /*
  * Test IRadio.getDataRegistrationState() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_2, getDataRegistrationState) {
+TEST_P(RadioHidlTest_v1_2, getDataRegistrationState) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->getDataRegistrationState(serial);
@@ -794,7 +797,7 @@
 /*
  * Test IRadio.getAvailableBandModes() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_2, getAvailableBandModes) {
+TEST_P(RadioHidlTest_v1_2, getAvailableBandModes) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_2->getAvailableBandModes(serial);
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_test.cpp b/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
index 21caddb..4845c7f 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
@@ -17,18 +17,10 @@
 #include <radio_hidl_hal_utils_v1_2.h>
 
 void RadioHidlTest_v1_2::SetUp() {
-    radio_v1_2 =
-        ::testing::VtsHalHidlTargetTestBase::getService<::android::hardware::radio::V1_2::IRadio>(
-            RadioHidlEnvironment::Instance()
-                ->getServiceName<::android::hardware::radio::V1_2::IRadio>(
-                    hidl_string(RADIO_SERVICE_NAME)));
+    radio_v1_2 = ::android::hardware::radio::V1_2::IRadio::getService(GetParam());
     if (radio_v1_2 == NULL) {
         sleep(60);
-        radio_v1_2 = ::testing::VtsHalHidlTargetTestBase::getService<
-            ::android::hardware::radio::V1_2::IRadio>(
-            RadioHidlEnvironment::Instance()
-                ->getServiceName<::android::hardware::radio::V1_2::IRadio>(
-                    hidl_string(RADIO_SERVICE_NAME)));
+        radio_v1_2 = ::android::hardware::radio::V1_2::IRadio::getService(GetParam());
     }
     ASSERT_NE(nullptr, radio_v1_2.get());
 
@@ -51,8 +43,7 @@
     /* Enforce Vts Testing with Sim Status Present only. */
     EXPECT_EQ(CardState::PRESENT, cardStatus.base.cardState);
 
-    radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<
-            ::android::hardware::radio::config::V1_1::IRadioConfig>();
+    radioConfig = ::android::hardware::radio::config::V1_1::IRadioConfig::getService();
 
     /* Enforce Vts tesing with RadioConfig for network scan excemption. */
     // Some devices can only perform network scan on logical modem that currently used for packet
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h b/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h
index 2db1cac..479340c 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h
+++ b/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h
@@ -16,8 +16,7 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <log/log.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -30,6 +29,7 @@
 #include <android/hardware/radio/1.2/IRadioIndication.h>
 #include <android/hardware/radio/1.2/IRadioResponse.h>
 #include <android/hardware/radio/1.2/types.h>
+#include <gtest/gtest.h>
 
 #include "vts_test_util.h"
 
@@ -631,25 +631,9 @@
                             const ::android::hardware::hidl_string& reason);
 };
 
-// Test environment for Radio HIDL HAL.
-class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static RadioHidlEnvironment* Instance() {
-        static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::radio::V1_2::IRadio>();
-    }
-
-   private:
-    RadioHidlEnvironment() {}
-};
-
 // The main test class for Radio HIDL.
-class RadioHidlTest_v1_2 : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class RadioHidlTest_v1_2 : public ::testing::TestWithParam<std::string> {
+  protected:
     std::mutex mtx_;
     std::condition_variable cv_;
     int count_;
diff --git a/radio/1.3/Android.bp b/radio/1.3/Android.bp
index de2a3e5..b6af874 100644
--- a/radio/1.3/Android.bp
+++ b/radio/1.3/Android.bp
@@ -20,4 +20,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/1.3/vts/functional/Android.bp b/radio/1.3/vts/functional/Android.bp
index 67aff6e..2301732 100644
--- a/radio/1.3/vts/functional/Android.bp
+++ b/radio/1.3/vts/functional/Android.bp
@@ -32,5 +32,5 @@
         "android.hardware.radio@1.0",
     ],
     header_libs: ["radio.util.header@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/radio/1.3/vts/functional/AndroidTest.xml b/radio/1.3/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..c910047
--- /dev/null
+++ b/radio/1.3/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 VtsHalRadioV1_3TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
+    <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="VtsHalRadioV1_3TargetTest->/data/local/tmp/VtsHalRadioV1_3TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalRadioV1_3TargetTest" />
+    </test>
+</configuration>
diff --git a/radio/1.3/vts/functional/VtsHalRadioV1_3TargetTest.cpp b/radio/1.3/vts/functional/VtsHalRadioV1_3TargetTest.cpp
index 7d2623e..2622bbc 100644
--- a/radio/1.3/vts/functional/VtsHalRadioV1_3TargetTest.cpp
+++ b/radio/1.3/vts/functional/VtsHalRadioV1_3TargetTest.cpp
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <radio_hidl_hal_utils_v1_3.h>
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    RadioHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(PerInstance, RadioHidlTest_v1_3,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 ::android::hardware::radio::V1_3::IRadio::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
index 813dd13..4e48141 100644
--- a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
@@ -22,7 +22,7 @@
 /*
  * Test IRadio.enableMddem() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_3, enableModem) {
+TEST_P(RadioHidlTest_v1_3, enableModem) {
     serial = GetRandomSerialNumber();
 
     bool responseToggle = radioRsp_v1_3->enableModemResponseToggle;
@@ -61,7 +61,7 @@
 /*
  * Test IRadio.getModemStackStatus() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_3, getModemStackStatus) {
+TEST_P(RadioHidlTest_v1_3, getModemStackStatus) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_3->getModemStackStatus(serial);
@@ -81,7 +81,7 @@
  *
  * This test is excluded from manifest, due to non-implementation in Q. Tracked by b/130254624.
  */
-TEST_F(RadioHidlTest_v1_3, setSystemSelectionChannels) {
+TEST_P(RadioHidlTest_v1_3, setSystemSelectionChannels) {
     serial = GetRandomSerialNumber();
 
     RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
diff --git a/radio/1.3/vts/functional/radio_hidl_hal_test.cpp b/radio/1.3/vts/functional/radio_hidl_hal_test.cpp
index a876b1a..4581350 100644
--- a/radio/1.3/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.3/vts/functional/radio_hidl_hal_test.cpp
@@ -17,18 +17,10 @@
 #include <radio_hidl_hal_utils_v1_3.h>
 
 void RadioHidlTest_v1_3::SetUp() {
-    radio_v1_3 = ::testing::VtsHalHidlTargetTestBase::getService<
-            ::android::hardware::radio::V1_3::IRadio>(
-            RadioHidlEnvironment::Instance()
-                    ->getServiceName<::android::hardware::radio::V1_3::IRadio>(
-                            hidl_string(RADIO_SERVICE_NAME)));
+    radio_v1_3 = ::android::hardware::radio::V1_3::IRadio::getService(GetParam());
     if (radio_v1_3 == NULL) {
         sleep(60);
-        radio_v1_3 = ::testing::VtsHalHidlTargetTestBase::getService<
-                ::android::hardware::radio::V1_3::IRadio>(
-                RadioHidlEnvironment::Instance()
-                        ->getServiceName<::android::hardware::radio::V1_3::IRadio>(
-                                hidl_string(RADIO_SERVICE_NAME)));
+        radio_v1_3 = ::android::hardware::radio::V1_3::IRadio::getService(GetParam());
     }
     ASSERT_NE(nullptr, radio_v1_3.get());
 
diff --git a/radio/1.3/vts/functional/radio_hidl_hal_utils_v1_3.h b/radio/1.3/vts/functional/radio_hidl_hal_utils_v1_3.h
index 1d03a99..893eac5 100644
--- a/radio/1.3/vts/functional/radio_hidl_hal_utils_v1_3.h
+++ b/radio/1.3/vts/functional/radio_hidl_hal_utils_v1_3.h
@@ -16,8 +16,7 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <log/log.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -609,25 +608,9 @@
                             const ::android::hardware::hidl_string& reason);
 };
 
-// Test environment for Radio HIDL HAL.
-class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static RadioHidlEnvironment* Instance() {
-        static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::radio::V1_3::IRadio>();
-    }
-
-   private:
-    RadioHidlEnvironment() {}
-};
-
 // The main test class for Radio HIDL.
-class RadioHidlTest_v1_3 : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class RadioHidlTest_v1_3 : public ::testing::TestWithParam<std::string> {
+  protected:
     std::mutex mtx_;
     std::condition_variable cv_;
     int count_;
diff --git a/radio/1.4/Android.bp b/radio/1.4/Android.bp
index 9f5f2f9..ff2e0d6 100644
--- a/radio/1.4/Android.bp
+++ b/radio/1.4/Android.bp
@@ -22,4 +22,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/1.4/vts/functional/Android.bp b/radio/1.4/vts/functional/Android.bp
index 6827132..8284404 100644
--- a/radio/1.4/vts/functional/Android.bp
+++ b/radio/1.4/vts/functional/Android.bp
@@ -35,5 +35,5 @@
         "android.hardware.radio.config@1.1",
     ],
     header_libs: ["radio.util.header@1.0"],
-    test_suites: ["general-tests"]
+    test_suites: ["general-tests", "vts-core"]
 }
diff --git a/radio/1.4/vts/functional/AndroidTest.xml b/radio/1.4/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..c910047
--- /dev/null
+++ b/radio/1.4/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 VtsHalRadioV1_3TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
+    <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="VtsHalRadioV1_3TargetTest->/data/local/tmp/VtsHalRadioV1_3TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalRadioV1_3TargetTest" />
+    </test>
+</configuration>
diff --git a/radio/1.4/vts/functional/VtsHalRadioV1_4TargetTest.cpp b/radio/1.4/vts/functional/VtsHalRadioV1_4TargetTest.cpp
index d6330e6..23ec011 100644
--- a/radio/1.4/vts/functional/VtsHalRadioV1_4TargetTest.cpp
+++ b/radio/1.4/vts/functional/VtsHalRadioV1_4TargetTest.cpp
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <radio_hidl_hal_utils_v1_4.h>
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    RadioHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
\ No newline at end of file
+INSTANTIATE_TEST_SUITE_P(PerInstance, RadioHidlTest_v1_4,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 ::android::hardware::radio::V1_4::IRadio::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
index f81af9b..95136bb 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
@@ -21,7 +21,7 @@
 /*
  * Test IRadio.emergencyDial() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_4, emergencyDial) {
+TEST_P(RadioHidlTest_v1_4, emergencyDial) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_0::Dial dialInfo;
@@ -52,7 +52,7 @@
 /*
  * Test IRadio.emergencyDial() with specified service and its response returned.
  */
-TEST_F(RadioHidlTest_v1_4, emergencyDial_withServices) {
+TEST_P(RadioHidlTest_v1_4, emergencyDial_withServices) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_0::Dial dialInfo;
@@ -84,7 +84,7 @@
 /*
  * Test IRadio.emergencyDial() with known emergency call routing and its response returned.
  */
-TEST_F(RadioHidlTest_v1_4, emergencyDial_withEmergencyRouting) {
+TEST_P(RadioHidlTest_v1_4, emergencyDial_withEmergencyRouting) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_0::Dial dialInfo;
@@ -116,7 +116,7 @@
 /*
  * Test IRadio.getPreferredNetworkTypeBitmap() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_4, getPreferredNetworkTypeBitmap) {
+TEST_P(RadioHidlTest_v1_4, getPreferredNetworkTypeBitmap) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_4->getPreferredNetworkTypeBitmap(serial);
@@ -130,7 +130,7 @@
     EXPECT_EQ(RadioError::NONE, radioRsp_v1_4->rspInfo.error);
 }
 
-TEST_F(RadioHidlTest_v1_4, setPreferredNetworkTypeBitmap) {
+TEST_P(RadioHidlTest_v1_4, setPreferredNetworkTypeBitmap) {
     serial = GetRandomSerialNumber();
     ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
             network_type_bitmap{};
@@ -175,7 +175,7 @@
  * REQUEST_NOT_SUPPORTED will be disallowed for all tests. Modems have "GSM" rat scan need to
  * support scanning requests combined with some parameters.
  */
-TEST_F(RadioHidlTest_v1_4, startNetworkScan) {
+TEST_P(RadioHidlTest_v1_4, startNetworkScan) {
     serial = GetRandomSerialNumber();
 
     RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
@@ -183,7 +183,12 @@
                                       .channels = {1, 2}};
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-            .type = ScanType::ONE_SHOT, .interval = 60, .specifiers = {specifier}};
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
 
     Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
     ASSERT_OK(res);
@@ -213,7 +218,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid specifier.
  */
-TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidArgument) {
+TEST_P(RadioHidlTest_v1_4, startNetworkScan_InvalidArgument) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {.type = ScanType::ONE_SHOT,
@@ -241,7 +246,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid interval (lower boundary).
  */
-TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidInterval1) {
+TEST_P(RadioHidlTest_v1_4, startNetworkScan_InvalidInterval1) {
     serial = GetRandomSerialNumber();
 
     RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
@@ -278,7 +283,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid interval (upper boundary).
  */
-TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidInterval2) {
+TEST_P(RadioHidlTest_v1_4, startNetworkScan_InvalidInterval2) {
     serial = GetRandomSerialNumber();
 
     RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
@@ -314,7 +319,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid max search time (lower boundary).
  */
-TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidMaxSearchTime1) {
+TEST_P(RadioHidlTest_v1_4, startNetworkScan_InvalidMaxSearchTime1) {
     serial = GetRandomSerialNumber();
 
     RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
@@ -350,7 +355,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid max search time (upper boundary).
  */
-TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidMaxSearchTime2) {
+TEST_P(RadioHidlTest_v1_4, startNetworkScan_InvalidMaxSearchTime2) {
     serial = GetRandomSerialNumber();
 
     RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
@@ -386,7 +391,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid periodicity (lower boundary).
  */
-TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidPeriodicity1) {
+TEST_P(RadioHidlTest_v1_4, startNetworkScan_InvalidPeriodicity1) {
     serial = GetRandomSerialNumber();
 
     RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
@@ -398,7 +403,7 @@
             .interval = 60,
             .specifiers = {specifier},
             .maxSearchTime = 600,
-            .incrementalResults = false,
+            .incrementalResults = true,
             .incrementalResultsPeriodicity = 0};
 
     Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
@@ -422,7 +427,7 @@
 /*
  * Test IRadio.startNetworkScan() with invalid periodicity (upper boundary).
  */
-TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidPeriodicity2) {
+TEST_P(RadioHidlTest_v1_4, startNetworkScan_InvalidPeriodicity2) {
     serial = GetRandomSerialNumber();
 
     RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
@@ -434,7 +439,7 @@
             .interval = 60,
             .specifiers = {specifier},
             .maxSearchTime = 600,
-            .incrementalResults = false,
+            .incrementalResults = true,
             .incrementalResultsPeriodicity = 11};
 
     Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
@@ -458,7 +463,7 @@
 /*
  * Test IRadio.startNetworkScan() with valid periodicity
  */
-TEST_F(RadioHidlTest_v1_4, startNetworkScan_GoodRequest1) {
+TEST_P(RadioHidlTest_v1_4, startNetworkScan_GoodRequest1) {
     serial = GetRandomSerialNumber();
 
     RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
@@ -497,7 +502,7 @@
 /*
  * Test IRadio.startNetworkScan() with valid periodicity and plmns
  */
-TEST_F(RadioHidlTest_v1_4, startNetworkScan_GoodRequest2) {
+TEST_P(RadioHidlTest_v1_4, startNetworkScan_GoodRequest2) {
     serial = GetRandomSerialNumber();
 
     RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
@@ -538,7 +543,7 @@
 /*
  * Test IRadio.getSignalStrength_1_4() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_4, getSignalStrength_1_4) {
+TEST_P(RadioHidlTest_v1_4, getSignalStrength_1_4) {
     serial = GetRandomSerialNumber();
 
     radio_v1_4->getSignalStrength_1_4(serial);
@@ -557,7 +562,7 @@
 /*
  * Test IRadio.setupDataCall_1_4() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_4, setupDataCall_1_4) {
+TEST_P(RadioHidlTest_v1_4, setupDataCall_1_4) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_4::AccessNetwork accessNetwork =
@@ -612,7 +617,7 @@
 /*
  * Test IRadio.getAllowedCarriers_1_4() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_4, getAllowedCarriers_1_4) {
+TEST_P(RadioHidlTest_v1_4, getAllowedCarriers_1_4) {
     serial = GetRandomSerialNumber();
 
     radio_v1_4->getAllowedCarriers_1_4(serial);
@@ -627,7 +632,7 @@
 /**
  * Test IRadio.setAllowedCarriers_1_4() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_4, setAllowedCarriers_1_4) {
+TEST_P(RadioHidlTest_v1_4, setAllowedCarriers_1_4) {
     serial = GetRandomSerialNumber();
     CarrierRestrictionsWithPriority carrierRestrictions;
     memset(&carrierRestrictions, 0, sizeof(carrierRestrictions));
@@ -722,7 +727,7 @@
     }
 }
 
-TEST_F(RadioHidlTest_v1_4, setDataProfile_1_4) {
+TEST_P(RadioHidlTest_v1_4, setDataProfile_1_4) {
     serial = GetRandomSerialNumber();
 
     // Create a dataProfileInfo
@@ -765,7 +770,7 @@
     }
 }
 
-TEST_F(RadioHidlTest_v1_4, setInitialAttachApn_1_4) {
+TEST_P(RadioHidlTest_v1_4, setInitialAttachApn_1_4) {
     serial = GetRandomSerialNumber();
 
     // Create a dataProfileInfo
@@ -807,7 +812,7 @@
 /*
  * Test IRadio.getDataRegistrationStateResponse_1_4() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_4, getDataRegistrationState_1_4) {
+TEST_P(RadioHidlTest_v1_4, getDataRegistrationState_1_4) {
     int rat;
     serial = GetRandomSerialNumber();
 
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_test.cpp b/radio/1.4/vts/functional/radio_hidl_hal_test.cpp
index f27749b..15a0b24 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_test.cpp
@@ -17,18 +17,11 @@
 #include <radio_hidl_hal_utils_v1_4.h>
 
 void RadioHidlTest_v1_4::SetUp() {
-    radio_v1_4 = ::testing::VtsHalHidlTargetTestBase::getService<
-            ::android::hardware::radio::V1_4::IRadio>(
-            RadioHidlEnvironment::Instance()
-                    ->getServiceName<::android::hardware::radio::V1_4::IRadio>(
-                            hidl_string(RADIO_SERVICE_NAME)));
+    radio_v1_4 = ::android::hardware::radio::V1_4::IRadio::getService(GetParam());
+
     if (radio_v1_4 == NULL) {
         sleep(60);
-        radio_v1_4 = ::testing::VtsHalHidlTargetTestBase::getService<
-                ::android::hardware::radio::V1_4::IRadio>(
-                RadioHidlEnvironment::Instance()
-                        ->getServiceName<::android::hardware::radio::V1_4::IRadio>(
-                                hidl_string(RADIO_SERVICE_NAME)));
+        radio_v1_4 = ::android::hardware::radio::V1_4::IRadio::getService(GetParam());
     }
     ASSERT_NE(nullptr, radio_v1_4.get());
 
@@ -48,8 +41,7 @@
     EXPECT_EQ(RadioError::NONE, radioRsp_v1_4->rspInfo.error);
 
     sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig =
-            ::testing::VtsHalHidlTargetTestBase::getService<
-                    ::android::hardware::radio::config::V1_1::IRadioConfig>();
+            ::android::hardware::radio::config::V1_1::IRadioConfig::getService();
 
     /* Enforce Vts tesing with RadioConfig is existed. */
     ASSERT_NE(nullptr, radioConfig.get());
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h b/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h
index b07f9c3..31b7e13 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h
+++ b/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h
@@ -16,8 +16,7 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <log/log.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -28,6 +27,7 @@
 #include <android/hardware/radio/1.4/IRadioIndication.h>
 #include <android/hardware/radio/1.4/IRadioResponse.h>
 #include <android/hardware/radio/1.4/types.h>
+#include <gtest/gtest.h>
 
 #include "vts_test_util.h"
 
@@ -705,25 +705,9 @@
                             const ::android::hardware::hidl_string& reason);
 };
 
-// Test environment for Radio HIDL HAL.
-class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static RadioHidlEnvironment* Instance() {
-        static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::radio::V1_4::IRadio>();
-    }
-
-   private:
-    RadioHidlEnvironment() {}
-};
-
 // The main test class for Radio HIDL.
-class RadioHidlTest_v1_4 : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class RadioHidlTest_v1_4 : public ::testing::TestWithParam<std::string> {
+  protected:
     std::mutex mtx_;
     std::condition_variable cv_;
     int count_;
diff --git a/radio/1.5/Android.bp b/radio/1.5/Android.bp
new file mode 100644
index 0000000..06a2a6e
--- /dev/null
+++ b/radio/1.5/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.radio@1.5",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IRadio.hal",
+        "IRadioIndication.hal",
+        "IRadioResponse.hal",
+    ],
+    interfaces: [
+        "android.hardware.radio@1.0",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.2",
+        "android.hardware.radio@1.3",
+        "android.hardware.radio@1.4",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
new file mode 100644
index 0000000..a4eb93c
--- /dev/null
+++ b/radio/1.5/IRadio.hal
@@ -0,0 +1,121 @@
+/*
+ * 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.radio@1.5;
+
+import @1.4::IRadio;
+import @1.5::AccessNetwork;
+import @1.5::NetworkScanRequest;
+import @1.5::RadioAccessSpecifier;
+import @1.5::SignalThresholdInfo;
+
+/**
+ * This interface is used by telephony and telecom to talk to cellular radio.
+ * All the functions have minimum one parameter:
+ * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
+ * duration of a method call. If clients provide colliding serials (including passing the same
+ * serial to different methods), multiple responses (one for each method call) must still be served.
+ * setResponseFunctions must work with @1.5::IRadioResponse and @1.5::IRadioIndication.
+ */
+interface IRadio extends @1.4::IRadio {
+    /**
+     * Sets the signal strength reporting criteria.
+     *
+     * The resulting reporting rules are the AND of all the supplied criteria. For each RAN
+     * The hysteresisDb and thresholds apply to only the following measured quantities:
+     * -GERAN    - RSSI
+     * -CDMA2000 - RSSI
+     * -UTRAN    - RSCP
+     * -EUTRAN   - RSRP/RSRQ/RSSNR
+     * -NGRAN    - SSRSRP/SSRSRQ/SSSINR
+     *
+     * Note: Reporting criteria must be individually set for each RAN. For each RAN, if none of
+     * reporting criteria of any measurement is set enabled
+     * (see @1.5::SignalThresholdInfo.isEnabled), the reporting criteria for this RAN is
+     * implementation-defined. For each RAN, if any of reporting criteria of any measure is set
+     * enabled, the reporting criteria of the other measures in this RAN are set disabled
+     * (see @1.5::SignalThresholdInfo.isEnabled) until they are set enabled.
+     *
+     * Response callback is
+     * IRadioResponse.setSignalStrengthReportingCriteriaResponse_1_5()
+     *
+     * @param serial Serial number of request.
+     * @param signalThresholdInfo Signal threshold info including the threshold values,
+     *                            hysteresisDb, hysteresisMs and isEnabled.
+     *                            See @1.5::SignalThresholdInfo for details.
+     * @param accessNetwork The type of network for which to apply these thresholds.
+     */
+    oneway setSignalStrengthReportingCriteria_1_5(int32_t serial,
+            SignalThresholdInfo signalThresholdInfo, AccessNetwork accessNetwork);
+
+    /**
+     * Enable or disable UiccApplications on the SIM. If disabled:
+     *  - Modem will not register on any network.
+     *  - SIM must be PRESENT, and the IccId of the SIM must still be accessible.
+     *  - The corresponding modem stack is still functional, e.g. able to make emergency calls or
+     *    do network scan.
+     * By default if this API is not called, the uiccApplications must be enabled automatically.
+     * It must work for both single SIM and DSDS cases for UX consistency.
+     * The preference is per SIM, and must be remembered over power cycle, modem reboot, or SIM
+     * insertion / unplug.
+     *
+     * @param serial Serial number of request.
+     * @param enable true if to enable uiccApplications, false to disable.
+
+     * Response callback is IRadioResponse.enableUiccApplicationsResponse()
+     */
+    oneway enableUiccApplications(int32_t serial, bool enable);
+
+    /**
+     * Whether uiccApplications are enabled, or disabled.
+     *
+     * By default uiccApplications must be enabled, unless enableUiccApplications() with enable
+     * being false is called.
+     *
+     * @param serial Serial number of request.
+     *
+     * Response callback is IRadioResponse.areUiccApplicationsEnabledResponse()
+     */
+    oneway areUiccApplicationsEnabled(int32_t serial);
+
+    /**
+     * Specify which bands modem's background scan must act on.
+     * If specifyChannels is true, it only scans bands specified in specifiers.
+     * If specifyChannels is false, it scans all bands.
+     *
+     * For example, CBRS is only on LTE band 48. By specifying this band,
+     * modem saves more power.
+     *
+     * @param serial Serial number of request.
+     * @param specifyChannels whether to scan bands defined in specifiers.
+     * @param specifiers which bands to scan. Only used if specifyChannels is true.
+     *
+     * Response callback is IRadioResponse.setSystemSelectionChannelsResponse()
+     */
+    oneway setSystemSelectionChannels_1_5(int32_t serial, bool specifyChannels,
+            vec<RadioAccessSpecifier> specifiers);
+
+    /**
+     * Starts a network scan
+     *
+     * @param serial Serial number of request.
+     * @param request Defines the radio networks/bands/channels which need to be scanned.
+     *
+     * Same API as @1.4::IRadio.startNetworkScan_1_4, except using
+     * 1.5 version of NetworkScanRequest
+     */
+    oneway startNetworkScan_1_5(int32_t serial, NetworkScanRequest request);
+};
diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal
new file mode 100644
index 0000000..81452ab
--- /dev/null
+++ b/radio/1.5/IRadioIndication.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.radio@1.5;
+
+import @1.0::RadioIndicationType;
+import @1.4::IRadioIndication;
+
+/**
+ * Interface declaring unsolicited radio indications.
+ */
+interface IRadioIndication extends @1.4::IRadioIndication {
+    /**
+     * Report change of whether uiccApplications are enabled, or disabled.
+     *
+     * @param type Type of radio indication
+     * @param enabled whether uiccApplications are enabled, or disabled
+     */
+    oneway uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled);
+};
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
new file mode 100644
index 0000000..505c595
--- /dev/null
+++ b/radio/1.5/IRadioResponse.hal
@@ -0,0 +1,83 @@
+/*
+ * 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.radio@1.5;
+
+import @1.0::RadioResponseInfo;
+import @1.4::IRadioResponse;
+
+/**
+ * Interface declaring response functions to solicited radio requests.
+ */
+interface IRadioResponse extends @1.4::IRadioResponse {
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:RADIO_NOT_AVAILABLE
+     */
+    oneway setSignalStrengthReportingCriteriaResponse_1_5(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:SIM_ABSENT
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:BUSY
+     */
+    oneway enableUiccApplicationsResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param enabled whether Uicc applications are enabled.
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:SIM_ABSENT
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    oneway areUiccApplicationsEnabledResponse(RadioResponseInfo info, bool enabled);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     */
+    oneway setSystemSelectionChannelsResponse_1_5(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:DEVICE_IN_USE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:MODEM_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     */
+    oneway startNetworkScanResponse_1_5(RadioResponseInfo info);
+};
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
new file mode 100644
index 0000000..04a9bcf
--- /dev/null
+++ b/radio/1.5/types.hal
@@ -0,0 +1,270 @@
+/*
+ * 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.radio@1.5;
+
+import @1.1::EutranBands;
+import @1.1::GeranBands;
+import @1.1::RadioAccessNetworks;
+import @1.1::RadioAccessSpecifier;
+import @1.1::ScanType;
+import @1.1::UtranBands;
+import @1.2::NetworkScanRequest;
+import @1.4::AccessNetwork;
+
+/**
+ * Defining signal strength type.
+ */
+enum SignalMeasurementType : int32_t {
+    /**
+     * Received Signal Strength Indication.
+     * Range: -113 dBm and -51 dBm
+     * Used RAN: GERAN, CDMA2000
+     * Reference: 3GPP TS 27.007 section 8.5.
+     */
+    RSSI = 1,
+    /**
+     * Received Signal Code Power.
+     * Range: -120 dBm to -25 dBm;
+     * Used RAN: UTRAN
+     * Reference: 3GPP TS 25.123, section 9.1.1.1
+     */
+    RSCP = 2,
+    /**
+     * Reference Signal Received Power.
+     * Range: -140 dBm to -44 dBm;
+     * Used RAN: EUTRAN
+     * Reference: 3GPP TS 36.133 9.1.4
+     */
+    RSRP = 3,
+    /**
+     * Reference Signal Received Quality
+     * Range: -20 dB to -3 dB;
+     * Used RAN: EUTRAN
+     * Reference: 3GPP TS 36.133 9.1.7
+     */
+    RSRQ = 4,
+    /**
+     * Reference Signal Signal to Noise Ratio
+     * Range: -20 dB to 30 dB;
+     * Used RAN: EUTRAN
+     * Note: this field is optional; how to support it can be decided by the
+     * corresponding vendor. Though the response code is not enforced,
+     * vendor's implementation must ensure this interface not crashing.
+     */
+    RSSNR = 5,
+    /**
+     * 5G SS reference signal received power.
+     * Range: -140 dBm to -44 dBm.
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215.
+     */
+    SSRSRP = 6,
+    /**
+     * 5G SS reference signal received quality.
+     * Range: -20 dB to -3 dB.
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215.
+     */
+    SSRSRQ = 7,
+    /**
+     * 5G SS signal-to-noise and interference ratio.
+     * Range: -23 dB to 40 dB
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
+     */
+    SSSINR = 8,
+};
+
+/**
+ * Contains the threshold values of each signal measurement type.
+ */
+struct SignalThresholdInfo {
+    /** Signal Measurement Type */
+    SignalMeasurementType signalMeasurement;
+
+    /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis */
+    int32_t hysteresisMs;
+
+    /**
+     * An interval in dB defining the required magnitude change between reports.
+     * hysteresisDb must be smaller than the smallest threshold delta.
+     * An interval value of 0 disables hysteresis.
+     */
+    int32_t hysteresisDb;
+
+    /**
+     * List of threshold values.
+     * Range and unit must reference specific @1.5::SignalMeasurementType.
+     * The threshold values for which to apply criteria.
+     * A vector size of 0 disables the use of thresholds for reporting.
+     */
+    vec<int32_t> thresholds;
+
+    /**
+     * Indicates whether the reporting criteria of the corresponding measurement is enabled
+     * (isEnabled==true) or disabled (isEnabled==false).
+     *
+     * If enabled, modem must trigger the report based on the criteria.
+     * If disabled, modem must not trigger the report based on the criteria.
+     */
+    bool isEnabled;
+};
+
+enum AccessNetwork : @1.4::AccessNetwork {
+    /**
+     *  Next-Generation Radio Access Network (NGRAN)
+     */
+    NGRAN = 6,
+};
+
+enum RadioAccessNetworks : @1.1::RadioAccessNetworks {
+    NGRAN = 4,
+};
+
+/**
+ * Overwritten from @1.1::RadioAccessSpecifier to add NGRAN and NgranBands
+ */
+struct RadioAccessSpecifier {
+    /**
+     * The type of network to scan.
+     */
+    RadioAccessNetworks radioAccessNetwork;
+
+    /**
+     * The frequency bands to scan.
+     * Maximum length of the vector is 8.
+     */
+    safe_union Bands {
+        /** Valid only if radioAccessNetwork = GERAN. */
+        vec<GeranBands> geranBands;
+        /** Valid only if radioAccessNetwork = UTRAN. */
+        vec<UtranBands> utranBands;
+        /** Valid only if radioAccessNetwork = EUTRAN. */
+        vec<EutranBands> eutranBands;
+        /** Valid only if radioAccessNetwork = NGRAN. */
+        vec<NgranBands> ngranBands;
+    } bands;
+
+    /**
+     * The radio channels to scan as defined in 3GPP TS 25.101 and 36.101.
+     * Maximum length of the vector is 32.
+     */
+    vec<int32_t> channels;
+};
+
+enum NgranBands : int32_t {
+    /** 3GPP TS 38.101-1, Table 5.2-1: FR1 bands */
+    BAND_1 = 1,
+    BAND_2 = 2,
+    BAND_3 = 3,
+    BAND_5 = 5,
+    BAND_7 = 7,
+    BAND_8 = 8,
+    BAND_12 = 12,
+    BAND_14 = 14,
+    BAND_18 = 18,
+    BAND_20 = 20,
+    BAND_25 = 25,
+    BAND_28 = 28,
+    BAND_29 = 29,
+    BAND_30 = 30,
+    BAND_34 = 34,
+    BAND_38 = 38,
+    BAND_39 = 39,
+    BAND_40 = 40,
+    BAND_41 = 41,
+    BAND_48 = 48,
+    BAND_50 = 50,
+    BAND_51 = 51,
+    BAND_65 = 65,
+    BAND_66 = 66,
+    BAND_70 = 70,
+    BAND_71 = 71,
+    BAND_74 = 74,
+    BAND_75 = 75,
+    BAND_76 = 76,
+    BAND_77 = 77,
+    BAND_78 = 78,
+    BAND_79 = 79,
+    BAND_80 = 80,
+    BAND_81 = 81,
+    BAND_82 = 82,
+    BAND_83 = 83,
+    BAND_84 = 84,
+    BAND_86 = 86,
+    BAND_90 = 90,
+    /** 3GPP TS 38.101-2, Table 5.2-1: FR2 bands */
+    BAND_257 = 257,
+    BAND_258 = 258,
+    BAND_260 = 260,
+    BAND_261 = 261,
+};
+
+/**
+ * Overwritten from @1.2::NetworkScanRequest to update
+ * RadioAccessSpecifier to 1.5 version
+ */
+struct NetworkScanRequest {
+    ScanType type;
+
+    /**
+     * Time interval in seconds between the completion of one scan and the start of
+     * a subsequent scan.
+     * Implementations may ignore this field unless the 'type' is 'PERIODIC'.
+     * Range: ScanIntervalRange:MIN to ScanIntervalRange:MAX
+     */
+    int32_t interval;
+
+    /**
+     * Networks with bands/channels to scan
+     * Maximum length of the vector is RadioConst:RADIO_ACCESS_SPECIFIER_MAX_SIZE
+     */
+    vec<RadioAccessSpecifier> specifiers;
+
+    /**
+     * Maximum duration of the periodic search (in seconds).
+     * If the search lasts maxSearchTime, it must be terminated.
+     * Range: MaxSearchTimeRange:MIN to MaxSearchTimeRange:MAX
+     */
+    int32_t maxSearchTime;
+
+    /**
+     * Indicates whether the modem must report incremental results of the network scan
+     * to the client.
+     * FALSE – Incremental results must not be reported.
+     * TRUE  – Incremental must be reported.
+     */
+    bool incrementalResults;
+
+    /**
+     * Indicates the periodicity with which the modem must report incremental results to
+     * the client (in seconds).
+     * Implementations may ignore this value if the incremental results are not requested.
+     * This value must be less than or equal to maxSearchTime.
+     * Range: IncrementalResultsPeriodicityRange:MIN to IncrementalResultsPeriodicityRange:MAX
+     */
+    int32_t incrementalResultsPeriodicity;
+
+    /**
+     * Describes the List of PLMN ids (MCC-MNC)
+     * If any PLMN of this list is found, search must end at that point and results with all
+     * PLMN found until that point should be sent as response.
+     * If the list is not sent, search to be completed until end and all PLMNs found to be
+     * reported.
+     */
+    vec<string> mccMncs;
+};
diff --git a/radio/1.5/vts/OWNERS b/radio/1.5/vts/OWNERS
new file mode 100644
index 0000000..3629a6c
--- /dev/null
+++ b/radio/1.5/vts/OWNERS
@@ -0,0 +1,10 @@
+# Telephony team
+refuhoo@google.com
+amitmahajan@google.com
+jackyu@google.com
+fionaxu@google.com
+# more to add
+
+# VTS team
+yuexima@google.com
+dshi@google.com
\ No newline at end of file
diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp
new file mode 100644
index 0000000..85c4f99
--- /dev/null
+++ b/radio/1.5/vts/functional/Android.bp
@@ -0,0 +1,40 @@
+//
+// 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: "VtsHalRadioV1_5TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "radio_hidl_hal_api.cpp",
+        "radio_hidl_hal_test.cpp",
+        "radio_response.cpp",
+        "radio_indication.cpp",
+        "VtsHalRadioV1_5TargetTest.cpp",
+    ],
+    static_libs: [
+        "RadioVtsTestUtilBase",
+        "android.hardware.radio@1.5",
+        "android.hardware.radio@1.4",
+        "android.hardware.radio@1.3",
+        "android.hardware.radio@1.2",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.0",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+    ],
+    header_libs: ["radio.util.header@1.0"],
+    test_suites: ["general-tests"]
+}
diff --git a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
new file mode 100644
index 0000000..5f11d19
--- /dev/null
+++ b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 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 <radio_hidl_hal_utils_v1_5.h>
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    RadioHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
new file mode 100644
index 0000000..67438ae
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -0,0 +1,823 @@
+/*
+ * 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 <radio_hidl_hal_utils_v1_5.h>
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() with invalid hysteresisDb
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_invalidHysteresisDb) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 10;  // hysteresisDb too large given threshold list deltas
+    signalThresholdInfo.thresholds = {-109, -103, -97, -89};
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_invalidHysteresisDb, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() with empty thresholds
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_EmptyThresholds) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI;
+    signalThresholdInfo.hysteresisMs = 0;
+    signalThresholdInfo.hysteresisDb = 0;
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_EmptyParams, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for GERAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Geran) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-109, -103, -97, -89};
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_Geran, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for UTRAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Utran) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSCP;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-110, -97, -73, -49, -25};
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::UTRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_Utran, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRP) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSRP;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-128, -108, -88, -68};
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_Eutran, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRQ) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSRQ;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-27, -20, -13, -6};
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_Eutran, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSSNR) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSNR;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-10, 0, 10, 20};
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for CDMA2000
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Cdma2000) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-105, -90, -75, -65};
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::CDMA2000);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_Cdma2000, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSRSRP
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::SSRSRP;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 0;
+    signalThresholdInfo.thresholds = {-105, -90, -75, -65};
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSRSRQ
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::SSRSRQ;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 0;
+    signalThresholdInfo.thresholds = {-15, -10, -5, -4};
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Disable_RSSNR) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSNR;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-10, 0, 10, 20};
+    signalThresholdInfo.isEnabled = false;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSSINR
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::SSSINR;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 0;
+    signalThresholdInfo.thresholds = {-10, 3, 16, 18};
+    signalThresholdInfo.isEnabled = true;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.enableUiccApplications() for the response returned.
+ * For SIM ABSENT case.
+ */
+TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) {
+    // This test case only test SIM ABSENT case.
+    if (cardStatus.base.base.cardState != CardState::ABSENT) return;
+
+    // Disable Uicc applications.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->enableUiccApplications(serial, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is absent, RadioError::SIM_ABSENT should be thrown.
+    EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error);
+
+    // Query Uicc application enablement.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->areUiccApplicationsEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is absent, RadioError::SIM_ABSENT should be thrown.
+    EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error);
+}
+
+/*
+ * Test IRadio.enableUiccApplications() for the response returned.
+ * For SIM PRESENT case.
+ */
+TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) {
+    // This test case only test SIM ABSENT case.
+    if (cardStatus.base.base.cardState != CardState::PRESENT) return;
+
+    // Disable Uicc applications.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->enableUiccApplications(serial, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is present, there shouldn't be error.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    // Query Uicc application enablement.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->areUiccApplicationsEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is present, there shouldn't be error.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+    ASSERT_FALSE(radioRsp_v1_5->areUiccApplicationsEnabled);
+
+    // Enable Uicc applications.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->enableUiccApplications(serial, true);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is present, there shouldn't be error.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    // Query Uicc application enablement.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->areUiccApplicationsEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    // As SIM is present, there shouldn't be error.
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+    ASSERT_TRUE(radioRsp_v1_5->areUiccApplicationsEnabled);
+}
+
+/*
+ * Test IRadio.areUiccApplicationsEnabled() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, areUiccApplicationsEnabled) {
+    // Disable Uicc applications.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->areUiccApplicationsEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    // If SIM is absent, RadioError::SIM_ABSENT should be thrown. Otherwise there shouldn't be any
+    // error.
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error);
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+    }
+}
+
+/*
+ * Test IRadio.setSystemSelectionChannels_1_5() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, setSystemSelectionChannels_1_5) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
+    rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480};
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
+            .bands = rasBands,
+            .channels = {1, 2}};
+
+    Return<void> res = radio_v1_5->setSystemSelectionChannels_1_5(serial, true, {specifier});
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_v1_5->rspInfo.error,
+            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR}));
+
+    if (radioRsp_v1_5->rspInfo.error == RadioError::NONE) {
+        serial = GetRandomSerialNumber();
+        Return<void> res = radio_v1_5->setSystemSelectionChannels_1_5(serial, false, {specifier});
+        ASSERT_OK(res);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+        ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
+              toString(radioRsp_v1_5->rspInfo.error).c_str());
+        EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan_1_5() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, startNetworkScan) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
+    rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480};
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
+            .bands = rasBands,
+            .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_5::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
+
+    Return<void> res = radio_v1_5->startNetworkScan_1_5(serial, request);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("startNetworkScan, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str());
+
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do
+        // not support the required manual GSM search functionality. This is
+        // tracked in b/112206766. Modems have "GSM" rat scan need to
+        // support scanning requests combined with some parameters.
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan_1_5() with invalid specifier.
+ */
+TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidArgument) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::NetworkScanRequest request = {.type = ScanType::ONE_SHOT,
+                                                                    .interval = 60};
+
+    Return<void> res = radio_v1_5->startNetworkScan_1_5(serial, request);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_5->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan_1_5() with invalid interval (lower boundary).
+ */
+TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval1) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
+    rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480};
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
+            .bands = rasBands,
+            .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_5::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 4,
+            .specifiers = {specifier},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
+
+    Return<void> res = radio_v1_5->startNetworkScan_1_5(serial, request);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("startNetworkScan_InvalidInterval1, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_5->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan_1_5() with invalid interval (upper boundary).
+ */
+TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval2) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
+    rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480};
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
+            .bands = rasBands,
+            .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_5::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 301,
+            .specifiers = {specifier},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
+
+    Return<void> res = radio_v1_5->startNetworkScan_1_5(serial, request);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("startNetworkScan_InvalidInterval2, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_5->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan_1_5() with invalid max search time (lower boundary).
+ */
+TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime1) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
+    rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480};
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
+            .bands = rasBands,
+            .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_5::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 59,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
+
+    Return<void> res = radio_v1_5->startNetworkScan_1_5(serial, request);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("startNetworkScan_InvalidMaxSearchTime1, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_5->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan_1_5() with invalid max search time (upper boundary).
+ */
+TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime2) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
+    rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480};
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
+            .bands = rasBands,
+            .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_5::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 3601,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
+
+    Return<void> res = radio_v1_5->startNetworkScan_1_5(serial, request);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("startNetworkScan_InvalidMaxSearchTime2, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_5->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan_1_5() with invalid periodicity (lower boundary).
+ */
+TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity1) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
+    rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480};
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
+            .bands = rasBands,
+            .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_5::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 600,
+            .incrementalResults = true,
+            .incrementalResultsPeriodicity = 0};
+
+    Return<void> res = radio_v1_5->startNetworkScan_1_5(serial, request);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("startNetworkScan_InvalidPeriodicity1, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_5->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan_1_5() with invalid periodicity (upper boundary).
+ */
+TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity2) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
+    rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480};
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
+            .bands = rasBands,
+            .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_5::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 600,
+            .incrementalResults = true,
+            .incrementalResultsPeriodicity = 11};
+
+    Return<void> res = radio_v1_5->startNetworkScan_1_5(serial, request);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("startNetworkScan_InvalidPeriodicity2, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_5->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan_1_5() with valid periodicity
+ */
+TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest1) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
+    rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480};
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
+            .bands = rasBands,
+            .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_5::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 360,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 10};
+
+    Return<void> res = radio_v1_5->startNetworkScan_1_5(serial, request);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("startNetworkScan_GoodRequest1, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::NONE, RadioError::SIM_ABSENT}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
+                                      RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
+
+/*
+ * Test IRadio.startNetworkScan_1_5() with valid periodicity and plmns
+ */
+TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest2) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
+    rasBands.geranBands() = {GeranBands::BAND_450, GeranBands::BAND_480};
+
+    ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier = {
+            .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
+            .bands = rasBands,
+            .channels = {1, 2}};
+
+    ::android::hardware::radio::V1_5::NetworkScanRequest request = {
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 360,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 10,
+            .mccMncs = {"310410"}};
+
+    Return<void> res = radio_v1_5->startNetworkScan_1_5(serial, request);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    ALOGI("startNetworkScan_GoodRequest2, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::NONE, RadioError::SIM_ABSENT}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
+                                      RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
new file mode 100644
index 0000000..a5d236d
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 <radio_hidl_hal_utils_v1_5.h>
+
+void RadioHidlTest_v1_5::SetUp() {
+    radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService<
+            ::android::hardware::radio::V1_5::IRadio>(
+            RadioHidlEnvironment::Instance()
+                    ->getServiceName<::android::hardware::radio::V1_5::IRadio>(
+                            hidl_string(RADIO_SERVICE_NAME)));
+    if (radio_v1_5 == NULL) {
+        sleep(60);
+        radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService<
+                ::android::hardware::radio::V1_5::IRadio>(
+                RadioHidlEnvironment::Instance()
+                        ->getServiceName<::android::hardware::radio::V1_5::IRadio>(
+                                hidl_string(RADIO_SERVICE_NAME)));
+    }
+    ASSERT_NE(nullptr, radio_v1_5.get());
+
+    radioRsp_v1_5 = new (std::nothrow) RadioResponse_v1_5(*this);
+    ASSERT_NE(nullptr, radioRsp_v1_5.get());
+
+    count_ = 0;
+
+    radioInd_v1_5 = new (std::nothrow) RadioIndication_v1_5(*this);
+    ASSERT_NE(nullptr, radioInd_v1_5.get());
+
+    radio_v1_5->setResponseFunctions(radioRsp_v1_5, radioInd_v1_5);
+
+    updateSimCardStatus();
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig =
+            ::testing::VtsHalHidlTargetTestBase::getService<
+                    ::android::hardware::radio::config::V1_1::IRadioConfig>();
+
+    /* Enforce Vts tesing with RadioConfig is existed. */
+    ASSERT_NE(nullptr, radioConfig.get());
+
+    /* Enforce Vts Testing with Sim Status Present only. */
+    EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.cardState);
+}
+
+/*
+ * Notify that the response message is received.
+ */
+void RadioHidlTest_v1_5::notify(int receivedSerial) {
+    std::unique_lock<std::mutex> lock(mtx_);
+    if (serial == receivedSerial) {
+        count_++;
+        cv_.notify_one();
+    }
+}
+
+/*
+ * Wait till the response message is notified or till TIMEOUT_PERIOD.
+ */
+std::cv_status RadioHidlTest_v1_5::wait() {
+    std::unique_lock<std::mutex> lock(mtx_);
+
+    std::cv_status status = std::cv_status::no_timeout;
+    auto now = std::chrono::system_clock::now();
+    while (count_ == 0) {
+        status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) {
+            return status;
+        }
+    }
+    count_--;
+    return status;
+}
+
+void RadioHidlTest_v1_5::updateSimCardStatus() {
+    serial = GetRandomSerialNumber();
+    radio_v1_5->getIccCardStatus(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
new file mode 100644
index 0000000..01bda69
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -0,0 +1,783 @@
+/*
+ * 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 <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include <android/hardware/radio/config/1.1/IRadioConfig.h>
+
+#include <android/hardware/radio/1.5/IRadio.h>
+#include <android/hardware/radio/1.5/IRadioIndication.h>
+#include <android/hardware/radio/1.5/IRadioResponse.h>
+#include <android/hardware/radio/1.5/types.h>
+
+#include "vts_test_util.h"
+
+using namespace ::android::hardware::radio::V1_5;
+using namespace ::android::hardware::radio::V1_4;
+using namespace ::android::hardware::radio::V1_3;
+using namespace ::android::hardware::radio::V1_2;
+using namespace ::android::hardware::radio::V1_1;
+using namespace ::android::hardware::radio::V1_0;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+#define TIMEOUT_PERIOD 75
+#define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
+#define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
+
+#define RADIO_SERVICE_NAME "slot1"
+
+class RadioHidlTest_v1_5;
+extern ::android::hardware::radio::V1_4::CardStatus cardStatus;
+
+/* Callback class for radio response v1_5 */
+class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioResponse {
+  protected:
+    RadioHidlTest_v1_5& parent_v1_5;
+
+  public:
+    hidl_vec<RadioBandMode> radioBandModes;
+
+    RadioResponseInfo rspInfo;
+
+    // Call
+    hidl_vec<::android::hardware::radio::V1_2::Call> currentCalls;
+
+    // Modem
+    bool isModemEnabled;
+    bool enableModemResponseToggle;
+
+    ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
+            networkTypeBitmapResponse;
+
+    // Data
+    ::android::hardware::radio::V1_4::DataRegStateResult dataRegResp;
+
+    // SimLock status
+    ::android::hardware::radio::V1_4::CarrierRestrictionsWithPriority carrierRestrictionsResp;
+    ::android::hardware::radio::V1_4::SimLockMultiSimPolicy multiSimPolicyResp;
+
+    // Whether toggling uicc applications operation is supported.
+    bool canToggleUiccApplicationsEnablement;
+
+    // Whether Uicc applications are enabled or not.
+    bool areUiccApplicationsEnabled;
+
+    RadioResponse_v1_5(RadioHidlTest_v1_5& parent_v1_5);
+    virtual ~RadioResponse_v1_5() = default;
+
+    Return<void> getIccCardStatusResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::CardStatus& cardStatus);
+
+    Return<void> supplyIccPinForAppResponse(const RadioResponseInfo& info,
+                                            int32_t remainingRetries);
+
+    Return<void> supplyIccPukForAppResponse(const RadioResponseInfo& info,
+                                            int32_t remainingRetries);
+
+    Return<void> supplyIccPin2ForAppResponse(const RadioResponseInfo& info,
+                                             int32_t remainingRetries);
+
+    Return<void> supplyIccPuk2ForAppResponse(const RadioResponseInfo& info,
+                                             int32_t remainingRetries);
+
+    Return<void> changeIccPinForAppResponse(const RadioResponseInfo& info,
+                                            int32_t remainingRetries);
+
+    Return<void> changeIccPin2ForAppResponse(const RadioResponseInfo& info,
+                                             int32_t remainingRetries);
+
+    Return<void> supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info,
+                                                        int32_t remainingRetries);
+
+    Return<void> getCurrentCallsResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& calls);
+
+    Return<void> dialResponse(const RadioResponseInfo& info);
+
+    Return<void> getIMSIForAppResponse(const RadioResponseInfo& info,
+                                       const ::android::hardware::hidl_string& imsi);
+
+    Return<void> hangupConnectionResponse(const RadioResponseInfo& info);
+
+    Return<void> hangupWaitingOrBackgroundResponse(const RadioResponseInfo& info);
+
+    Return<void> hangupForegroundResumeBackgroundResponse(const RadioResponseInfo& info);
+
+    Return<void> switchWaitingOrHoldingAndActiveResponse(const RadioResponseInfo& info);
+
+    Return<void> conferenceResponse(const RadioResponseInfo& info);
+
+    Return<void> rejectCallResponse(const RadioResponseInfo& info);
+
+    Return<void> getLastCallFailCauseResponse(const RadioResponseInfo& info,
+                                              const LastCallFailCauseInfo& failCauseInfo);
+
+    Return<void> getSignalStrengthResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::SignalStrength& sigStrength);
+
+    Return<void> getVoiceRegistrationStateResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::VoiceRegStateResult& voiceRegResponse);
+
+    Return<void> getDataRegistrationStateResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::DataRegStateResult& dataRegResponse);
+
+    Return<void> getOperatorResponse(const RadioResponseInfo& info,
+                                     const ::android::hardware::hidl_string& longName,
+                                     const ::android::hardware::hidl_string& shortName,
+                                     const ::android::hardware::hidl_string& numeric);
+
+    Return<void> setRadioPowerResponse(const RadioResponseInfo& info);
+
+    Return<void> sendDtmfResponse(const RadioResponseInfo& info);
+
+    Return<void> sendSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+    Return<void> sendSMSExpectMoreResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+    Return<void> setupDataCallResponse(
+            const RadioResponseInfo& info,
+            const android::hardware::radio::V1_0::SetupDataCallResult& dcResponse);
+
+    Return<void> iccIOForAppResponse(const RadioResponseInfo& info, const IccIoResult& iccIo);
+
+    Return<void> sendUssdResponse(const RadioResponseInfo& info);
+
+    Return<void> cancelPendingUssdResponse(const RadioResponseInfo& info);
+
+    Return<void> getClirResponse(const RadioResponseInfo& info, int32_t n, int32_t m);
+
+    Return<void> setClirResponse(const RadioResponseInfo& info);
+
+    Return<void> getCallForwardStatusResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<CallForwardInfo>& call_forwardInfos);
+
+    Return<void> setCallForwardResponse(const RadioResponseInfo& info);
+
+    Return<void> getCallWaitingResponse(const RadioResponseInfo& info, bool enable,
+                                        int32_t serviceClass);
+
+    Return<void> setCallWaitingResponse(const RadioResponseInfo& info);
+
+    Return<void> acknowledgeLastIncomingGsmSmsResponse(const RadioResponseInfo& info);
+
+    Return<void> acceptCallResponse(const RadioResponseInfo& info);
+
+    Return<void> deactivateDataCallResponse(const RadioResponseInfo& info);
+
+    Return<void> getFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t response);
+
+    Return<void> setFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t retry);
+
+    Return<void> setBarringPasswordResponse(const RadioResponseInfo& info);
+
+    Return<void> getNetworkSelectionModeResponse(const RadioResponseInfo& info, bool manual);
+
+    Return<void> setNetworkSelectionModeAutomaticResponse(const RadioResponseInfo& info);
+
+    Return<void> setNetworkSelectionModeManualResponse(const RadioResponseInfo& info);
+
+    Return<void> getAvailableNetworksResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<OperatorInfo>& networkInfos);
+
+    Return<void> startDtmfResponse(const RadioResponseInfo& info);
+
+    Return<void> stopDtmfResponse(const RadioResponseInfo& info);
+
+    Return<void> getBasebandVersionResponse(const RadioResponseInfo& info,
+                                            const ::android::hardware::hidl_string& version);
+
+    Return<void> separateConnectionResponse(const RadioResponseInfo& info);
+
+    Return<void> setMuteResponse(const RadioResponseInfo& info);
+
+    Return<void> getMuteResponse(const RadioResponseInfo& info, bool enable);
+
+    Return<void> getClipResponse(const RadioResponseInfo& info, ClipStatus status);
+
+    Return<void> getDataCallListResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<
+                    android::hardware::radio::V1_0::SetupDataCallResult>& dcResponse);
+
+    Return<void> sendOemRilRequestRawResponse(const RadioResponseInfo& info,
+                                              const ::android::hardware::hidl_vec<uint8_t>& data);
+
+    Return<void> sendOemRilRequestStringsResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data);
+
+    Return<void> setSuppServiceNotificationsResponse(const RadioResponseInfo& info);
+
+    Return<void> writeSmsToSimResponse(const RadioResponseInfo& info, int32_t index);
+
+    Return<void> deleteSmsOnSimResponse(const RadioResponseInfo& info);
+
+    Return<void> setBandModeResponse(const RadioResponseInfo& info);
+
+    Return<void> getAvailableBandModesResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<RadioBandMode>& bandModes);
+
+    Return<void> sendEnvelopeResponse(const RadioResponseInfo& info,
+                                      const ::android::hardware::hidl_string& commandResponse);
+
+    Return<void> sendTerminalResponseToSimResponse(const RadioResponseInfo& info);
+
+    Return<void> handleStkCallSetupRequestFromSimResponse(const RadioResponseInfo& info);
+
+    Return<void> explicitCallTransferResponse(const RadioResponseInfo& info);
+
+    Return<void> setPreferredNetworkTypeResponse(const RadioResponseInfo& info);
+
+    Return<void> getPreferredNetworkTypeResponse(const RadioResponseInfo& info,
+                                                 PreferredNetworkType nwType);
+
+    Return<void> getNeighboringCidsResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<NeighboringCell>& cells);
+
+    Return<void> setLocationUpdatesResponse(const RadioResponseInfo& info);
+
+    Return<void> setCdmaSubscriptionSourceResponse(const RadioResponseInfo& info);
+
+    Return<void> setCdmaRoamingPreferenceResponse(const RadioResponseInfo& info);
+
+    Return<void> getCdmaRoamingPreferenceResponse(const RadioResponseInfo& info,
+                                                  CdmaRoamingType type);
+
+    Return<void> setTTYModeResponse(const RadioResponseInfo& info);
+
+    Return<void> getTTYModeResponse(const RadioResponseInfo& info, TtyMode mode);
+
+    Return<void> setPreferredVoicePrivacyResponse(const RadioResponseInfo& info);
+
+    Return<void> getPreferredVoicePrivacyResponse(const RadioResponseInfo& info, bool enable);
+
+    Return<void> sendCDMAFeatureCodeResponse(const RadioResponseInfo& info);
+
+    Return<void> sendBurstDtmfResponse(const RadioResponseInfo& info);
+
+    Return<void> sendCdmaSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+    Return<void> acknowledgeLastIncomingCdmaSmsResponse(const RadioResponseInfo& info);
+
+    Return<void> getGsmBroadcastConfigResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& configs);
+
+    Return<void> setGsmBroadcastConfigResponse(const RadioResponseInfo& info);
+
+    Return<void> setGsmBroadcastActivationResponse(const RadioResponseInfo& info);
+
+    Return<void> getCdmaBroadcastConfigResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& configs);
+
+    Return<void> setCdmaBroadcastConfigResponse(const RadioResponseInfo& info);
+
+    Return<void> setCdmaBroadcastActivationResponse(const RadioResponseInfo& info);
+
+    Return<void> getCDMASubscriptionResponse(const RadioResponseInfo& info,
+                                             const ::android::hardware::hidl_string& mdn,
+                                             const ::android::hardware::hidl_string& hSid,
+                                             const ::android::hardware::hidl_string& hNid,
+                                             const ::android::hardware::hidl_string& min,
+                                             const ::android::hardware::hidl_string& prl);
+
+    Return<void> writeSmsToRuimResponse(const RadioResponseInfo& info, uint32_t index);
+
+    Return<void> deleteSmsOnRuimResponse(const RadioResponseInfo& info);
+
+    Return<void> getDeviceIdentityResponse(const RadioResponseInfo& info,
+                                           const ::android::hardware::hidl_string& imei,
+                                           const ::android::hardware::hidl_string& imeisv,
+                                           const ::android::hardware::hidl_string& esn,
+                                           const ::android::hardware::hidl_string& meid);
+
+    Return<void> exitEmergencyCallbackModeResponse(const RadioResponseInfo& info);
+
+    Return<void> getSmscAddressResponse(const RadioResponseInfo& info,
+                                        const ::android::hardware::hidl_string& smsc);
+
+    Return<void> setSmscAddressResponse(const RadioResponseInfo& info);
+
+    Return<void> reportSmsMemoryStatusResponse(const RadioResponseInfo& info);
+
+    Return<void> reportStkServiceIsRunningResponse(const RadioResponseInfo& info);
+
+    Return<void> getCdmaSubscriptionSourceResponse(const RadioResponseInfo& info,
+                                                   CdmaSubscriptionSource source);
+
+    Return<void> requestIsimAuthenticationResponse(
+            const RadioResponseInfo& info, const ::android::hardware::hidl_string& response);
+
+    Return<void> acknowledgeIncomingGsmSmsWithPduResponse(const RadioResponseInfo& info);
+
+    Return<void> sendEnvelopeWithStatusResponse(const RadioResponseInfo& info,
+                                                const IccIoResult& iccIo);
+
+    Return<void> getVoiceRadioTechnologyResponse(
+            const RadioResponseInfo& info, ::android::hardware::radio::V1_0::RadioTechnology rat);
+
+    Return<void> getCellInfoListResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>&
+                    cellInfo);
+
+    Return<void> setCellInfoListRateResponse(const RadioResponseInfo& info);
+
+    Return<void> setInitialAttachApnResponse(const RadioResponseInfo& info);
+
+    Return<void> getImsRegistrationStateResponse(const RadioResponseInfo& info, bool isRegistered,
+                                                 RadioTechnologyFamily ratFamily);
+
+    Return<void> sendImsSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+    Return<void> iccTransmitApduBasicChannelResponse(const RadioResponseInfo& info,
+                                                     const IccIoResult& result);
+
+    Return<void> iccOpenLogicalChannelResponse(
+            const RadioResponseInfo& info, int32_t channelId,
+            const ::android::hardware::hidl_vec<int8_t>& selectResponse);
+
+    Return<void> iccCloseLogicalChannelResponse(const RadioResponseInfo& info);
+
+    Return<void> iccTransmitApduLogicalChannelResponse(const RadioResponseInfo& info,
+                                                       const IccIoResult& result);
+
+    Return<void> nvReadItemResponse(const RadioResponseInfo& info,
+                                    const ::android::hardware::hidl_string& result);
+
+    Return<void> nvWriteItemResponse(const RadioResponseInfo& info);
+
+    Return<void> nvWriteCdmaPrlResponse(const RadioResponseInfo& info);
+
+    Return<void> nvResetConfigResponse(const RadioResponseInfo& info);
+
+    Return<void> setUiccSubscriptionResponse(const RadioResponseInfo& info);
+
+    Return<void> setDataAllowedResponse(const RadioResponseInfo& info);
+
+    Return<void> getHardwareConfigResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<HardwareConfig>& config);
+
+    Return<void> requestIccSimAuthenticationResponse(const RadioResponseInfo& info,
+                                                     const IccIoResult& result);
+
+    Return<void> setDataProfileResponse(const RadioResponseInfo& info);
+
+    Return<void> requestShutdownResponse(const RadioResponseInfo& info);
+
+    Return<void> getRadioCapabilityResponse(
+            const RadioResponseInfo& info,
+            const android::hardware::radio::V1_0::RadioCapability& rc);
+
+    Return<void> setRadioCapabilityResponse(
+            const RadioResponseInfo& info,
+            const android::hardware::radio::V1_0::RadioCapability& rc);
+
+    Return<void> startLceServiceResponse(const RadioResponseInfo& info,
+                                         const LceStatusInfo& statusInfo);
+
+    Return<void> stopLceServiceResponse(const RadioResponseInfo& info,
+                                        const LceStatusInfo& statusInfo);
+
+    Return<void> pullLceDataResponse(const RadioResponseInfo& info, const LceDataInfo& lceInfo);
+
+    Return<void> getModemActivityInfoResponse(const RadioResponseInfo& info,
+                                              const ActivityStatsInfo& activityInfo);
+
+    Return<void> setAllowedCarriersResponse(const RadioResponseInfo& info, int32_t numAllowed);
+
+    Return<void> getAllowedCarriersResponse(const RadioResponseInfo& info, bool allAllowed,
+                                            const CarrierRestrictions& carriers);
+
+    Return<void> sendDeviceStateResponse(const RadioResponseInfo& info);
+
+    Return<void> setIndicationFilterResponse(const RadioResponseInfo& info);
+
+    Return<void> setSimCardPowerResponse(const RadioResponseInfo& info);
+
+    Return<void> acknowledgeRequest(int32_t serial);
+
+    /* 1.1 Api */
+    Return<void> setCarrierInfoForImsiEncryptionResponse(const RadioResponseInfo& info);
+
+    Return<void> setSimCardPowerResponse_1_1(const RadioResponseInfo& info);
+
+    Return<void> startNetworkScanResponse(const RadioResponseInfo& info);
+
+    Return<void> stopNetworkScanResponse(const RadioResponseInfo& info);
+
+    Return<void> startKeepaliveResponse(const RadioResponseInfo& info,
+                                        const KeepaliveStatus& status);
+
+    Return<void> stopKeepaliveResponse(const RadioResponseInfo& info);
+
+    /* 1.2 Api */
+    Return<void> setSignalStrengthReportingCriteriaResponse(const RadioResponseInfo& info);
+
+    Return<void> setLinkCapacityReportingCriteriaResponse(const RadioResponseInfo& info);
+
+    Return<void> getIccCardStatusResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_2::CardStatus& card_status);
+
+    Return<void> getCurrentCallsResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls);
+
+    Return<void> getSignalStrengthResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_2::SignalStrength& sig_strength);
+
+    Return<void> getSignalStrengthResponse_1_4(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_4::SignalStrength& sig_strength);
+
+    Return<void> getCellInfoListResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>&
+                    cellInfo);
+
+    Return<void> getVoiceRegistrationStateResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_2::VoiceRegStateResult& voiceRegResponse);
+
+    Return<void> getDataRegistrationStateResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_2::DataRegStateResult& dataRegResponse);
+
+    /* 1.3 Api */
+    Return<void> setSystemSelectionChannelsResponse(const RadioResponseInfo& info);
+
+    Return<void> enableModemResponse(const RadioResponseInfo& info);
+
+    Return<void> getModemStackStatusResponse(const RadioResponseInfo& info, const bool enabled);
+
+    /* 1.4 Api */
+    Return<void> emergencyDialResponse(const RadioResponseInfo& info);
+
+    Return<void> startNetworkScanResponse_1_4(const RadioResponseInfo& info);
+
+    Return<void> getCellInfoListResponse_1_4(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>&
+                    cellInfo);
+
+    Return<void> getDataRegistrationStateResponse_1_4(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse);
+
+    Return<void> getIccCardStatusResponse_1_4(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_4::CardStatus& card_status);
+
+    Return<void> getPreferredNetworkTypeBitmapResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_bitfield<
+                    ::android::hardware::radio::V1_4::RadioAccessFamily>
+                    networkTypeBitmap);
+
+    Return<void> setPreferredNetworkTypeBitmapResponse(const RadioResponseInfo& info);
+
+    Return<void> getDataCallListResponse_1_4(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<
+                    ::android::hardware::radio::V1_4::SetupDataCallResult>& dcResponse);
+
+    Return<void> setupDataCallResponse_1_4(
+            const RadioResponseInfo& info,
+            const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse);
+
+    Return<void> setAllowedCarriersResponse_1_4(const RadioResponseInfo& info);
+
+    Return<void> getAllowedCarriersResponse_1_4(const RadioResponseInfo& info,
+                                                const CarrierRestrictionsWithPriority& carriers,
+                                                SimLockMultiSimPolicy multiSimPolicy);
+
+    /* 1.5 Api */
+    Return<void> setSignalStrengthReportingCriteriaResponse_1_5(const RadioResponseInfo& info);
+
+    Return<void> enableUiccApplicationsResponse(const RadioResponseInfo& info);
+
+    Return<void> areUiccApplicationsEnabledResponse(const RadioResponseInfo& info, bool enabled);
+
+    Return<void> canToggleUiccApplicationsEnablementResponse(const RadioResponseInfo& info,
+                                                             bool canToggle);
+
+    Return<void> setSystemSelectionChannelsResponse_1_5(const RadioResponseInfo& info);
+
+    Return<void> startNetworkScanResponse_1_5(const RadioResponseInfo& info);
+};
+
+/* Callback class for radio indication */
+class RadioIndication_v1_5 : public ::android::hardware::radio::V1_5::IRadioIndication {
+  protected:
+    RadioHidlTest_v1_5& parent_v1_5;
+
+  public:
+    RadioIndication_v1_5(RadioHidlTest_v1_5& parent_v1_5);
+    virtual ~RadioIndication_v1_5() = default;
+
+    /* 1.5 Api */
+    Return<void> uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled);
+
+    /* 1.4 Api */
+    Return<void> currentEmergencyNumberList(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<EmergencyNumber>& emergencyNumberList);
+
+    Return<void> cellInfoList_1_4(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>&
+                    records);
+
+    Return<void> networkScanResult_1_4(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_4::NetworkScanResult& result);
+
+    Return<void> currentPhysicalChannelConfigs_1_4(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<
+                    ::android::hardware::radio::V1_4::PhysicalChannelConfig>& configs);
+
+    Return<void> dataCallListChanged_1_4(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<
+                    android::hardware::radio::V1_4::SetupDataCallResult>& dcList);
+
+    /* 1.2 Api */
+    Return<void> networkScanResult_1_2(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_2::NetworkScanResult& result);
+
+    Return<void> cellInfoList_1_2(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>&
+                    records);
+
+    Return<void> currentLinkCapacityEstimate(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_2::LinkCapacityEstimate& lce);
+
+    Return<void> currentPhysicalChannelConfigs(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<
+                    ::android::hardware::radio::V1_2::PhysicalChannelConfig>& configs);
+
+    Return<void> currentSignalStrength_1_2(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_2::SignalStrength& signalStrength);
+
+    Return<void> currentSignalStrength_1_4(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_4::SignalStrength& signalStrength);
+
+    /* 1.1 Api */
+    Return<void> carrierInfoForImsiEncryption(RadioIndicationType info);
+
+    Return<void> networkScanResult(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_1::NetworkScanResult& result);
+
+    Return<void> keepaliveStatus(RadioIndicationType type, const KeepaliveStatus& status);
+
+    /* 1.0 Api */
+    Return<void> radioStateChanged(RadioIndicationType type, RadioState radioState);
+
+    Return<void> callStateChanged(RadioIndicationType type);
+
+    Return<void> networkStateChanged(RadioIndicationType type);
+
+    Return<void> newSms(RadioIndicationType type,
+                        const ::android::hardware::hidl_vec<uint8_t>& pdu);
+
+    Return<void> newSmsStatusReport(RadioIndicationType type,
+                                    const ::android::hardware::hidl_vec<uint8_t>& pdu);
+
+    Return<void> newSmsOnSim(RadioIndicationType type, int32_t recordNumber);
+
+    Return<void> onUssd(RadioIndicationType type, UssdModeType modeType,
+                        const ::android::hardware::hidl_string& msg);
+
+    Return<void> nitzTimeReceived(RadioIndicationType type,
+                                  const ::android::hardware::hidl_string& nitzTime,
+                                  uint64_t receivedTime);
+
+    Return<void> currentSignalStrength(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_0::SignalStrength& signalStrength);
+
+    Return<void> dataCallListChanged(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<
+                    android::hardware::radio::V1_0::SetupDataCallResult>& dcList);
+
+    Return<void> suppSvcNotify(RadioIndicationType type, const SuppSvcNotification& suppSvc);
+
+    Return<void> stkSessionEnd(RadioIndicationType type);
+
+    Return<void> stkProactiveCommand(RadioIndicationType type,
+                                     const ::android::hardware::hidl_string& cmd);
+
+    Return<void> stkEventNotify(RadioIndicationType type,
+                                const ::android::hardware::hidl_string& cmd);
+
+    Return<void> stkCallSetup(RadioIndicationType type, int64_t timeout);
+
+    Return<void> simSmsStorageFull(RadioIndicationType type);
+
+    Return<void> simRefresh(RadioIndicationType type, const SimRefreshResult& refreshResult);
+
+    Return<void> callRing(RadioIndicationType type, bool isGsm, const CdmaSignalInfoRecord& record);
+
+    Return<void> simStatusChanged(RadioIndicationType type);
+
+    Return<void> cdmaNewSms(RadioIndicationType type, const CdmaSmsMessage& msg);
+
+    Return<void> newBroadcastSms(RadioIndicationType type,
+                                 const ::android::hardware::hidl_vec<uint8_t>& data);
+
+    Return<void> cdmaRuimSmsStorageFull(RadioIndicationType type);
+
+    Return<void> restrictedStateChanged(RadioIndicationType type, PhoneRestrictedState state);
+
+    Return<void> enterEmergencyCallbackMode(RadioIndicationType type);
+
+    Return<void> cdmaCallWaiting(RadioIndicationType type,
+                                 const CdmaCallWaiting& callWaitingRecord);
+
+    Return<void> cdmaOtaProvisionStatus(RadioIndicationType type, CdmaOtaProvisionStatus status);
+
+    Return<void> cdmaInfoRec(RadioIndicationType type, const CdmaInformationRecords& records);
+
+    Return<void> indicateRingbackTone(RadioIndicationType type, bool start);
+
+    Return<void> resendIncallMute(RadioIndicationType type);
+
+    Return<void> cdmaSubscriptionSourceChanged(RadioIndicationType type,
+                                               CdmaSubscriptionSource cdmaSource);
+
+    Return<void> cdmaPrlChanged(RadioIndicationType type, int32_t version);
+
+    Return<void> exitEmergencyCallbackMode(RadioIndicationType type);
+
+    Return<void> rilConnected(RadioIndicationType type);
+
+    Return<void> voiceRadioTechChanged(RadioIndicationType type,
+                                       ::android::hardware::radio::V1_0::RadioTechnology rat);
+
+    Return<void> cellInfoList(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>&
+                    records);
+
+    Return<void> imsNetworkStateChanged(RadioIndicationType type);
+
+    Return<void> subscriptionStatusChanged(RadioIndicationType type, bool activate);
+
+    Return<void> srvccStateNotify(RadioIndicationType type, SrvccState state);
+
+    Return<void> hardwareConfigChanged(
+            RadioIndicationType type, const ::android::hardware::hidl_vec<HardwareConfig>& configs);
+
+    Return<void> radioCapabilityIndication(
+            RadioIndicationType type, const android::hardware::radio::V1_0::RadioCapability& rc);
+
+    Return<void> onSupplementaryServiceIndication(RadioIndicationType type,
+                                                  const StkCcUnsolSsResult& ss);
+
+    Return<void> stkCallControlAlphaNotify(RadioIndicationType type,
+                                           const ::android::hardware::hidl_string& alpha);
+
+    Return<void> lceData(RadioIndicationType type, const LceDataInfo& lce);
+
+    Return<void> pcoData(RadioIndicationType type, const PcoDataInfo& pco);
+
+    Return<void> modemReset(RadioIndicationType type,
+                            const ::android::hardware::hidl_string& reason);
+};
+
+// Test environment for Radio HIDL HAL.
+class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    // get the test environment singleton
+    static RadioHidlEnvironment* Instance() {
+        static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
+        return instance;
+    }
+    virtual void registerTestServices() override {
+        registerTestService<::android::hardware::radio::V1_5::IRadio>();
+    }
+
+  private:
+    RadioHidlEnvironment() {}
+};
+
+// The main test class for Radio HIDL.
+class RadioHidlTest_v1_5 : public ::testing::VtsHalHidlTargetTestBase {
+  protected:
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int count_;
+
+    /* Serial number for radio request */
+    int serial;
+
+    /* Clear Potential Established Calls */
+    void clearPotentialEstablishedCalls();
+
+    /* Update Sim Card Status */
+    void updateSimCardStatus();
+
+  public:
+    virtual void SetUp() override;
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    void notify(int receivedSerial);
+
+    /* Test code calls this function to wait for response */
+    std::cv_status wait();
+
+    /* radio service handle */
+    sp<::android::hardware::radio::V1_5::IRadio> radio_v1_5;
+
+    /* radio response handle */
+    sp<RadioResponse_v1_5> radioRsp_v1_5;
+
+    /* radio indication handle */
+    sp<RadioIndication_v1_5> radioInd_v1_5;
+};
diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp
new file mode 100644
index 0000000..acffbbe
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_indication.cpp
@@ -0,0 +1,335 @@
+/*
+ * 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 <radio_hidl_hal_utils_v1_5.h>
+
+RadioIndication_v1_5::RadioIndication_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
+
+/* 1.4 Apis */
+Return<void> RadioIndication_v1_5::currentPhysicalChannelConfigs_1_4(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_4::PhysicalChannelConfig>& /*configs*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkScanResult_1_4(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_4::NetworkScanResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_4(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_4::CellInfo>& /*records*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentEmergencyNumberList(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<EmergencyNumber>& /*emergencyNumberList*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::dataCallListChanged_1_4(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<android::hardware::radio::V1_4::SetupDataCallResult>&
+        /*dcList*/) {
+    return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioIndication_v1_5::networkScanResult_1_2(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_2::NetworkScanResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_2(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_2::CellInfo>& /*records*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentLinkCapacityEstimate(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_2::LinkCapacityEstimate& /*lce*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentPhysicalChannelConfigs(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_2::PhysicalChannelConfig>& /*configs*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength_1_2(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_2::SignalStrength& /*signalStrength*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength_1_4(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_4::SignalStrength& /*signalStrength*/) {
+    return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioIndication_v1_5::carrierInfoForImsiEncryption(RadioIndicationType /*info*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkScanResult(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_1::NetworkScanResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::keepaliveStatus(RadioIndicationType /*type*/,
+                                                   const KeepaliveStatus& /*status*/) {
+    return Void();
+}
+
+/* 1.0 Apis */
+Return<void> RadioIndication_v1_5::radioStateChanged(RadioIndicationType /*type*/,
+                                                     RadioState /*radioState*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::callStateChanged(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkStateChanged(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSms(RadioIndicationType /*type*/,
+                                          const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSmsStatusReport(
+        RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSmsOnSim(RadioIndicationType /*type*/,
+                                               int32_t /*recordNumber*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::onUssd(RadioIndicationType /*type*/, UssdModeType /*modeType*/,
+                                          const ::android::hardware::hidl_string& /*msg*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::nitzTimeReceived(
+        RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*nitzTime*/,
+        uint64_t /*receivedTime*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_0::SignalStrength& /*signalStrength*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::dataCallListChanged(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>&
+        /*dcList*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::suppSvcNotify(RadioIndicationType /*type*/,
+                                                 const SuppSvcNotification& /*suppSvc*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkSessionEnd(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkProactiveCommand(
+        RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*cmd*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkEventNotify(RadioIndicationType /*type*/,
+                                                  const ::android::hardware::hidl_string& /*cmd*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkCallSetup(RadioIndicationType /*type*/, int64_t /*timeout*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::simSmsStorageFull(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::simRefresh(RadioIndicationType /*type*/,
+                                              const SimRefreshResult& /*refreshResult*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::callRing(RadioIndicationType /*type*/, bool /*isGsm*/,
+                                            const CdmaSignalInfoRecord& /*record*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::simStatusChanged(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaNewSms(RadioIndicationType /*type*/,
+                                              const CdmaSmsMessage& /*msg*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::newBroadcastSms(
+        RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaRuimSmsStorageFull(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::restrictedStateChanged(RadioIndicationType /*type*/,
+                                                          PhoneRestrictedState /*state*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::enterEmergencyCallbackMode(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaCallWaiting(RadioIndicationType /*type*/,
+                                                   const CdmaCallWaiting& /*callWaitingRecord*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaOtaProvisionStatus(RadioIndicationType /*type*/,
+                                                          CdmaOtaProvisionStatus /*status*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaInfoRec(RadioIndicationType /*type*/,
+                                               const CdmaInformationRecords& /*records*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::indicateRingbackTone(RadioIndicationType /*type*/,
+                                                        bool /*start*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::resendIncallMute(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaSubscriptionSourceChanged(
+        RadioIndicationType /*type*/, CdmaSubscriptionSource /*cdmaSource*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaPrlChanged(RadioIndicationType /*type*/,
+                                                  int32_t /*version*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::exitEmergencyCallbackMode(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::rilConnected(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::voiceRadioTechChanged(
+        RadioIndicationType /*type*/, ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_0::CellInfo>& /*records*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::imsNetworkStateChanged(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::subscriptionStatusChanged(RadioIndicationType /*type*/,
+                                                             bool /*activate*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::srvccStateNotify(RadioIndicationType /*type*/,
+                                                    SrvccState /*state*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::hardwareConfigChanged(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<HardwareConfig>& /*configs*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::radioCapabilityIndication(
+        RadioIndicationType /*type*/,
+        const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::onSupplementaryServiceIndication(
+        RadioIndicationType /*type*/, const StkCcUnsolSsResult& /*ss*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkCallControlAlphaNotify(
+        RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*alpha*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::lceData(RadioIndicationType /*type*/,
+                                           const LceDataInfo& /*lce*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::pcoData(RadioIndicationType /*type*/,
+                                           const PcoDataInfo& /*pco*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::modemReset(RadioIndicationType /*type*/,
+                                              const ::android::hardware::hidl_string& /*reason*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/,
+                                                                     bool /*enabled*/) {
+    return Void();
+}
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
new file mode 100644
index 0000000..5964c96
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -0,0 +1,930 @@
+/*
+ * 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 <radio_hidl_hal_utils_v1_5.h>
+
+::android::hardware::radio::V1_4::CardStatus cardStatus;
+
+RadioResponse_v1_5::RadioResponse_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
+
+/* 1.0 Apis */
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::CardStatus& /*card_status*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPinForAppResponse(const RadioResponseInfo& /*info*/,
+                                                            int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPukForAppResponse(const RadioResponseInfo& /*info*/,
+                                                            int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
+                                                             int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPuk2ForAppResponse(const RadioResponseInfo& /*info*/,
+                                                             int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::changeIccPinForAppResponse(const RadioResponseInfo& /*info*/,
+                                                            int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::changeIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
+                                                             int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyNetworkDepersonalizationResponse(
+        const RadioResponseInfo& /*info*/, int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCurrentCallsResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::dialResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIMSIForAppResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imsi*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupConnectionResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupWaitingOrBackgroundResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupForegroundResumeBackgroundResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::switchWaitingOrHoldingAndActiveResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::conferenceResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::rejectCallResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getLastCallFailCauseResponse(
+        const RadioResponseInfo& /*info*/, const LastCallFailCauseInfo& /*failCauseInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::SignalStrength& /*sig_strength*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::VoiceRegStateResult& /*voiceRegResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::DataRegStateResult& /*dataRegResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getOperatorResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*longName*/,
+        const ::android::hardware::hidl_string& /*shortName*/,
+        const ::android::hardware::hidl_string& /*numeric*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setRadioPowerResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendSmsResponse(const RadioResponseInfo& /*info*/,
+                                                 const SendSmsResult& /*sms*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendSMSExpectMoreResponse(const RadioResponseInfo& /*info*/,
+                                                           const SendSmsResult& /*sms*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setupDataCallResponse(
+        const RadioResponseInfo& /*info*/,
+        const android::hardware::radio::V1_0::SetupDataCallResult& /*dcResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccIOForAppResponse(const RadioResponseInfo& /*info*/,
+                                                     const IccIoResult& /*iccIo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendUssdResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::cancelPendingUssdResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getClirResponse(const RadioResponseInfo& /*info*/, int32_t /*n*/,
+                                                 int32_t /*m*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setClirResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCallForwardStatusResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<CallForwardInfo>&
+        /*callForwardInfos*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCallForwardResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCallWaitingResponse(const RadioResponseInfo& /*info*/,
+                                                        bool /*enable*/, int32_t /*serviceClass*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCallWaitingResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeLastIncomingGsmSmsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::acceptCallResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::deactivateDataCallResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getFacilityLockForAppResponse(const RadioResponseInfo& /*info*/,
+                                                               int32_t /*response*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setFacilityLockForAppResponse(const RadioResponseInfo& /*info*/,
+                                                               int32_t /*retry*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setBarringPasswordResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getNetworkSelectionModeResponse(const RadioResponseInfo& /*info*/,
+                                                                 bool /*manual*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setNetworkSelectionModeAutomaticResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setNetworkSelectionModeManualResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAvailableNetworksResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<OperatorInfo>& /*networkInfos*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getBasebandVersionResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*version*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::separateConnectionResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setMuteResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getMuteResponse(const RadioResponseInfo& /*info*/,
+                                                 bool /*enable*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getClipResponse(const RadioResponseInfo& /*info*/,
+                                                 ClipStatus /*status*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataCallListResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>&
+        /*dcResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendOemRilRequestRawResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendOemRilRequestStringsResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& /*data*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSuppServiceNotificationsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::writeSmsToSimResponse(const RadioResponseInfo& /*info*/,
+                                                       int32_t /*index*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::deleteSmsOnSimResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setBandModeResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAvailableBandModesResponse(
+        const RadioResponseInfo& info,
+        const ::android::hardware::hidl_vec<RadioBandMode>& bandModes) {
+    rspInfo = info;
+    radioBandModes = bandModes;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendEnvelopeResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_string& /*commandResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendTerminalResponseToSimResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::handleStkCallSetupRequestFromSimResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::explicitCallTransferResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredNetworkTypeResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredNetworkTypeResponse(const RadioResponseInfo& /*info*/,
+                                                                 PreferredNetworkType /*nw_type*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getNeighboringCidsResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<NeighboringCell>& /*cells*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setLocationUpdatesResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaSubscriptionSourceResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaRoamingPreferenceResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaRoamingPreferenceResponse(const RadioResponseInfo& /*info*/,
+                                                                  CdmaRoamingType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setTTYModeResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getTTYModeResponse(const RadioResponseInfo& /*info*/,
+                                                    TtyMode /*mode*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredVoicePrivacyResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredVoicePrivacyResponse(const RadioResponseInfo& /*info*/,
+                                                                  bool /*enable*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendCDMAFeatureCodeResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendBurstDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendCdmaSmsResponse(const RadioResponseInfo& /*info*/,
+                                                     const SendSmsResult& /*sms*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeLastIncomingCdmaSmsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getGsmBroadcastConfigResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& /*configs*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setGsmBroadcastConfigResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setGsmBroadcastActivationResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaBroadcastConfigResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& /*configs*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaBroadcastConfigResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaBroadcastActivationResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCDMASubscriptionResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*mdn*/,
+        const ::android::hardware::hidl_string& /*hSid*/,
+        const ::android::hardware::hidl_string& /*hNid*/,
+        const ::android::hardware::hidl_string& /*min*/,
+        const ::android::hardware::hidl_string& /*prl*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::writeSmsToRuimResponse(const RadioResponseInfo& /*info*/,
+                                                        uint32_t /*index*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::deleteSmsOnRuimResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDeviceIdentityResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imei*/,
+        const ::android::hardware::hidl_string& /*imeisv*/,
+        const ::android::hardware::hidl_string& /*esn*/,
+        const ::android::hardware::hidl_string& /*meid*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::exitEmergencyCallbackModeResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSmscAddressResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*smsc*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSmscAddressResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::reportSmsMemoryStatusResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::reportStkServiceIsRunningResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaSubscriptionSourceResponse(
+        const RadioResponseInfo& /*info*/, CdmaSubscriptionSource /*source*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestIsimAuthenticationResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*response*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeIncomingGsmSmsWithPduResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendEnvelopeWithStatusResponse(const RadioResponseInfo& /*info*/,
+                                                                const IccIoResult& /*iccIo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRadioTechnologyResponse(
+        const RadioResponseInfo& /*info*/,
+        ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_0::CellInfo>& /*cellInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCellInfoListRateResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setInitialAttachApnResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getImsRegistrationStateResponse(
+        const RadioResponseInfo& /*info*/, bool /*isRegistered*/,
+        RadioTechnologyFamily /*ratFamily*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendImsSmsResponse(const RadioResponseInfo& /*info*/,
+                                                    const SendSmsResult& /*sms*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccTransmitApduBasicChannelResponse(
+        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccOpenLogicalChannelResponse(
+        const RadioResponseInfo& /*info*/, int32_t /*channelId*/,
+        const ::android::hardware::hidl_vec<int8_t>& /*selectResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccCloseLogicalChannelResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccTransmitApduLogicalChannelResponse(
+        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvReadItemResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvWriteItemResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvWriteCdmaPrlResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvResetConfigResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setUiccSubscriptionResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setDataAllowedResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getHardwareConfigResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<HardwareConfig>& /*config*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestIccSimAuthenticationResponse(
+        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setDataProfileResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestShutdownResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getRadioCapabilityResponse(
+        const RadioResponseInfo& /*info*/,
+        const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setRadioCapabilityResponse(
+        const RadioResponseInfo& /*info*/,
+        const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startLceServiceResponse(const RadioResponseInfo& /*info*/,
+                                                         const LceStatusInfo& /*statusInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopLceServiceResponse(const RadioResponseInfo& /*info*/,
+                                                        const LceStatusInfo& /*statusInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::pullLceDataResponse(const RadioResponseInfo& /*info*/,
+                                                     const LceDataInfo& /*lceInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getModemActivityInfoResponse(
+        const RadioResponseInfo& /*info*/, const ActivityStatsInfo& /*activityInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setAllowedCarriersResponse(const RadioResponseInfo& /*info*/,
+                                                            int32_t /*numAllowed*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAllowedCarriersResponse(
+        const RadioResponseInfo& /*info*/, bool /*allAllowed*/,
+        const CarrierRestrictions& /*carriers*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendDeviceStateResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setIndicationFilterResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSimCardPowerResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeRequest(int32_t /*serial*/) {
+    return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioResponse_v1_5::setCarrierInfoForImsiEncryptionResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSimCardPowerResponse_1_1(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startNetworkScanResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopNetworkScanResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startKeepaliveResponse(const RadioResponseInfo& /*info*/,
+                                                        const KeepaliveStatus& /*status*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopKeepaliveResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioResponse_v1_5::setSignalStrengthReportingCriteriaResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setLinkCapacityReportingCriteriaResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_2(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_2::CardStatus& /*card_status*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCurrentCallsResponse_1_2(
+        const RadioResponseInfo& info,
+        const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls) {
+    rspInfo = info;
+    currentCalls = calls;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse_1_2(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_2::SignalStrength& /*sig_strength*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse_1_4(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_4::SignalStrength& /*sig_strength*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse_1_2(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_2::CellInfo>& /*cellInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse_1_2(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_2::VoiceRegStateResult& /*voiceRegResponse*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse_1_2(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_2::DataRegStateResult& /*dataRegResponse*/) {
+    return Void();
+}
+
+/* 1.3 Apis */
+Return<void> RadioResponse_v1_5::setSystemSelectionChannelsResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::enableModemResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getModemStackStatusResponse(const RadioResponseInfo& info,
+                                                             const bool enabled) {
+    rspInfo = info;
+    isModemEnabled = enabled;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+/* 1.4 Apis */
+Return<void> RadioResponse_v1_5::emergencyDialResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startNetworkScanResponse_1_4(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse_1_4(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse) {
+    rspInfo = info;
+    dataRegResp = dataRegResponse;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse_1_4(
+        const RadioResponseInfo& info,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_4::CellInfo>& /*cellInfo*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_4(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_4::CardStatus& card_status) {
+    rspInfo = info;
+    cardStatus = card_status;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredNetworkTypeBitmapResponse(
+        const RadioResponseInfo& info, const ::android::hardware::hidl_bitfield<
+                                               ::android::hardware::radio::V1_4::RadioAccessFamily>
+                                               networkTypeBitmap) {
+    rspInfo = info;
+    networkTypeBitmapResponse = networkTypeBitmap;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredNetworkTypeBitmapResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataCallListResponse_1_4(
+        const RadioResponseInfo& info,
+        const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::SetupDataCallResult>&
+        /*dcResponse*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setupDataCallResponse_1_4(
+        const RadioResponseInfo& info,
+        const android::hardware::radio::V1_4::SetupDataCallResult& /*dcResponse*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setAllowedCarriersResponse_1_4(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAllowedCarriersResponse_1_4(
+        const RadioResponseInfo& info, const CarrierRestrictionsWithPriority& carriers,
+        SimLockMultiSimPolicy multiSimPolicy) {
+    rspInfo = info;
+    carrierRestrictionsResp = carriers;
+    multiSimPolicyResp = multiSimPolicy;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+/* 1.5 Apis */
+Return<void> RadioResponse_v1_5::setSignalStrengthReportingCriteriaResponse_1_5(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::enableUiccApplicationsResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::areUiccApplicationsEnabledResponse(const RadioResponseInfo& info,
+                                                                    bool enabled) {
+    rspInfo = info;
+    areUiccApplicationsEnabled = enabled;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::canToggleUiccApplicationsEnablementResponse(
+        const RadioResponseInfo& info, bool canToggle) {
+    rspInfo = info;
+    canToggleUiccApplicationsEnablement = canToggle;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSystemSelectionChannelsResponse_1_5(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startNetworkScanResponse_1_5(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
diff --git a/radio/config/1.0/Android.bp b/radio/config/1.0/Android.bp
index 7fb0ea1..387f953 100644
--- a/radio/config/1.0/Android.bp
+++ b/radio/config/1.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/config/1.0/default/Android.bp b/radio/config/1.0/default/Android.bp
index f52335e..a0f4214 100644
--- a/radio/config/1.0/default/Android.bp
+++ b/radio/config/1.0/default/Android.bp
@@ -11,7 +11,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.radio.config@1.0",
diff --git a/radio/config/1.0/default/android.hardware.radio.config@1.0-service.rc b/radio/config/1.0/default/android.hardware.radio.config@1.0-service.rc
index fad16b1..94d5edb 100644
--- a/radio/config/1.0/default/android.hardware.radio.config@1.0-service.rc
+++ b/radio/config/1.0/default/android.hardware.radio.config@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.radio-config-hal-1-0 /vendor/bin/hw/android.hardware.radio.config@1.0-service
+    interface android.hardware.radio.config@1.0::IRadioConfig default
     class hal
     user system
     group system
diff --git a/radio/config/1.0/vts/functional/Android.bp b/radio/config/1.0/vts/functional/Android.bp
index 9c96030..859b24b 100644
--- a/radio/config/1.0/vts/functional/Android.bp
+++ b/radio/config/1.0/vts/functional/Android.bp
@@ -29,5 +29,5 @@
         "android.hardware.radio.config@1.0",
     ],
     header_libs: ["radio.util.header@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/radio/config/1.0/vts/functional/VtsHalRadioConfigV1_0TargetTest.cpp b/radio/config/1.0/vts/functional/VtsHalRadioConfigV1_0TargetTest.cpp
index 2fc6b62..b3fae86 100644
--- a/radio/config/1.0/vts/functional/VtsHalRadioConfigV1_0TargetTest.cpp
+++ b/radio/config/1.0/vts/functional/VtsHalRadioConfigV1_0TargetTest.cpp
@@ -16,11 +16,7 @@
 
 #include <radio_config_hidl_hal_utils.h>
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(RadioConfigHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    RadioConfigHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioConfigHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IRadioConfig::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/radio/config/1.0/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.0/vts/functional/radio_config_hidl_hal_api.cpp
index 6782314..4ff560f 100644
--- a/radio/config/1.0/vts/functional/radio_config_hidl_hal_api.cpp
+++ b/radio/config/1.0/vts/functional/radio_config_hidl_hal_api.cpp
@@ -21,7 +21,7 @@
 /*
  * Test IRadioConfig.getSimSlotsStatus()
  */
-TEST_F(RadioConfigHidlTest, getSimSlotsStatus) {
+TEST_P(RadioConfigHidlTest, getSimSlotsStatus) {
     const int serial = GetRandomSerialNumber();
     Return<void> res = radioConfig->getSimSlotsStatus(serial);
     ASSERT_OK(res);
@@ -38,7 +38,7 @@
 /*
  * Test IRadioConfig.setSimSlotsMapping()
  */
-TEST_F(RadioConfigHidlTest, setSimSlotsMapping) {
+TEST_P(RadioConfigHidlTest, setSimSlotsMapping) {
     const int serial = GetRandomSerialNumber();
     android::hardware::hidl_vec<uint32_t> mapping = {0};
     Return<void> res = radioConfig->setSimSlotsMapping(serial, mapping);
diff --git a/radio/config/1.0/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.0/vts/functional/radio_config_hidl_hal_test.cpp
index c01dc4c..f589e2f 100644
--- a/radio/config/1.0/vts/functional/radio_config_hidl_hal_test.cpp
+++ b/radio/config/1.0/vts/functional/radio_config_hidl_hal_test.cpp
@@ -17,14 +17,10 @@
 #include <radio_config_hidl_hal_utils.h>
 
 void RadioConfigHidlTest::SetUp() {
-    radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<IRadioConfig>(
-        RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>(
-            hidl_string(RADIO_SERVICE_NAME)));
+    radioConfig = IRadioConfig::getService(GetParam());
     if (radioConfig == NULL) {
         sleep(60);
-        radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<IRadioConfig>(
-            RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>(
-                hidl_string(RADIO_SERVICE_NAME)));
+        radioConfig = IRadioConfig::getService(GetParam());
     }
     ASSERT_NE(nullptr, radioConfig.get());
 
diff --git a/radio/config/1.0/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.0/vts/functional/radio_config_hidl_hal_utils.h
index e7d697a..2722afe 100644
--- a/radio/config/1.0/vts/functional/radio_config_hidl_hal_utils.h
+++ b/radio/config/1.0/vts/functional/radio_config_hidl_hal_utils.h
@@ -16,8 +16,6 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -26,6 +24,10 @@
 #include <android/hardware/radio/config/1.0/IRadioConfigIndication.h>
 #include <android/hardware/radio/config/1.0/IRadioConfigResponse.h>
 #include <android/hardware/radio/config/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
 
 #include "vts_test_util.h"
 
@@ -76,22 +78,8 @@
         RadioIndicationType type, const ::android::hardware::hidl_vec<SimSlotStatus>& slotStatus);
 };
 
-// Test environment for Radio HIDL HAL.
-class RadioConfigHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static RadioConfigHidlEnvironment* Instance() {
-        static RadioConfigHidlEnvironment* instance = new RadioConfigHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override { registerTestService<IRadioConfig>(); }
-
-   private:
-    RadioConfigHidlEnvironment() {}
-};
-
 // The main test class for Radio config HIDL.
-class RadioConfigHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class RadioConfigHidlTest : public ::testing::TestWithParam<std::string> {
    protected:
     std::mutex mtx_;
     std::condition_variable cv_;
diff --git a/radio/config/1.1/Android.bp b/radio/config/1.1/Android.bp
index 5c9ad7c..1e9071a 100644
--- a/radio/config/1.1/Android.bp
+++ b/radio/config/1.1/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/config/1.1/vts/functional/Android.bp b/radio/config/1.1/vts/functional/Android.bp
index de909a3..8cf7b62 100644
--- a/radio/config/1.1/vts/functional/Android.bp
+++ b/radio/config/1.1/vts/functional/Android.bp
@@ -29,5 +29,5 @@
         "android.hardware.radio.config@1.1",
     ],
     header_libs: ["radio.util.header@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/radio/config/1.1/vts/functional/VtsHalRadioConfigV1_1TargetTest.cpp b/radio/config/1.1/vts/functional/VtsHalRadioConfigV1_1TargetTest.cpp
index 2fc6b62..b3fae86 100644
--- a/radio/config/1.1/vts/functional/VtsHalRadioConfigV1_1TargetTest.cpp
+++ b/radio/config/1.1/vts/functional/VtsHalRadioConfigV1_1TargetTest.cpp
@@ -16,11 +16,7 @@
 
 #include <radio_config_hidl_hal_utils.h>
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(RadioConfigHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    RadioConfigHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioConfigHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IRadioConfig::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp
index 5d0e867..49c7aad 100644
--- a/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp
+++ b/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp
@@ -21,7 +21,7 @@
 /*
  * Test IRadioConfig.getModemsConfig()
  */
-TEST_F(RadioConfigHidlTest, getModemsConfig) {
+TEST_P(RadioConfigHidlTest, getModemsConfig) {
     serial = GetRandomSerialNumber();
     Return<void> res = radioConfig->getModemsConfig(serial);
     ASSERT_OK(res);
@@ -37,7 +37,7 @@
 /*
  * Test IRadioConfig.setModemsConfig()
  */
-TEST_F(RadioConfigHidlTest, setModemsConfig_invalidArgument) {
+TEST_P(RadioConfigHidlTest, setModemsConfig_invalidArgument) {
     serial = GetRandomSerialNumber();
     ModemsConfig* mConfig = new ModemsConfig();
     Return<void> res = radioConfig->setModemsConfig(serial, *mConfig);
@@ -55,7 +55,7 @@
 /*
  * Test IRadioConfig.setModemsConfig()
  */
-TEST_F(RadioConfigHidlTest, setModemsConfig_goodRequest) {
+TEST_P(RadioConfigHidlTest, setModemsConfig_goodRequest) {
     serial = GetRandomSerialNumber();
     ModemsConfig* mConfig = new ModemsConfig();
     mConfig->numOfLiveModems = 1;
@@ -73,7 +73,7 @@
 /*
  * Test IRadioConfig.getPhoneCapability()
  */
-TEST_F(RadioConfigHidlTest, getPhoneCapability) {
+TEST_P(RadioConfigHidlTest, getPhoneCapability) {
     serial = GetRandomSerialNumber();
     Return<void> res = radioConfig->getPhoneCapability(serial);
     ASSERT_OK(res);
@@ -99,7 +99,7 @@
 /*
  * Test IRadioConfig.getPhoneCapability()
  */
-TEST_F(RadioConfigHidlTest, setPreferredDataModem) {
+TEST_P(RadioConfigHidlTest, setPreferredDataModem) {
     serial = GetRandomSerialNumber();
     Return<void> res = radioConfig->getPhoneCapability(serial);
     ASSERT_OK(res);
@@ -141,7 +141,7 @@
 /*
  * Test IRadioConfig.getPhoneCapability()
  */
-TEST_F(RadioConfigHidlTest, setPreferredDataModem_invalidArgument) {
+TEST_P(RadioConfigHidlTest, setPreferredDataModem_invalidArgument) {
     serial = GetRandomSerialNumber();
     uint8_t modemId = -1;
     Return<void> res = radioConfig->setPreferredDataModem(serial, modemId);
diff --git a/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp
index 39e6487..2e5e424 100644
--- a/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp
+++ b/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp
@@ -17,14 +17,10 @@
 #include <radio_config_hidl_hal_utils.h>
 
 void RadioConfigHidlTest::SetUp() {
-    radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<IRadioConfig>(
-        RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>(
-            hidl_string(RADIO_SERVICE_NAME)));
+    radioConfig = IRadioConfig::getService(GetParam());
     if (radioConfig == NULL) {
         sleep(60);
-        radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<IRadioConfig>(
-            RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>(
-                hidl_string(RADIO_SERVICE_NAME)));
+        radioConfig = IRadioConfig::getService(GetParam());
     }
     ASSERT_NE(nullptr, radioConfig.get());
 
diff --git a/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h
index c980901..4cdeb06 100644
--- a/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h
+++ b/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h
@@ -16,8 +16,6 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -25,6 +23,10 @@
 #include <android/hardware/radio/config/1.1/IRadioConfig.h>
 #include <android/hardware/radio/config/1.1/IRadioConfigResponse.h>
 #include <android/hardware/radio/config/1.1/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
 
 #include "vts_test_util.h"
 
@@ -73,22 +75,8 @@
     Return<void> setModemsConfigResponse(const RadioResponseInfo& info);
 };
 
-// Test environment for Radio HIDL HAL.
-class RadioConfigHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static RadioConfigHidlEnvironment* Instance() {
-        static RadioConfigHidlEnvironment* instance = new RadioConfigHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override { registerTestService<IRadioConfig>(); }
-
-   private:
-    RadioConfigHidlEnvironment() {}
-};
-
 // The main test class for Radio config HIDL.
-class RadioConfigHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class RadioConfigHidlTest : public ::testing::TestWithParam<std::string> {
    protected:
     std::mutex mtx_;
     std::condition_variable cv_;
diff --git a/radio/config/1.2/Android.bp b/radio/config/1.2/Android.bp
index e69be40..812f166 100644
--- a/radio/config/1.2/Android.bp
+++ b/radio/config/1.2/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/config/1.2/vts/functional/Android.bp b/radio/config/1.2/vts/functional/Android.bp
index 0cafc24..2c2073a 100644
--- a/radio/config/1.2/vts/functional/Android.bp
+++ b/radio/config/1.2/vts/functional/Android.bp
@@ -31,5 +31,5 @@
         "android.hardware.radio.config@1.2",
     ],
     header_libs: ["radio.util.header@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/radio/config/1.2/vts/functional/VtsHalRadioConfigV1_2TargetTest.cpp b/radio/config/1.2/vts/functional/VtsHalRadioConfigV1_2TargetTest.cpp
index ec6544e..f09ac3a 100644
--- a/radio/config/1.2/vts/functional/VtsHalRadioConfigV1_2TargetTest.cpp
+++ b/radio/config/1.2/vts/functional/VtsHalRadioConfigV1_2TargetTest.cpp
@@ -16,11 +16,7 @@
 
 #include <radio_config_hidl_hal_utils.h>
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(RadioConfigHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    RadioConfigHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioConfigHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IRadioConfig::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/radio/config/1.2/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.2/vts/functional/radio_config_hidl_hal_api.cpp
index a3729ac..2129ecd 100644
--- a/radio/config/1.2/vts/functional/radio_config_hidl_hal_api.cpp
+++ b/radio/config/1.2/vts/functional/radio_config_hidl_hal_api.cpp
@@ -21,7 +21,7 @@
 /*
  * Test IRadioConfig.getSimSlotsStatus()
  */
-TEST_F(RadioConfigHidlTest, getSimSlotsStatus) {
+TEST_P(RadioConfigHidlTest, getSimSlotsStatus) {
     const int serial = GetRandomSerialNumber();
     Return<void> res = radioConfig->getSimSlotsStatus(serial);
     ASSERT_OK(res);
diff --git a/radio/config/1.2/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.2/vts/functional/radio_config_hidl_hal_test.cpp
index cd7a172..fd344b0 100644
--- a/radio/config/1.2/vts/functional/radio_config_hidl_hal_test.cpp
+++ b/radio/config/1.2/vts/functional/radio_config_hidl_hal_test.cpp
@@ -17,14 +17,10 @@
 #include <radio_config_hidl_hal_utils.h>
 
 void RadioConfigHidlTest::SetUp() {
-    radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<IRadioConfig>(
-            RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>(
-                    hidl_string(RADIO_SERVICE_NAME)));
+    radioConfig = IRadioConfig::getService(GetParam());
     if (radioConfig == NULL) {
         sleep(60);
-        radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<IRadioConfig>(
-                RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>(
-                        hidl_string(RADIO_SERVICE_NAME)));
+        radioConfig = IRadioConfig::getService(GetParam());
     }
     ASSERT_NE(nullptr, radioConfig.get());
 
diff --git a/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h
index a876766..ba3f02e 100644
--- a/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h
+++ b/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h
@@ -16,8 +16,6 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -27,6 +25,10 @@
 #include <android/hardware/radio/config/1.2/IRadioConfigIndication.h>
 #include <android/hardware/radio/config/1.2/IRadioConfigResponse.h>
 #include <android/hardware/radio/config/1.2/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
 
 #include "vts_test_util.h"
 
@@ -97,22 +99,8 @@
             const ::android::hardware::hidl_vec<SimSlotStatus>& slotStatus);
 };
 
-// Test environment for Radio HIDL HAL.
-class RadioConfigHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-  public:
-    // get the test environment singleton
-    static RadioConfigHidlEnvironment* Instance() {
-        static RadioConfigHidlEnvironment* instance = new RadioConfigHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override { registerTestService<IRadioConfig>(); }
-
-  private:
-    RadioConfigHidlEnvironment() {}
-};
-
 // The main test class for Radio config HIDL.
-class RadioConfigHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class RadioConfigHidlTest : public ::testing::TestWithParam<std::string> {
   protected:
     std::mutex mtx_;
     std::condition_variable cv_;
diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp
new file mode 100644
index 0000000..88de666
--- /dev/null
+++ b/radio/config/1.3/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.radio.config@1.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IRadioConfig.hal",
+        "IRadioConfigIndication.hal",
+        "IRadioConfigResponse.hal",
+    ],
+    interfaces: [
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hardware.radio.config@1.2",
+        "android.hardware.radio@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal
new file mode 100644
index 0000000..a0ce6e0
--- /dev/null
+++ b/radio/config/1.3/IRadioConfig.hal
@@ -0,0 +1,31 @@
+/*
+ * 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.radio.config@1.3;
+
+import @1.1::IRadioConfig;
+
+/**
+ * This interface is used by telephony and telecom to talk to cellular radio for the purpose of
+ * radio configuration, and it is not associated with any specific modem or slot.
+ * All the functions have minimum one parameter:
+ * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
+ * duration of a method call. If clients provide colliding serials (including passing the same
+ * serial to different methods), multiple responses (one for each method call) must still be served.
+ */
+interface IRadioConfig extends @1.1::IRadioConfig {
+
+};
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/radio/config/1.3/IRadioConfigIndication.hal
similarity index 66%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to radio/config/1.3/IRadioConfigIndication.hal
index 8bb72a1..9ef496c 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/radio/config/1.3/IRadioConfigIndication.hal
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
+package android.hardware.radio.config@1.3;
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
+import @1.2::IRadioConfigIndication;
 
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
+/**
+ * Interface declaring unsolicited radio config indications.
+ */
+interface IRadioConfigIndication extends @1.2::IRadioConfigIndication {
 
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+};
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/radio/config/1.3/IRadioConfigResponse.hal
similarity index 66%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to radio/config/1.3/IRadioConfigResponse.hal
index 8bb72a1..9c4c971 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/radio/config/1.3/IRadioConfigResponse.hal
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
+package android.hardware.radio.config@1.3;
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
+import @1.2::IRadioConfigResponse;
 
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
+/**
+ * Interface declaring response functions to solicited radio config requests.
+ */
+interface IRadioConfigResponse extends @1.2::IRadioConfigResponse {
 
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+};
diff --git a/radio/config/1.3/default/Android.bp b/radio/config/1.3/default/Android.bp
new file mode 100644
index 0000000..163c5c5
--- /dev/null
+++ b/radio/config/1.3/default/Android.bp
@@ -0,0 +1,28 @@
+cc_binary {
+    name: "android.hardware.radio.config@1.3-service",
+    init_rc: ["android.hardware.radio.config@1.3-service.rc"],
+    relative_install_path: "hw",
+    vintf_fragments: ["radio-config-default.xml"],
+    vendor: true,
+    srcs: [
+        "RadioConfig.cpp",
+        "RadioConfigIndication.cpp",
+        "RadioConfigResponse.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hardware.radio.config@1.2",
+        "android.hardware.radio.config@1.3",
+        "android.hardware.radio@1.0",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.2",
+        "android.hardware.radio@1.3",
+        "android.hardware.radio@1.4",
+        "android.hardware.radio@1.5",
+    ],
+}
diff --git a/radio/config/1.3/default/RadioConfig.cpp b/radio/config/1.3/default/RadioConfig.cpp
new file mode 100644
index 0000000..c28119c
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfig.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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 "RadioConfig.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config;
+
+// Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow.
+Return<void> RadioConfig::setResponseFunctions(
+        const sp<V1_0::IRadioConfigResponse>& radioConfigResponse,
+        const sp<V1_0::IRadioConfigIndication>& radioConfigIndication) {
+    mRadioConfigResponse = radioConfigResponse;
+    mRadioConfigIndication = radioConfigIndication;
+
+    mRadioConfigResponseV1_3 =
+            V1_3::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    mRadioConfigIndicationV1_3 =
+            V1_3::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
+    if (mRadioConfigResponseV1_3 == nullptr || mRadioConfigIndicationV1_3 == nullptr) {
+        mRadioConfigResponseV1_3 = nullptr;
+        mRadioConfigIndicationV1_3 = nullptr;
+    }
+
+    mRadioConfigResponseV1_2 =
+            V1_2::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    mRadioConfigIndicationV1_2 =
+            V1_2::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
+    if (mRadioConfigResponseV1_2 == nullptr || mRadioConfigIndicationV1_2 == nullptr) {
+        mRadioConfigResponseV1_2 = nullptr;
+        mRadioConfigIndicationV1_2 = nullptr;
+    }
+
+    mRadioConfigResponseV1_1 =
+            V1_1::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    mRadioConfigIndicationV1_1 =
+            V1_1::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
+    if (mRadioConfigResponseV1_1 == nullptr || mRadioConfigIndicationV1_1 == nullptr) {
+        mRadioConfigResponseV1_1 = nullptr;
+        mRadioConfigIndicationV1_1 = nullptr;
+    }
+
+    return Void();
+}
+
+Return<void> RadioConfig::getSimSlotsStatus(int32_t /* serial */) {
+    hidl_vec<V1_0::SimSlotStatus> slotStatus;
+    RadioResponseInfo info;
+    mRadioConfigResponse->getSimSlotsStatusResponse(info, slotStatus);
+    return Void();
+}
+
+Return<void> RadioConfig::setSimSlotsMapping(int32_t /* serial */,
+                                             const hidl_vec<uint32_t>& /* slotMap */) {
+    RadioResponseInfo info;
+    mRadioConfigResponse->setSimSlotsMappingResponse(info);
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow.
+Return<void> RadioConfig::getPhoneCapability(int32_t /* serial */) {
+    V1_1::PhoneCapability phoneCapability;
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->getPhoneCapabilityResponse(info, phoneCapability);
+    return Void();
+}
+
+Return<void> RadioConfig::setPreferredDataModem(int32_t /* serial */, uint8_t /* modemId */) {
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->setPreferredDataModemResponse(info);
+    return Void();
+}
+
+Return<void> RadioConfig::setModemsConfig(int32_t /* serial */,
+                                          const V1_1::ModemsConfig& /* modemsConfig */) {
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->setModemsConfigResponse(info);
+    return Void();
+}
+
+Return<void> RadioConfig::getModemsConfig(int32_t /* serial */) {
+    V1_1::ModemsConfig modemsConfig;
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->getModemsConfigResponse(info, modemsConfig);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfig.h b/radio/config/1.3/default/RadioConfig.h
new file mode 100644
index 0000000..00585e6
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfig.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H
+#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H
+
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::config;
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct RadioConfig : public V1_3::IRadioConfig {
+    sp<V1_0::IRadioConfigResponse> mRadioConfigResponse;
+    sp<V1_0::IRadioConfigIndication> mRadioConfigIndication;
+    sp<V1_1::IRadioConfigResponse> mRadioConfigResponseV1_1;
+    sp<V1_1::IRadioConfigIndication> mRadioConfigIndicationV1_1;
+    sp<V1_2::IRadioConfigResponse> mRadioConfigResponseV1_2;
+    sp<V1_2::IRadioConfigIndication> mRadioConfigIndicationV1_2;
+    sp<V1_3::IRadioConfigResponse> mRadioConfigResponseV1_3;
+    sp<V1_3::IRadioConfigIndication> mRadioConfigIndicationV1_3;
+
+    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow.
+    Return<void> setResponseFunctions(
+            const sp<V1_0::IRadioConfigResponse>& radioConfigResponse,
+            const sp<V1_0::IRadioConfigIndication>& radioConfigIndication);
+    Return<void> getSimSlotsStatus(int32_t serial);
+    Return<void> setSimSlotsMapping(int32_t serial, const hidl_vec<uint32_t>& slotMap);
+
+    // Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow.
+    Return<void> getPhoneCapability(int32_t serial);
+    Return<void> setPreferredDataModem(int32_t serial, uint8_t modemId);
+    Return<void> setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig);
+    Return<void> getModemsConfig(int32_t serial);
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H
diff --git a/radio/config/1.3/default/RadioConfigIndication.cpp b/radio/config/1.3/default/RadioConfigIndication.cpp
new file mode 100644
index 0000000..eb77a48
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigIndication.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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 "RadioConfigIndication.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config::V1_0;
+using namespace ::android::hardware::radio::config::V1_2;
+
+// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow.
+Return<void> RadioConfigIndication::simSlotsStatusChanged(
+        RadioIndicationType /* type */, const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow.
+Return<void> RadioConfigIndication::simSlotsStatusChanged_1_2(
+        RadioIndicationType /* type */, const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfigIndication.h b/radio/config/1.3/default/RadioConfigIndication.h
new file mode 100644
index 0000000..3697492
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigIndication.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
+#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
+
+#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config;
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct RadioConfigIndication : public IRadioConfigIndication {
+    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow.
+    Return<void> simSlotsStatusChanged(RadioIndicationType type,
+                                       const hidl_vec<V1_0::SimSlotStatus>& slotStatus) override;
+
+    // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow.
+    Return<void> simSlotsStatusChanged_1_2(
+            RadioIndicationType type, const hidl_vec<V1_2::SimSlotStatus>& slotStatus) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
diff --git a/radio/config/1.3/default/RadioConfigResponse.cpp b/radio/config/1.3/default/RadioConfigResponse.cpp
new file mode 100644
index 0000000..48e81da
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigResponse.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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 "RadioConfigResponse.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config::V1_0;
+using namespace ::android::hardware::radio::config::V1_1;
+using namespace ::android::hardware::radio::config::V1_2;
+
+// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
+        const RadioResponseInfo& /* info */,
+        const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) {
+    // TODO implement
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
+        const RadioResponseInfo& /* info */, const V1_1::PhoneCapability& /* phoneCapability */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setPreferredDataModemResponse(
+        const RadioResponseInfo& /* info */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::getModemsConfigResponse(
+        const RadioResponseInfo& /* info */, const V1_1::ModemsConfig& /* modemsConfig */) {
+    // TODO implement
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
+        const RadioResponseInfo& /* info */,
+        const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfigResponse.h b/radio/config/1.3/default/RadioConfigResponse.h
new file mode 100644
index 0000000..0f0033f
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigResponse.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
+#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
+
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct RadioConfigResponse : public IRadioConfigResponse {
+    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
+    Return<void> getSimSlotsStatusResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus)
+            override;
+    Return<void> setSimSlotsMappingResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+
+    // Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow.
+    Return<void> getPhoneCapabilityResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::radio::config::V1_1::PhoneCapability& phoneCapability)
+            override;
+    Return<void> setPreferredDataModemResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+    Return<void> setModemsConfigResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+    Return<void> getModemsConfigResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::radio::config::V1_1::ModemsConfig& modemsConfig) override;
+
+    // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow.
+    Return<void> getSimSlotsStatusResponse_1_2(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::config::V1_2::SimSlotStatus>& slotStatus)
+            override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
diff --git a/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc b/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc
new file mode 100644
index 0000000..6df9b52
--- /dev/null
+++ b/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc
@@ -0,0 +1,7 @@
+service vendor.radio-config-hal-1-3 /vendor/bin/hw/android.hardware.radio.config@1.3-service
+    interface android.hardware.radio.config@1.0::IRadioConfig default
+    interface android.hardware.radio.config@1.1::IRadioConfig default
+    interface android.hardware.radio.config@1.3::IRadioConfig default
+    class hal
+    user system
+    group system
diff --git a/radio/config/1.3/default/radio-config-default.xml b/radio/config/1.3/default/radio-config-default.xml
new file mode 100644
index 0000000..72f363e
--- /dev/null
+++ b/radio/config/1.3/default/radio-config-default.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.radio.config</name>
+        <transport>hwbinder</transport>
+        <version>1.3</version>
+        <interface>
+            <name>IRadioConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/radio/config/1.3/default/service.cpp b/radio/config/1.3/default/service.cpp
new file mode 100644
index 0000000..b1e6736
--- /dev/null
+++ b/radio/config/1.3/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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.radio.config@1.3-service"
+
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "RadioConfig.h"
+
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::radio::config::V1_3::IRadioConfig;
+using android::hardware::radio::config::V1_3::implementation::RadioConfig;
+
+int main() {
+    configureRpcThreadpool(1, true);
+    sp<IRadioConfig> radioConfig = new RadioConfig;
+    const status_t status = radioConfig->registerAsService();
+    ALOGW_IF(status != OK, "Could not register IRadioConfig 1.3");
+    ALOGD("Default service is ready.");
+
+    joinRpcThreadpool();
+    return 1;
+}
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/radio/config/1.3/types.hal
similarity index 66%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to radio/config/1.3/types.hal
index 8bb72a1..866002a 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/radio/config/1.3/types.hal
@@ -14,13 +14,4 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
-
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
-
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
-
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+package android.hardware.radio.config@1.3;
diff --git a/radio/config/1.3/vts/functional/Android.bp b/radio/config/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..6b28faf
--- /dev/null
+++ b/radio/config/1.3/vts/functional/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_test {
+    name: "VtsHalRadioConfigV1_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "radio_config_hidl_hal_api.cpp",
+        "radio_config_hidl_hal_test.cpp",
+        "radio_config_response.cpp",
+        "VtsHalRadioConfigV1_3TargetTest.cpp",
+    ],
+    static_libs: [
+        "RadioVtsTestUtilBase",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hardware.radio.config@1.2",
+        "android.hardware.radio.config@1.3",
+    ],
+    header_libs: ["radio.util.header@1.0"],
+    test_suites: ["general-tests", "vts-core"],
+}
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
similarity index 65%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
index 8bb72a1..3bacacf 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
@@ -14,13 +14,10 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
+#include <radio_config_hidl_hal_utils.h>
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
-
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
-
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioConfigHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                ::android::hardware::radio::config::V1_3::IRadioConfig::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
similarity index 66%
rename from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
rename to radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
index 8bb72a1..07e9ede 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
@@ -14,13 +14,6 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
+#include <radio_config_hidl_hal_utils.h>
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
-
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
-
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
new file mode 100644
index 0000000..dbb4bf4
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 <radio_config_hidl_hal_utils.h>
+
+void RadioConfigHidlTest::SetUp() {
+    radioConfig = ::android::hardware::radio::config::V1_3::IRadioConfig::getService(GetParam());
+    ASSERT_NE(nullptr, radioConfig.get());
+
+    radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
+    ASSERT_NE(nullptr, radioConfigRsp.get());
+
+    count_ = 0;
+
+    radioConfig->setResponseFunctions(radioConfigRsp, nullptr);
+}
+
+/*
+ * Notify that the response message is received.
+ */
+void RadioConfigHidlTest::notify(int receivedSerial) {
+    std::unique_lock<std::mutex> lock(mtx_);
+    if (serial == receivedSerial) {
+        count_++;
+        cv_.notify_one();
+    }
+}
+
+/*
+ * Wait till the response message is notified or till TIMEOUT_PERIOD.
+ */
+std::cv_status RadioConfigHidlTest::wait() {
+    std::unique_lock<std::mutex> lock(mtx_);
+
+    std::cv_status status = std::cv_status::no_timeout;
+    auto now = std::chrono::system_clock::now();
+    while (count_ == 0) {
+        status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) {
+            return status;
+        }
+    }
+    count_--;
+    return status;
+}
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
new file mode 100644
index 0000000..9b78c04
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
@@ -0,0 +1,128 @@
+/*
+ * 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 <android-base/logging.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <android/hardware/radio/config/1.3/types.h>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "vts_test_util.h"
+
+using namespace ::android::hardware::radio::config::V1_1;
+using namespace ::android::hardware::radio::config::V1_2;
+using namespace ::android::hardware::radio::config::V1_3;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
+using ::android::hardware::radio::V1_0::RadioResponseType;
+
+#define TIMEOUT_PERIOD 75
+
+class RadioConfigHidlTest;
+
+/* Callback class for radio config response */
+class RadioConfigResponse : public ::android::hardware::radio::config::V1_3::IRadioConfigResponse {
+  protected:
+    RadioConfigHidlTest& parent;
+
+  public:
+    RadioResponseInfo rspInfo;
+    PhoneCapability phoneCap;
+
+    RadioConfigResponse(RadioConfigHidlTest& parent);
+    virtual ~RadioConfigResponse() = default;
+
+    /* 1.0 Api */
+    Return<void> getSimSlotsStatusResponse(
+            const RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus);
+
+    Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info);
+
+    /* 1.1 Api */
+    Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
+                                            const PhoneCapability& phoneCapability);
+
+    Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info);
+
+    Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
+                                         const ModemsConfig& mConfig);
+
+    Return<void> setModemsConfigResponse(const RadioResponseInfo& info);
+
+    /* 1.2 Api */
+    Return<void> getSimSlotsStatusResponse_1_2(const RadioResponseInfo& info,
+                                               const hidl_vec<SimSlotStatus>& slotStatus);
+};
+
+/* Callback class for radio config indication */
+class RadioConfigIndication
+    : public ::android::hardware::radio::config::V1_3::IRadioConfigIndication {
+  protected:
+    RadioConfigHidlTest& parent;
+
+  public:
+    RadioConfigIndication(RadioConfigHidlTest& parent);
+    virtual ~RadioConfigIndication() = default;
+
+    /* 1.2 Api */
+    Return<void> simSlotsStatusChanged_1_2(
+            ::android::hardware::radio::V1_0::RadioIndicationType type,
+            const hidl_vec<SimSlotStatus>& slotStatus);
+};
+
+// The main test class for Radio config HIDL.
+class RadioConfigHidlTest : public ::testing::TestWithParam<std::string> {
+  protected:
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int count_;
+
+  public:
+    virtual void SetUp() override;
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    void notify(int receivedSerial);
+
+    /* Test code calls this function to wait for response */
+    std::cv_status wait();
+
+    void updateSimCardStatus();
+
+    /* Serial number for radio request */
+    int serial;
+
+    /* radio config service handle */
+    sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig;
+
+    /* radio config response handle */
+    sp<RadioConfigResponse> radioConfigRsp;
+};
diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp
new file mode 100644
index 0000000..1ca960e
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_response.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 <radio_config_hidl_hal_utils.h>
+
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
+
+// SimSlotStatus slotStatus;
+
+RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {}
+
+/* 1.0 Apis */
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
+        const RadioResponseInfo& /* info */,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
+        const RadioResponseInfo& info, const PhoneCapability& phoneCapability) {
+    rspInfo = info;
+    phoneCap = phoneCapability;
+    parent.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setPreferredDataModemResponse(
+        const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */,
+                                                          const ModemsConfig& /* mConfig */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
+        const RadioResponseInfo& /* info */,
+        const ::android::hardware::hidl_vec<SimSlotStatus>& /* slotStatus */) {
+    return Void();
+}
\ No newline at end of file
diff --git a/radio/deprecated/1.0/Android.bp b/radio/deprecated/1.0/Android.bp
index c9f86f0..cb13b86 100644
--- a/radio/deprecated/1.0/Android.bp
+++ b/radio/deprecated/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/renderscript/1.0/Android.bp b/renderscript/1.0/Android.bp
index 1d7efad..feae9f7 100644
--- a/renderscript/1.0/Android.bp
+++ b/renderscript/1.0/Android.bp
@@ -18,4 +18,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/renderscript/1.0/default/Android.bp b/renderscript/1.0/default/Android.bp
index d5d6d8d..4fa85c6 100644
--- a/renderscript/1.0/default/Android.bp
+++ b/renderscript/1.0/default/Android.bp
@@ -14,7 +14,6 @@
         "libdl",
         "libbase",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.renderscript@1.0",
     ],
diff --git a/renderscript/1.0/default/Device.cpp b/renderscript/1.0/default/Device.cpp
index d603a12..9a6d7ba 100644
--- a/renderscript/1.0/default/Device.cpp
+++ b/renderscript/1.0/default/Device.cpp
@@ -86,150 +86,116 @@
     }
 
     dispatchTable dispatchHal = {
-        .SetNativeLibDir = (SetNativeLibDirFnPtr) nullptr,
+            .SetNativeLibDir = (SetNativeLibDirFnPtr) nullptr,
 
-        .Allocation1DData =
-            (Allocation1DDataFnPtr)dlsym(handle, "rsAllocation1DData"),
-        .Allocation1DElementData = (Allocation1DElementDataFnPtr) nullptr,
-        .Allocation1DRead =
-            (Allocation1DReadFnPtr)dlsym(handle, "rsAllocation1DRead"),
-        .Allocation2DData =
-            (Allocation2DDataFnPtr)dlsym(handle, "rsAllocation2DData"),
-        .Allocation2DRead =
-            (Allocation2DReadFnPtr)dlsym(handle, "rsAllocation2DRead"),
-        .Allocation3DData =
-            (Allocation3DDataFnPtr)dlsym(handle, "rsAllocation3DData"),
-        .Allocation3DRead =
-            (Allocation3DReadFnPtr)dlsym(handle, "rsAllocation3DRead"),
-        .AllocationAdapterCreate = (AllocationAdapterCreateFnPtr)dlsym(
-            handle, "rsAllocationAdapterCreate"),
-        .AllocationAdapterOffset = (AllocationAdapterOffsetFnPtr)dlsym(
-            handle, "rsAllocationAdapterOffset"),
-        .AllocationCopy2DRange = (AllocationCopy2DRangeFnPtr)dlsym(
-            handle, "rsAllocationCopy2DRange"),
-        .AllocationCopy3DRange = (AllocationCopy3DRangeFnPtr)dlsym(
-            handle, "rsAllocationCopy3DRange"),
-        .AllocationCopyToBitmap = (AllocationCopyToBitmapFnPtr)dlsym(
-            handle, "rsAllocationCopyToBitmap"),
-        .AllocationCreateFromBitmap = (AllocationCreateFromBitmapFnPtr)dlsym(
-            handle, "rsAllocationCreateFromBitmap"),
-        .AllocationCreateStrided = (AllocationCreateStridedFnPtr)dlsym(
-            handle, "rsAllocationCreateStrided"),
-        .AllocationCreateTyped = (AllocationCreateTypedFnPtr)dlsym(
-            handle, "rsAllocationCreateTyped"),
-        .AllocationCubeCreateFromBitmap =
-            (AllocationCubeCreateFromBitmapFnPtr)dlsym(
-                handle, "rsAllocationCubeCreateFromBitmap"),
-        .AllocationElementData = (AllocationElementDataFnPtr)dlsym(
-            handle, "rsAllocationElementData"),
-        .AllocationElementRead = (AllocationElementReadFnPtr)dlsym(
-            handle, "rsAllocationElementRead"),
-        .AllocationGenerateMipmaps = (AllocationGenerateMipmapsFnPtr)dlsym(
-            handle, "rsAllocationGenerateMipmaps"),
-        .AllocationGetPointer =
-            (AllocationGetPointerFnPtr)dlsym(handle, "rsAllocationGetPointer"),
-        .AllocationGetSurface =
-            (AllocationGetSurfaceFnPtr)dlsym(handle, "rsAllocationGetSurface"),
-        .AllocationGetType =
-            (AllocationGetTypeFnPtr)dlsym(handle, "rsaAllocationGetType"),
-        .AllocationIoReceive =
-            (AllocationIoReceiveFnPtr)dlsym(handle, "rsAllocationIoReceive"),
-        .AllocationIoSend =
-            (AllocationIoSendFnPtr)dlsym(handle, "rsAllocationIoSend"),
-        .AllocationRead =
-            (AllocationReadFnPtr)dlsym(handle, "rsAllocationRead"),
-        .AllocationResize1D =
-            (AllocationResize1DFnPtr)dlsym(handle, "rsAllocationResize1D"),
-        .AllocationSetSurface =
-            (AllocationSetSurfaceFnPtr)dlsym(handle, "rsAllocationSetSurface"),
-        .AllocationSetupBufferQueue = (AllocationSetupBufferQueueFnPtr)dlsym(
-            handle, "rsAllocationSetupBufferQueue"),
-        .AllocationShareBufferQueue = (AllocationShareBufferQueueFnPtr)dlsym(
-            handle, "rsAllocationShareBufferQueue"),
-        .AllocationSyncAll =
-            (AllocationSyncAllFnPtr)dlsym(handle, "rsAllocationSyncAll"),
-        .AssignName = (AssignNameFnPtr)dlsym(handle, "rsAssignName"),
-        .ClosureCreate = (ClosureCreateFnPtr)dlsym(handle, "rsClosureCreate"),
-        .ClosureSetArg = (ClosureSetArgFnPtr)dlsym(handle, "rsClosureSetArg"),
-        .ClosureSetGlobal =
-            (ClosureSetGlobalFnPtr)dlsym(handle, "rsClosureSetGlobal"),
-        .ContextCreateVendor =
-            (ContextCreateVendorFnPtr)dlsym(handle, "rsContextCreateVendor"),
-        .ContextDeinitToClient = (ContextDeinitToClientFnPtr)dlsym(
-            handle, "rsContextDeinitToClient"),
-        .ContextDestroy =
-            (ContextDestroyFnPtr)dlsym(handle, "rsContextDestroy"),
-        .ContextDump = (ContextDumpFnPtr)dlsym(handle, "rsContextDump"),
-        .ContextFinish = (ContextFinishFnPtr)dlsym(handle, "rsContextFinish"),
-        .ContextGetMessage =
-            (ContextGetMessageFnPtr)dlsym(handle, "rsContextGetMessage"),
-        .ContextInitToClient =
-            (ContextInitToClientFnPtr)dlsym(handle, "rsContextInitToClient"),
-        .ContextPeekMessage =
-            (ContextPeekMessageFnPtr)dlsym(handle, "rsContextPeekMessage"),
-        .ContextSendMessage =
-            (ContextSendMessageFnPtr)dlsym(handle, "rsContextSendMessage"),
-        .ContextSetCacheDir =
-            (ContextSetCacheDirFnPtr)dlsym(handle, "rsContextSetCacheDir"),
-        .ContextSetPriority =
-            (ContextSetPriorityFnPtr)dlsym(handle, "rsContextSetPriority"),
-        .DeviceCreate = (DeviceCreateFnPtr) nullptr,
-        .DeviceDestroy = (DeviceDestroyFnPtr) nullptr,
-        .DeviceSetConfig = (DeviceSetConfigFnPtr) nullptr,
-        .ElementCreate2 =
-            (ElementCreate2FnPtr)dlsym(handle, "rsElementCreate2"),
-        .ElementCreate = (ElementCreateFnPtr)dlsym(handle, "rsElementCreate"),
-        .ElementGetNativeData =
-            (ElementGetNativeDataFnPtr)dlsym(handle, "rsaElementGetNativeData"),
-        .ElementGetSubElements = (ElementGetSubElementsFnPtr)dlsym(
-            handle, "rsaElementGetSubElements"),
-        .GetName = (GetNameFnPtr)dlsym(handle, "rsaGetName"),
-        .InvokeClosureCreate =
-            (InvokeClosureCreateFnPtr)dlsym(handle, "rsInvokeClosureCreate"),
-        .ObjDestroy = (ObjDestroyFnPtr)dlsym(handle, "rsObjDestroy"),
-        .SamplerCreate = (SamplerCreateFnPtr)dlsym(handle, "rsSamplerCreate"),
-        .ScriptBindAllocation =
-            (ScriptBindAllocationFnPtr)dlsym(handle, "rsScriptBindAllocation"),
-        .ScriptCCreate = (ScriptCCreateFnPtr)dlsym(handle, "rsScriptCCreate"),
-        .ScriptFieldIDCreate =
-            (ScriptFieldIDCreateFnPtr)dlsym(handle, "rsScriptFieldIDCreate"),
-        .ScriptForEach = (ScriptForEachFnPtr) nullptr,
-        .ScriptForEachMulti =
-            (ScriptForEachMultiFnPtr)dlsym(handle, "rsScriptForEachMulti"),
-        .ScriptGetVarV = (ScriptGetVarVFnPtr)dlsym(handle, "rsScriptGetVarV"),
-        .ScriptGroup2Create =
-            (ScriptGroup2CreateFnPtr)dlsym(handle, "rsScriptGroup2Create"),
-        .ScriptGroupCreate =
-            (ScriptGroupCreateFnPtr)dlsym(handle, "rsScriptGroupCreate"),
-        .ScriptGroupExecute =
-            (ScriptGroupExecuteFnPtr)dlsym(handle, "rsScriptGroupExecute"),
-        .ScriptGroupSetInput =
-            (ScriptGroupSetInputFnPtr)dlsym(handle, "rsScriptGroupSetInput"),
-        .ScriptGroupSetOutput =
-            (ScriptGroupSetOutputFnPtr)dlsym(handle, "rsScriptGroupSetOutput"),
-        .ScriptIntrinsicCreate = (ScriptIntrinsicCreateFnPtr)dlsym(
-            handle, "rsScriptIntrinsicCreate"),
-        .ScriptInvoke = (ScriptInvokeFnPtr)dlsym(handle, "rsScriptInvoke"),
-        .ScriptInvokeIDCreate =
-            (ScriptInvokeIDCreateFnPtr)dlsym(handle, "rsScriptInvokeIDCreate"),
-        .ScriptInvokeV = (ScriptInvokeVFnPtr)dlsym(handle, "rsScriptInvokeV"),
-        .ScriptKernelIDCreate =
-            (ScriptKernelIDCreateFnPtr)dlsym(handle, "rsScriptKernelIDCreate"),
-        .ScriptReduce = (ScriptReduceFnPtr)dlsym(handle, "rsScriptReduce"),
-        .ScriptSetTimeZone =
-            (ScriptSetTimeZoneFnPtr)dlsym(handle, "rsScriptSetTimeZone"),
-        .ScriptSetVarD = (ScriptSetVarDFnPtr)dlsym(handle, "rsScriptSetVarD"),
-        .ScriptSetVarF = (ScriptSetVarFFnPtr)dlsym(handle, "rsScriptSetVarF"),
-        .ScriptSetVarI = (ScriptSetVarIFnPtr)dlsym(handle, "rsScriptSetVarI"),
-        .ScriptSetVarJ = (ScriptSetVarJFnPtr)dlsym(handle, "rsScriptSetVarJ"),
-        .ScriptSetVarObj =
-            (ScriptSetVarObjFnPtr)dlsym(handle, "rsScriptSetVarObj"),
-        .ScriptSetVarVE =
-            (ScriptSetVarVEFnPtr)dlsym(handle, "rsScriptSetVarVE"),
-        .ScriptSetVarV = (ScriptSetVarVFnPtr)dlsym(handle, "rsScriptSetVarV"),
-        .TypeCreate = (TypeCreateFnPtr)dlsym(handle, "rsTypeCreate"),
-        .TypeGetNativeData =
-            (TypeGetNativeDataFnPtr)dlsym(handle, "rsaTypeGetNativeData"),
+            .Allocation1DData = (Allocation1DDataFnPtr)dlsym(handle, "rsAllocation1DData"),
+            .Allocation1DElementData = (Allocation1DElementDataFnPtr) nullptr,
+            .Allocation1DRead = (Allocation1DReadFnPtr)dlsym(handle, "rsAllocation1DRead"),
+            .Allocation2DData = (Allocation2DDataFnPtr)dlsym(handle, "rsAllocation2DData"),
+            .Allocation2DRead = (Allocation2DReadFnPtr)dlsym(handle, "rsAllocation2DRead"),
+            .Allocation3DData = (Allocation3DDataFnPtr)dlsym(handle, "rsAllocation3DData"),
+            .Allocation3DRead = (Allocation3DReadFnPtr)dlsym(handle, "rsAllocation3DRead"),
+            .AllocationAdapterCreate =
+                    (AllocationAdapterCreateFnPtr)dlsym(handle, "rsAllocationAdapterCreate"),
+            .AllocationAdapterOffset =
+                    (AllocationAdapterOffsetFnPtr)dlsym(handle, "rsAllocationAdapterOffset"),
+            .AllocationCopy2DRange =
+                    (AllocationCopy2DRangeFnPtr)dlsym(handle, "rsAllocationCopy2DRange"),
+            .AllocationCopy3DRange =
+                    (AllocationCopy3DRangeFnPtr)dlsym(handle, "rsAllocationCopy3DRange"),
+            .AllocationCopyToBitmap =
+                    (AllocationCopyToBitmapFnPtr)dlsym(handle, "rsAllocationCopyToBitmap"),
+            .AllocationCreateFromBitmap =
+                    (AllocationCreateFromBitmapFnPtr)dlsym(handle, "rsAllocationCreateFromBitmap"),
+            .AllocationCreateStrided =
+                    (AllocationCreateStridedFnPtr)dlsym(handle, "rsAllocationCreateStrided"),
+            .AllocationCreateTyped =
+                    (AllocationCreateTypedFnPtr)dlsym(handle, "rsAllocationCreateTyped"),
+            .AllocationCubeCreateFromBitmap = (AllocationCubeCreateFromBitmapFnPtr)dlsym(
+                    handle, "rsAllocationCubeCreateFromBitmap"),
+            .AllocationElementData =
+                    (AllocationElementDataFnPtr)dlsym(handle, "rsAllocationElementData"),
+            .AllocationElementRead =
+                    (AllocationElementReadFnPtr)dlsym(handle, "rsAllocationElementRead"),
+            .AllocationGenerateMipmaps =
+                    (AllocationGenerateMipmapsFnPtr)dlsym(handle, "rsAllocationGenerateMipmaps"),
+            .AllocationGetPointer =
+                    (AllocationGetPointerFnPtr)dlsym(handle, "rsAllocationGetPointer"),
+            .AllocationGetSurface =
+                    (AllocationGetSurfaceFnPtr)dlsym(handle, "rsAllocationGetSurface"),
+            .AllocationGetType = (AllocationGetTypeFnPtr)dlsym(handle, "rsaAllocationGetType"),
+            .AllocationIoReceive = (AllocationIoReceiveFnPtr)dlsym(handle, "rsAllocationIoReceive"),
+            .AllocationIoSend = (AllocationIoSendFnPtr)dlsym(handle, "rsAllocationIoSend"),
+            .AllocationRead = (AllocationReadFnPtr)dlsym(handle, "rsAllocationRead"),
+            .AllocationResize1D = (AllocationResize1DFnPtr)dlsym(handle, "rsAllocationResize1D"),
+            .AllocationSetSurface =
+                    (AllocationSetSurfaceFnPtr)dlsym(handle, "rsAllocationSetSurface"),
+            .AllocationSyncAll = (AllocationSyncAllFnPtr)dlsym(handle, "rsAllocationSyncAll"),
+            .AllocationSetupBufferQueue =
+                    (AllocationSetupBufferQueueFnPtr)dlsym(handle, "rsAllocationSetupBufferQueue"),
+            .AllocationShareBufferQueue =
+                    (AllocationShareBufferQueueFnPtr)dlsym(handle, "rsAllocationShareBufferQueue"),
+            .AssignName = (AssignNameFnPtr)dlsym(handle, "rsAssignName"),
+            .ClosureCreate = (ClosureCreateFnPtr)dlsym(handle, "rsClosureCreate"),
+            .ClosureSetArg = (ClosureSetArgFnPtr)dlsym(handle, "rsClosureSetArg"),
+            .ClosureSetGlobal = (ClosureSetGlobalFnPtr)dlsym(handle, "rsClosureSetGlobal"),
+            .ContextCreateVendor = (ContextCreateVendorFnPtr)dlsym(handle, "rsContextCreateVendor"),
+            .ContextDeinitToClient =
+                    (ContextDeinitToClientFnPtr)dlsym(handle, "rsContextDeinitToClient"),
+            .ContextDestroy = (ContextDestroyFnPtr)dlsym(handle, "rsContextDestroy"),
+            .ContextDump = (ContextDumpFnPtr)dlsym(handle, "rsContextDump"),
+            .ContextFinish = (ContextFinishFnPtr)dlsym(handle, "rsContextFinish"),
+            .ContextGetMessage = (ContextGetMessageFnPtr)dlsym(handle, "rsContextGetMessage"),
+            .ContextInitToClient = (ContextInitToClientFnPtr)dlsym(handle, "rsContextInitToClient"),
+            .ContextPeekMessage = (ContextPeekMessageFnPtr)dlsym(handle, "rsContextPeekMessage"),
+            .ContextSendMessage = (ContextSendMessageFnPtr)dlsym(handle, "rsContextSendMessage"),
+            .ContextSetPriority = (ContextSetPriorityFnPtr)dlsym(handle, "rsContextSetPriority"),
+            .ContextSetCacheDir = (ContextSetCacheDirFnPtr)dlsym(handle, "rsContextSetCacheDir"),
+            .DeviceCreate = (DeviceCreateFnPtr) nullptr,
+            .DeviceDestroy = (DeviceDestroyFnPtr) nullptr,
+            .DeviceSetConfig = (DeviceSetConfigFnPtr) nullptr,
+            .ElementCreate2 = (ElementCreate2FnPtr)dlsym(handle, "rsElementCreate2"),
+            .ElementCreate = (ElementCreateFnPtr)dlsym(handle, "rsElementCreate"),
+            .ElementGetNativeData =
+                    (ElementGetNativeDataFnPtr)dlsym(handle, "rsaElementGetNativeData"),
+            .ElementGetSubElements =
+                    (ElementGetSubElementsFnPtr)dlsym(handle, "rsaElementGetSubElements"),
+            .GetName = (GetNameFnPtr)dlsym(handle, "rsaGetName"),
+            .InvokeClosureCreate = (InvokeClosureCreateFnPtr)dlsym(handle, "rsInvokeClosureCreate"),
+            .ObjDestroy = (ObjDestroyFnPtr)dlsym(handle, "rsObjDestroy"),
+            .SamplerCreate = (SamplerCreateFnPtr)dlsym(handle, "rsSamplerCreate"),
+            .ScriptBindAllocation =
+                    (ScriptBindAllocationFnPtr)dlsym(handle, "rsScriptBindAllocation"),
+            .ScriptCCreate = (ScriptCCreateFnPtr)dlsym(handle, "rsScriptCCreate"),
+            .ScriptFieldIDCreate = (ScriptFieldIDCreateFnPtr)dlsym(handle, "rsScriptFieldIDCreate"),
+            .ScriptForEach = (ScriptForEachFnPtr) nullptr,
+            .ScriptForEachMulti = (ScriptForEachMultiFnPtr)dlsym(handle, "rsScriptForEachMulti"),
+            .ScriptGetVarV = (ScriptGetVarVFnPtr)dlsym(handle, "rsScriptGetVarV"),
+            .ScriptGroup2Create = (ScriptGroup2CreateFnPtr)dlsym(handle, "rsScriptGroup2Create"),
+            .ScriptGroupCreate = (ScriptGroupCreateFnPtr)dlsym(handle, "rsScriptGroupCreate"),
+            .ScriptGroupExecute = (ScriptGroupExecuteFnPtr)dlsym(handle, "rsScriptGroupExecute"),
+            .ScriptGroupSetInput = (ScriptGroupSetInputFnPtr)dlsym(handle, "rsScriptGroupSetInput"),
+            .ScriptGroupSetOutput =
+                    (ScriptGroupSetOutputFnPtr)dlsym(handle, "rsScriptGroupSetOutput"),
+            .ScriptIntrinsicCreate =
+                    (ScriptIntrinsicCreateFnPtr)dlsym(handle, "rsScriptIntrinsicCreate"),
+            .ScriptInvoke = (ScriptInvokeFnPtr)dlsym(handle, "rsScriptInvoke"),
+            .ScriptInvokeIDCreate =
+                    (ScriptInvokeIDCreateFnPtr)dlsym(handle, "rsScriptInvokeIDCreate"),
+            .ScriptInvokeV = (ScriptInvokeVFnPtr)dlsym(handle, "rsScriptInvokeV"),
+            .ScriptKernelIDCreate =
+                    (ScriptKernelIDCreateFnPtr)dlsym(handle, "rsScriptKernelIDCreate"),
+            .ScriptReduce = (ScriptReduceFnPtr)dlsym(handle, "rsScriptReduce"),
+            .ScriptSetTimeZone = (ScriptSetTimeZoneFnPtr)dlsym(handle, "rsScriptSetTimeZone"),
+            .ScriptSetVarD = (ScriptSetVarDFnPtr)dlsym(handle, "rsScriptSetVarD"),
+            .ScriptSetVarF = (ScriptSetVarFFnPtr)dlsym(handle, "rsScriptSetVarF"),
+            .ScriptSetVarI = (ScriptSetVarIFnPtr)dlsym(handle, "rsScriptSetVarI"),
+            .ScriptSetVarJ = (ScriptSetVarJFnPtr)dlsym(handle, "rsScriptSetVarJ"),
+            .ScriptSetVarObj = (ScriptSetVarObjFnPtr)dlsym(handle, "rsScriptSetVarObj"),
+            .ScriptSetVarVE = (ScriptSetVarVEFnPtr)dlsym(handle, "rsScriptSetVarVE"),
+            .ScriptSetVarV = (ScriptSetVarVFnPtr)dlsym(handle, "rsScriptSetVarV"),
+            .TypeCreate = (TypeCreateFnPtr)dlsym(handle, "rsTypeCreate"),
+            .TypeGetNativeData = (TypeGetNativeDataFnPtr)dlsym(handle, "rsaTypeGetNativeData"),
     };
 
     return dispatchHal;
diff --git a/secure_element/1.0/Android.bp b/secure_element/1.0/Android.bp
index c6fa6a9..32b752b 100644
--- a/secure_element/1.0/Android.bp
+++ b/secure_element/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/secure_element/1.0/vts/functional/Android.bp b/secure_element/1.0/vts/functional/Android.bp
index 2b2b73e..6dbd027 100644
--- a/secure_element/1.0/vts/functional/Android.bp
+++ b/secure_element/1.0/vts/functional/Android.bp
@@ -21,5 +21,5 @@
     static_libs: [
         "android.hardware.secure_element@1.0",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
index 671923a..93ffd05 100644
--- a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
+++ b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
@@ -20,10 +20,11 @@
 #include <android/hardware/secure_element/1.0/ISecureElement.h>
 #include <android/hardware/secure_element/1.0/ISecureElementHalCallback.h>
 #include <android/hardware/secure_element/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 
 using ::android::hardware::secure_element::V1_0::ISecureElement;
 using ::android::hardware::secure_element::V1_0::ISecureElementHalCallback;
@@ -32,7 +33,6 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::sp;
-using ::testing::VtsHalHidlTargetTestEnvBase;
 
 #define DATA_APDU \
     { 0x00, 0x08, 0x00, 0x00, 0x00 }
@@ -63,30 +63,11 @@
     };
 };
 
-class SecureElementHidlEnvironment : public VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static SecureElementHidlEnvironment* Instance() {
-        static SecureElementHidlEnvironment* instance = new SecureElementHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<ISecureElement>(); }
-
-   private:
-    SecureElementHidlEnvironment() {}
-
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(SecureElementHidlEnvironment);
-};
-
-class SecureElementHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
+class SecureElementHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override {
-        std::string serviceName =
-            SecureElementHidlEnvironment::Instance()->getServiceName<ISecureElement>("eSE1");
-        LOG(INFO) << "get service with name:" << serviceName;
-        ASSERT_FALSE(serviceName.empty());
-        se_ = ::testing::VtsHalHidlTargetTestBase::getService<ISecureElement>(serviceName);
+        LOG(INFO) << "get service with name:" << GetParam();
+        se_ = ISecureElement::getService(GetParam());
         ASSERT_NE(se_, nullptr);
 
         se_cb_ = new SecureElementHalCallback();
@@ -105,7 +86,7 @@
  * isCardPresent:
  * Expects the card to be present
  */
-TEST_F(SecureElementHidlTest, isCardPresent) {
+TEST_P(SecureElementHidlTest, isCardPresent) {
     EXPECT_TRUE(se_->isCardPresent());
 }
 
@@ -113,7 +94,7 @@
  * transmit:
  * Check status word in the response
  */
-TEST_F(SecureElementHidlTest, transmit) {
+TEST_P(SecureElementHidlTest, transmit) {
     std::vector<uint8_t> aid = ANDROID_TEST_AID;
     SecureElementStatus statusReturned;
     LogicalChannelResponse response;
@@ -153,7 +134,7 @@
  * If the secure element allows opening of basic channel:
  *  open channel, check the length of selectResponse and close the channel
  */
-TEST_F(SecureElementHidlTest, openBasicChannel) {
+TEST_P(SecureElementHidlTest, openBasicChannel) {
     std::vector<uint8_t> aid = ANDROID_TEST_AID;
     SecureElementStatus statusReturned;
     std::vector<uint8_t> response;
@@ -179,7 +160,7 @@
 /*
  * GetATR
  */
-TEST_F(SecureElementHidlTest, getAtr) {
+TEST_P(SecureElementHidlTest, getAtr) {
     std::vector<uint8_t> atr;
     se_->getAtr([&atr](std::vector<uint8_t> atrReturned) {
         atr.resize(atrReturned.size());
@@ -200,7 +181,7 @@
  * Check status
  * Close Channel
  */
-TEST_F(SecureElementHidlTest, openCloseLogicalChannel) {
+TEST_P(SecureElementHidlTest, openCloseLogicalChannel) {
     std::vector<uint8_t> aid = ANDROID_TEST_AID;
     SecureElementStatus statusReturned;
     LogicalChannelResponse response;
@@ -223,10 +204,7 @@
     EXPECT_EQ(SecureElementStatus::SUCCESS, se_->closeChannel(response.channelNumber));
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(SecureElementHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    SecureElementHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, SecureElementHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISecureElement::descriptor)),
+        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/secure_element/1.1/Android.bp b/secure_element/1.1/Android.bp
index e16bc3d..3ea2de9 100644
--- a/secure_element/1.1/Android.bp
+++ b/secure_element/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/secure_element/1.1/vts/functional/Android.bp b/secure_element/1.1/vts/functional/Android.bp
index 51410bd..a2c39dc 100644
--- a/secure_element/1.1/vts/functional/Android.bp
+++ b/secure_element/1.1/vts/functional/Android.bp
@@ -22,5 +22,5 @@
         "android.hardware.secure_element@1.0",
         "android.hardware.secure_element@1.1",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp b/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp
index f8765ca..66fc47c 100644
--- a/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp
+++ b/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp
@@ -22,10 +22,11 @@
 #include <android/hardware/secure_element/1.0/types.h>
 #include <android/hardware/secure_element/1.1/ISecureElement.h>
 #include <android/hardware/secure_element/1.1/ISecureElementHalCallback.h>
+#include <gtest/gtest.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_string;
@@ -33,7 +34,6 @@
 using ::android::hardware::Void;
 using ::android::hardware::secure_element::V1_1::ISecureElement;
 using ::android::hardware::secure_element::V1_1::ISecureElementHalCallback;
-using ::testing::VtsHalHidlTargetTestEnvBase;
 
 constexpr char kCallbackNameOnStateChange[] = "onStateChange";
 
@@ -60,30 +60,11 @@
     Return<void> onStateChange(__attribute__((unused)) bool state) override { return Void(); }
 };
 
-class SecureElementHidlEnvironment : public VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static SecureElementHidlEnvironment* Instance() {
-        static SecureElementHidlEnvironment* instance = new SecureElementHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<ISecureElement>(); }
-
-   private:
-    SecureElementHidlEnvironment() {}
-
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(SecureElementHidlEnvironment);
-};
-
-class SecureElementHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
+class SecureElementHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override {
-        std::string serviceName =
-                SecureElementHidlEnvironment::Instance()->getServiceName<ISecureElement>("eSE1");
-        LOG(INFO) << "get service with name:" << serviceName;
-        ASSERT_FALSE(serviceName.empty());
-        se_ = ::testing::VtsHalHidlTargetTestBase::getService<ISecureElement>(serviceName);
+        LOG(INFO) << "get service with name:" << GetParam();
+        se_ = ISecureElement::getService(GetParam());
         ASSERT_NE(se_, nullptr);
 
         se_cb_ = new SecureElementHalCallback();
@@ -103,14 +84,11 @@
  * isCardPresent:
  * Expects the card to be present
  */
-TEST_F(SecureElementHidlTest, isCardPresent) {
+TEST_P(SecureElementHidlTest, isCardPresent) {
     EXPECT_TRUE(se_->isCardPresent());
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(SecureElementHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    SecureElementHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, SecureElementHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISecureElement::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/sensors/1.0/Android.bp b/sensors/1.0/Android.bp
index 3a41f9c..509f72f 100644
--- a/sensors/1.0/Android.bp
+++ b/sensors/1.0/Android.bp
@@ -16,4 +16,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/sensors/1.0/default/Android.bp b/sensors/1.0/default/Android.bp
index 2485b05..d5c1b23 100644
--- a/sensors/1.0/default/Android.bp
+++ b/sensors/1.0/default/Android.bp
@@ -11,7 +11,6 @@
         "libbase",
         "libutils",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.sensors@1.0",
     ],
     static_libs: [
@@ -34,7 +33,6 @@
         "libbase",
         "libutils",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.sensors@1.0",
     ],
     local_include_dirs: ["include/sensors"],
@@ -57,7 +55,6 @@
         "libbase",
         "libutils",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.sensors@1.0",
     ],
 }
diff --git a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
index db340af..b41730b 100644
--- a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
+++ b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.sensors-hal-1-0 /vendor/bin/hw/android.hardware.sensors@1.0-service
+    interface android.hardware.sensors@1.0::ISensors default
     class hal
     user system
     group system wakelock uhid
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
index 52f5e4f..53ceb0d 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -68,9 +68,9 @@
     typedef ::android::hardware::sensors::V1_0::MetaDataEventType MetaDataEventType;
 
     *dst = {
-        .sensorHandle = src.sensor,
-        .sensorType = (SensorType)src.type,
-        .timestamp = src.timestamp
+            .timestamp = src.timestamp,
+            .sensorHandle = src.sensor,
+            .sensorType = (SensorType)src.type,
     };
 
     switch (dst->sensorType) {
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 7bb992b..1167fd4 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -31,6 +31,6 @@
         "android.hardware.sensors@1.0",
         "VtsHalSensorsTargetTestUtils",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/sensors/1.0/vts/functional/AndroidTest.xml b/sensors/1.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..fb0d64c
--- /dev/null
+++ b/sensors/1.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,39 @@
+<?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 VtsHalSensorsV1_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.RunCommandTargetPreparer">
+        <option name="run-command" value="stop"/>
+        <option name="teardown-command" value="start"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalSensorsV1_0TargetTest->/data/local/tmp/VtsHalSensorsV1_0TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-timeout" value="900000" />
+        <option name="runtime-hint" value="300000"/>
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalSensorsV1_0TargetTest" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
index 00207b1..1e5e886 100644
--- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
@@ -35,8 +35,7 @@
         // this do ... while is for easy error handling
         do {
             step = "getService()";
-            sensors = ISensors::getService(
-                SensorsHidlEnvironmentV1_0::Instance()->getServiceName<ISensors>());
+            sensors = ISensors::getService(mServiceName);
             if (sensors == nullptr) {
                 break;
             }
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
index 0a9e59f..29bfa50 100644
--- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
@@ -32,23 +32,14 @@
 class SensorsHidlEnvironmentV1_0 : public SensorsHidlEnvironmentBase {
    public:
     using Event = ::android::hardware::sensors::V1_0::Event;
-    // get the test environment singleton
-    static SensorsHidlEnvironmentV1_0* Instance() {
-        static SensorsHidlEnvironmentV1_0* instance = new SensorsHidlEnvironmentV1_0();
-        return instance;
-    }
+    SensorsHidlEnvironmentV1_0(const std::string& service_name)
+        : SensorsHidlEnvironmentBase(service_name) {}
 
-    virtual void registerTestServices() override {
-        registerTestService<android::hardware::sensors::V1_0::ISensors>();
-    }
-
-   private:
+  private:
     friend SensorsHidlTest;
     // sensors hidl service
     sp<android::hardware::sensors::V1_0::ISensors> sensors;
 
-    SensorsHidlEnvironmentV1_0() {}
-
     bool resetHal() override;
     void startPollingThread() override;
     static void pollingThread(SensorsHidlEnvironmentV1_0* env, std::atomic_bool& stop);
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
index 5453ef6..2cad54d 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -19,6 +19,8 @@
 
 #include <android/hardware/sensors/1.0/ISensors.h>
 #include <android/hardware/sensors/1.0/types.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 #include <utils/SystemClock.h>
 
@@ -33,7 +35,17 @@
 // The main test class for SENSORS HIDL HAL.
 
 class SensorsHidlTest : public SensorsHidlTestBase {
-   protected:
+  public:
+    virtual void SetUp() override {
+        mEnvironment = new SensorsHidlEnvironmentV1_0(GetParam());
+        mEnvironment->HidlSetUp();
+        // Ensure that we have a valid environment before performing tests
+        ASSERT_NE(S(), nullptr);
+    }
+
+    virtual void TearDown() override { mEnvironment->HidlTearDown(); }
+
+  protected:
     SensorInfo defaultSensorByType(SensorType type) override;
     std::vector<SensorInfo> getSensorsList();
     // implementation wrapper
@@ -66,11 +78,13 @@
         return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
     }
 
-    inline sp<ISensors>& S() { return SensorsHidlEnvironmentV1_0::Instance()->sensors; }
+    inline sp<ISensors>& S() { return mEnvironment->sensors; }
 
-    SensorsHidlEnvironmentBase* getEnvironment() override {
-        return SensorsHidlEnvironmentV1_0::Instance();
-    }
+    SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; }
+
+  private:
+    // Test environment for sensors HAL.
+    SensorsHidlEnvironmentV1_0* mEnvironment;
 };
 
 Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
@@ -133,55 +147,52 @@
 }
 
 // Test if sensor list returned is valid
-TEST_F(SensorsHidlTest, SensorListValid) {
-  S()->getSensorsList(
-      [&] (const auto &list) {
+TEST_P(SensorsHidlTest, SensorListValid) {
+    S()->getSensorsList([&](const auto& list) {
         const size_t count = list.size();
         for (size_t i = 0; i < count; ++i) {
-          const auto &s = list[i];
-          SCOPED_TRACE(::testing::Message() << i << "/" << count << ": "
-                       << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
-                       << s.sensorHandle << std::dec
-                       << " type=" << static_cast<int>(s.type)
-                       << " name=" << s.name);
+            const auto& s = list[i];
+            SCOPED_TRACE(::testing::Message()
+                         << i << "/" << count << ": "
+                         << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                         << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
+                         << " name=" << s.name);
 
-          // Test non-empty type string
-          EXPECT_FALSE(s.typeAsString.empty());
+            // Test non-empty type string
+            EXPECT_FALSE(s.typeAsString.empty());
 
-          // Test defined type matches defined string type
-          EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
+            // Test defined type matches defined string type
+            EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
 
-          // Test if all sensor has name and vendor
-          EXPECT_FALSE(s.name.empty());
-          EXPECT_FALSE(s.vendor.empty());
+            // Test if all sensor has name and vendor
+            EXPECT_FALSE(s.name.empty());
+            EXPECT_FALSE(s.vendor.empty());
 
-          // Test power > 0, maxRange > 0
-          EXPECT_LE(0, s.power);
-          EXPECT_LT(0, s.maxRange);
+            // Test power > 0, maxRange > 0
+            EXPECT_LE(0, s.power);
+            EXPECT_LT(0, s.maxRange);
 
-          // Info type, should have no sensor
-          EXPECT_FALSE(
-              s.type == SensorType::ADDITIONAL_INFO
-              || s.type == SensorType::META_DATA);
+            // Info type, should have no sensor
+            EXPECT_FALSE(s.type == SensorType::ADDITIONAL_INFO || s.type == SensorType::META_DATA);
 
-          // Test fifoMax >= fifoReserved
-          EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
-              << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
+            // Test fifoMax >= fifoReserved
+            EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
+                    << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
 
-          // Test Reporting mode valid
-          EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
+            // Test Reporting mode valid
+            EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
 
-          // Test min max are in the right order
-          EXPECT_LE(s.minDelay, s.maxDelay);
-          // Test min/max delay matches reporting mode
-          EXPECT_NO_FATAL_FAILURE(
-              assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
+            // Test min max are in the right order
+            EXPECT_LE(s.minDelay, s.maxDelay);
+            // Test min/max delay matches reporting mode
+            EXPECT_NO_FATAL_FAILURE(
+                    assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
         }
-      });
+    });
 }
 
 // Test if sensor list returned is valid
-TEST_F(SensorsHidlTest, SetOperationMode) {
+TEST_P(SensorsHidlTest, SetOperationMode) {
     std::vector<SensorInfo> sensorList = getSensorsList();
 
     bool needOperationModeSupport =
@@ -199,7 +210,7 @@
 }
 
 // Test if sensor list returned is valid
-TEST_F(SensorsHidlTest, InjectSensorEventData) {
+TEST_P(SensorsHidlTest, InjectSensorEventData) {
     std::vector<SensorInfo> sensorList = getSensorsList();
     std::vector<SensorInfo> sensorSupportInjection;
 
@@ -244,224 +255,202 @@
 }
 
 // Test if sensor hal can do UI speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
-  testStreamingOperation(SensorType::ACCELEROMETER,
-                         std::chrono::milliseconds(200),
-                         std::chrono::seconds(5),
-                         sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
+    testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200),
+                           std::chrono::seconds(5), sAccelNormChecker);
 }
 
 // Test if sensor hal can do normal speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
-  testStreamingOperation(SensorType::ACCELEROMETER,
-                         std::chrono::milliseconds(20),
-                         std::chrono::seconds(5),
-                         sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
+    testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20),
+                           std::chrono::seconds(5), sAccelNormChecker);
 }
 
 // Test if sensor hal can do game speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationFast) {
-  testStreamingOperation(SensorType::ACCELEROMETER,
-                         std::chrono::milliseconds(5),
-                         std::chrono::seconds(5),
-                         sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) {
+    testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5),
+                           std::chrono::seconds(5), sAccelNormChecker);
 }
 
 // Test if sensor hal can do UI speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
-  testStreamingOperation(SensorType::GYROSCOPE,
-                         std::chrono::milliseconds(200),
-                         std::chrono::seconds(5),
-                         sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
+    testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200),
+                           std::chrono::seconds(5), sGyroNormChecker);
 }
 
 // Test if sensor hal can do normal speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
-  testStreamingOperation(SensorType::GYROSCOPE,
-                         std::chrono::milliseconds(20),
-                         std::chrono::seconds(5),
-                         sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
+    testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20),
+                           std::chrono::seconds(5), sGyroNormChecker);
 }
 
 // Test if sensor hal can do game speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationFast) {
-  testStreamingOperation(SensorType::GYROSCOPE,
-                         std::chrono::milliseconds(5),
-                         std::chrono::seconds(5),
-                         sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) {
+    testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5),
+                           std::chrono::seconds(5), sGyroNormChecker);
 }
 
 // Test if sensor hal can do UI speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
-  testStreamingOperation(SensorType::MAGNETIC_FIELD,
-                         std::chrono::milliseconds(200),
-                         std::chrono::seconds(5),
-                         NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
+    testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200),
+                           std::chrono::seconds(5), NullChecker());
 }
 
 // Test if sensor hal can do normal speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
-  testStreamingOperation(SensorType::MAGNETIC_FIELD,
-                         std::chrono::milliseconds(20),
-                         std::chrono::seconds(5),
-                         NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
+    testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20),
+                           std::chrono::seconds(5), NullChecker());
 }
 
 // Test if sensor hal can do game speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) {
-  testStreamingOperation(SensorType::MAGNETIC_FIELD,
-                         std::chrono::milliseconds(5),
-                         std::chrono::seconds(5),
-                         NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) {
+    testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5),
+                           std::chrono::seconds(5), NullChecker());
 }
 
 // Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
-  testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
-  testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/);
+TEST_P(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+    testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
+    testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/);
 }
 
 // Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
-  testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
-  testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/);
+TEST_P(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
+    testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
+    testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/);
 }
 
 // Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
-  testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
-  testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
+TEST_P(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
+    testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
+    testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
 }
 
 // Test if sensor hal can do accelerometer batching properly
-TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
-  testBatchingOperation(SensorType::ACCELEROMETER);
+TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) {
+    testBatchingOperation(SensorType::ACCELEROMETER);
 }
 
 // Test if sensor hal can do gyroscope batching properly
-TEST_F(SensorsHidlTest, GyroscopeBatchingOperation) {
-  testBatchingOperation(SensorType::GYROSCOPE);
+TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) {
+    testBatchingOperation(SensorType::GYROSCOPE);
 }
 
 // Test if sensor hal can do magnetometer batching properly
-TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) {
-  testBatchingOperation(SensorType::MAGNETIC_FIELD);
+TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) {
+    testBatchingOperation(SensorType::MAGNETIC_FIELD);
 }
 
 // Test sensor event direct report with ashmem for accel sensor at normal rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
-  testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                            sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
+                              sAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for accel sensor at fast rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
-  testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
-                            sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
+                              sAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for accel sensor at very fast rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
-  testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
-                            sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM,
+                              RateLevel::VERY_FAST, sAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at normal rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
-  testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                            sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
+                              sGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at fast rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
-  testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
-                            sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
+                              sGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at very fast rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
-  testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
-                            sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
+                              sGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for mag sensor at normal rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
-  testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                            NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
+                              NullChecker());
 }
 
 // Test sensor event direct report with ashmem for mag sensor at fast rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
-  testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
-                            NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
+                              NullChecker());
 }
 
 // Test sensor event direct report with ashmem for mag sensor at very fast rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
-  testDirectReportOperation(
-      SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::VERY_FAST, NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM,
+                              RateLevel::VERY_FAST, NullChecker());
 }
 
 // Test sensor event direct report with gralloc for accel sensor at normal rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
-  testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                            sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
+                              sAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for accel sensor at fast rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
-  testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
-                            sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
+                              sAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for accel sensor at very fast rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
-  testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
-                            sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC,
+                              RateLevel::VERY_FAST, sAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at normal rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
-  testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                            sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
+                              sGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at fast rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
-  testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
-                            sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
+                              sGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at very fast rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
-  testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
-                            sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
+                              sGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for mag sensor at normal rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
-  testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                            NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
+                              NullChecker());
 }
 
 // Test sensor event direct report with gralloc for mag sensor at fast rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
-  testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
-                            NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
+                              NullChecker());
 }
 
 // Test sensor event direct report with gralloc for mag sensor at very fast rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
-  testDirectReportOperation(
-      SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::VERY_FAST, NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC,
+                              RateLevel::VERY_FAST, NullChecker());
 }
 
-int main(int argc, char **argv) {
-    ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV1_0::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    SensorsHidlEnvironmentV1_0::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, SensorsHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISensors::descriptor)),
+        android::hardware::PrintInstanceNameToString);
 // vim: set ts=2 sw=2
diff --git a/sensors/2.0/Android.bp b/sensors/2.0/Android.bp
index eead1d3..c8517c8 100644
--- a/sensors/2.0/Android.bp
+++ b/sensors/2.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/sensors/2.0/default/Android.bp b/sensors/2.0/default/Android.bp
index 05a34bb..62c9487 100644
--- a/sensors/2.0/default/Android.bp
+++ b/sensors/2.0/default/Android.bp
@@ -30,7 +30,6 @@
         "libcutils",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libpower",
         "libutils",
diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp
new file mode 100644
index 0000000..811c455
--- /dev/null
+++ b/sensors/2.0/multihal/Android.bp
@@ -0,0 +1,94 @@
+//
+// 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_defaults {
+    name: "android.hardware.sensors@2.0-multihal-defaults",
+    header_libs: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
+}
+
+cc_binary {
+    name: "android.hardware.sensors@2.0-service.multihal",
+    defaults: [
+        "hidl_defaults",
+        "android.hardware.sensors@2.0-multihal-defaults",
+    ],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "service.cpp",
+        "HalProxy.cpp",
+    ],
+    init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
+    vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
+    shared_libs: ["android.hardware.sensors@2.0-ScopedWakelock"]
+}
+
+cc_library_headers {
+    name: "android.hardware.sensors@2.0-multihal.header",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+}
+
+cc_library_shared {
+    name: "android.hardware.sensors@2.0-ScopedWakelock",
+    defaults: [
+        "hidl_defaults",
+        "android.hardware.sensors@2.0-multihal-defaults",
+    ],
+    srcs: [
+        "ScopedWakelock.cpp",
+    ],
+    vendor_available: true,
+    export_header_lib_headers: [
+        "android.hardware.sensors@2.0-multihal.header"
+    ]
+}
+
+// The below targets should only be used for testing.
+cc_test_library {
+    name: "android.hardware.sensors@2.0-HalProxy",
+    defaults: [
+        "hidl_defaults",
+        "android.hardware.sensors@2.0-multihal-defaults",
+    ],
+    vendor_available: true,
+    srcs: [
+        "HalProxy.cpp",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+    export_shared_lib_headers: [
+	"android.hardware.sensors@2.0-ScopedWakelock",
+    ],
+    shared_libs: [
+        "libutils",
+        "android.hardware.sensors@2.0-ScopedWakelock",
+    ],
+}
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
new file mode 100644
index 0000000..03ff605
--- /dev/null
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -0,0 +1,690 @@
+/*
+ * 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 "HalProxy.h"
+
+#include "SubHal.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+
+#include <android-base/file.h>
+#include "hardware_legacy/power.h"
+
+#include <dlfcn.h>
+
+#include <cinttypes>
+#include <cmath>
+#include <fstream>
+#include <functional>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::getTimeNow;
+using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs;
+
+typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*);
+
+static constexpr int32_t kBitsAfterSubHalIndex = 24;
+
+/**
+ * Set the subhal index as first byte of sensor handle and return this modified version.
+ *
+ * @param sensorHandle The sensor handle to modify.
+ * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to.
+ *
+ * @return The modified sensor handle.
+ */
+int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) {
+    return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
+}
+
+/**
+ * Extract the subHalIndex from sensorHandle.
+ *
+ * @param sensorHandle The sensorHandle to extract from.
+ *
+ * @return The subhal index.
+ */
+size_t extractSubHalIndex(int32_t sensorHandle) {
+    return static_cast<size_t>(sensorHandle >> kBitsAfterSubHalIndex);
+}
+
+/**
+ * Convert nanoseconds to milliseconds.
+ *
+ * @param nanos The nanoseconds input.
+ *
+ * @return The milliseconds count.
+ */
+int64_t msFromNs(int64_t nanos) {
+    constexpr int64_t nanosecondsInAMillsecond = 1000000;
+    return nanos / nanosecondsInAMillsecond;
+}
+
+HalProxy::HalProxy() {
+    const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
+    initializeSubHalListFromConfigFile(kMultiHalConfigFile);
+    init();
+}
+
+HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) {
+    init();
+}
+
+HalProxy::~HalProxy() {
+    stopThreads();
+}
+
+Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& iter : mSensors) {
+        sensors.push_back(iter.second);
+    }
+    _hidl_cb(sensors);
+    return Void();
+}
+
+Return<Result> HalProxy::setOperationMode(OperationMode mode) {
+    Result result = Result::OK;
+    size_t subHalIndex;
+    for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+        ISensorsSubHal* subHal = mSubHalList[subHalIndex];
+        result = subHal->setOperationMode(mode);
+        if (result != Result::OK) {
+            ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str());
+            break;
+        }
+    }
+    if (result != Result::OK) {
+        // Reset the subhal operation modes that have been flipped
+        for (size_t i = 0; i < subHalIndex; i++) {
+            ISensorsSubHal* subHal = mSubHalList[i];
+            subHal->setOperationMode(mCurrentOperationMode);
+        }
+    } else {
+        mCurrentOperationMode = mode;
+    }
+    return result;
+}
+
+Return<Result> HalProxy::activate(int32_t sensorHandle, bool enabled) {
+    if (!isSubHalIndexValid(sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
+    return getSubHalForSensorHandle(sensorHandle)
+            ->activate(clearSubHalIndex(sensorHandle), enabled);
+}
+
+Return<Result> HalProxy::initialize(
+        const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+        const sp<ISensorsCallback>& sensorsCallback) {
+    Result result = Result::OK;
+
+    stopThreads();
+    resetSharedWakelock();
+
+    // So that the pending write events queue can be cleared safely and when we start threads
+    // again we do not get new events until after initialize resets the subhals.
+    disableAllSensors();
+
+    // Clears the queue if any events were pending write before.
+    mPendingWriteEventsQueue = std::queue<std::pair<std::vector<Event>, size_t>>();
+    mSizePendingWriteEventsQueue = 0;
+
+    // Clears previously connected dynamic sensors
+    mDynamicSensors.clear();
+
+    mDynamicSensorsCallback = sensorsCallback;
+
+    // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
+    mEventQueue =
+            std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
+
+    // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
+    // events have been successfully read and handled by the framework.
+    mWakeLockQueue =
+            std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
+
+    if (mEventQueueFlag != nullptr) {
+        EventFlag::deleteEventFlag(&mEventQueueFlag);
+    }
+    if (mWakelockQueueFlag != nullptr) {
+        EventFlag::deleteEventFlag(&mWakelockQueueFlag);
+    }
+    if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
+        result = Result::BAD_VALUE;
+    }
+    if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) {
+        result = Result::BAD_VALUE;
+    }
+    if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
+        result = Result::BAD_VALUE;
+    }
+
+    mThreadsRun.store(true);
+
+    mPendingWritesThread = std::thread(startPendingWritesThread, this);
+    mWakelockThread = std::thread(startWakelockThread, this);
+
+    for (size_t i = 0; i < mSubHalList.size(); i++) {
+        auto subHal = mSubHalList[i];
+        const auto& subHalCallback = mSubHalCallbacks[i];
+        Result currRes = subHal->initialize(subHalCallback);
+        if (currRes != Result::OK) {
+            result = currRes;
+            ALOGE("Subhal '%s' failed to initialize.", subHal->getName().c_str());
+            break;
+        }
+    }
+
+    mCurrentOperationMode = OperationMode::NORMAL;
+
+    return result;
+}
+
+Return<Result> HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                               int64_t maxReportLatencyNs) {
+    if (!isSubHalIndexValid(sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
+    return getSubHalForSensorHandle(sensorHandle)
+            ->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs);
+}
+
+Return<Result> HalProxy::flush(int32_t sensorHandle) {
+    if (!isSubHalIndexValid(sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
+    return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle));
+}
+
+Return<Result> HalProxy::injectSensorData(const Event& event) {
+    Result result = Result::OK;
+    if (mCurrentOperationMode == OperationMode::NORMAL &&
+        event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) {
+        ALOGE("An event with type != ADDITIONAL_INFO passed to injectSensorData while operation"
+              " mode was NORMAL.");
+        result = Result::BAD_VALUE;
+    }
+    if (result == Result::OK) {
+        Event subHalEvent = event;
+        if (!isSubHalIndexValid(event.sensorHandle)) {
+            return Result::BAD_VALUE;
+        }
+        subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle);
+        result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent);
+    }
+    return result;
+}
+
+Return<void> HalProxy::registerDirectChannel(const SharedMemInfo& mem,
+                                             registerDirectChannel_cb _hidl_cb) {
+    if (mDirectChannelSubHal == nullptr) {
+        _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+    } else {
+        mDirectChannelSubHal->registerDirectChannel(mem, _hidl_cb);
+    }
+    return Return<void>();
+}
+
+Return<Result> HalProxy::unregisterDirectChannel(int32_t channelHandle) {
+    Result result;
+    if (mDirectChannelSubHal == nullptr) {
+        result = Result::INVALID_OPERATION;
+    } else {
+        result = mDirectChannelSubHal->unregisterDirectChannel(channelHandle);
+    }
+    return result;
+}
+
+Return<void> HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle,
+                                          RateLevel rate, configDirectReport_cb _hidl_cb) {
+    if (mDirectChannelSubHal == nullptr) {
+        _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */);
+    } else {
+        mDirectChannelSubHal->configDirectReport(clearSubHalIndex(sensorHandle), channelHandle,
+                                                 rate, _hidl_cb);
+    }
+    return Return<void>();
+}
+
+Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+        ALOGE("%s: missing fd for writing", __FUNCTION__);
+        return Void();
+    }
+
+    android::base::borrowed_fd writeFd = dup(fd->data[0]);
+
+    std::ostringstream stream;
+    stream << "===HalProxy===" << std::endl;
+    stream << "Internal values:" << std::endl;
+    stream << "  Threads are running: " << (mThreadsRun.load() ? "true" : "false") << std::endl;
+    int64_t now = getTimeNow();
+    stream << "  Wakelock timeout start time: " << msFromNs(now - mWakelockTimeoutStartTime)
+           << " ms ago" << std::endl;
+    stream << "  Wakelock timeout reset time: " << msFromNs(now - mWakelockTimeoutResetTime)
+           << " ms ago" << std::endl;
+    // TODO(b/142969448): Add logging for history of wakelock acquisition per subhal.
+    stream << "  Wakelock ref count: " << mWakelockRefCount << std::endl;
+    stream << "  # of events on pending write writes queue: " << mSizePendingWriteEventsQueue
+           << std::endl;
+    if (!mPendingWriteEventsQueue.empty()) {
+        stream << "  Size of events list on front of pending writes queue: "
+               << mPendingWriteEventsQueue.front().first.size() << std::endl;
+    }
+    stream << "  # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl;
+    stream << "  # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl;
+    stream << "SubHals (" << mSubHalList.size() << "):" << std::endl;
+    for (ISensorsSubHal* subHal : mSubHalList) {
+        stream << "  Name: " << subHal->getName() << std::endl;
+        stream << "  Debug dump: " << std::endl;
+        android::base::WriteStringToFd(stream.str(), writeFd);
+        subHal->debug(fd, {});
+        stream.str("");
+        stream << std::endl;
+    }
+    android::base::WriteStringToFd(stream.str(), writeFd);
+    return Return<void>();
+}
+
+Return<void> HalProxy::onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+                                                 int32_t subHalIndex) {
+    std::vector<SensorInfo> sensors;
+    {
+        std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+        for (SensorInfo sensor : dynamicSensorsAdded) {
+            if (!subHalIndexIsClear(sensor.sensorHandle)) {
+                ALOGE("Dynamic sensor added %s had sensorHandle with first byte not 0.",
+                      sensor.name.c_str());
+            } else {
+                sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
+                mDynamicSensors[sensor.sensorHandle] = sensor;
+                sensors.push_back(sensor);
+            }
+        }
+    }
+    mDynamicSensorsCallback->onDynamicSensorsConnected(sensors);
+    return Return<void>();
+}
+
+Return<void> HalProxy::onDynamicSensorsDisconnected(
+        const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) {
+    // TODO(b/143302327): Block this call until all pending events are flushed from queue
+    std::vector<int32_t> sensorHandles;
+    {
+        std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+        for (int32_t sensorHandle : dynamicSensorHandlesRemoved) {
+            if (!subHalIndexIsClear(sensorHandle)) {
+                ALOGE("Dynamic sensorHandle removed had first byte not 0.");
+            } else {
+                sensorHandle = setSubHalIndex(sensorHandle, subHalIndex);
+                if (mDynamicSensors.find(sensorHandle) != mDynamicSensors.end()) {
+                    mDynamicSensors.erase(sensorHandle);
+                    sensorHandles.push_back(sensorHandle);
+                }
+            }
+        }
+    }
+    mDynamicSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
+    return Return<void>();
+}
+
+void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
+    std::ifstream subHalConfigStream(configFileName);
+    if (!subHalConfigStream) {
+        ALOGE("Failed to load subHal config file: %s", configFileName);
+    } else {
+        std::string subHalLibraryFile;
+        while (subHalConfigStream >> subHalLibraryFile) {
+            void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW);
+            if (handle == nullptr) {
+                ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str());
+            } else {
+                SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
+                        (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
+                if (sensorsHalGetSubHalPtr == nullptr) {
+                    ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s",
+                          subHalLibraryFile.c_str());
+                } else {
+                    std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
+                            *sensorsHalGetSubHalPtr;
+                    uint32_t version;
+                    ISensorsSubHal* subHal = sensorsHalGetSubHal(&version);
+                    if (version != SUB_HAL_2_0_VERSION) {
+                        ALOGE("SubHal version was not 2.0 for library: %s",
+                              subHalLibraryFile.c_str());
+                    } else {
+                        ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
+                        mSubHalList.push_back(subHal);
+                    }
+                }
+            }
+        }
+    }
+}
+
+void HalProxy::initializeSubHalCallbacks() {
+    for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+        sp<IHalProxyCallback> callback = new HalProxyCallback(this, subHalIndex);
+        mSubHalCallbacks.push_back(callback);
+    }
+}
+
+void HalProxy::initializeSensorList() {
+    for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+        ISensorsSubHal* subHal = mSubHalList[subHalIndex];
+        auto result = subHal->getSensorsList([&](const auto& list) {
+            for (SensorInfo sensor : list) {
+                if (!subHalIndexIsClear(sensor.sensorHandle)) {
+                    ALOGE("SubHal sensorHandle's first byte was not 0");
+                } else {
+                    ALOGV("Loaded sensor: %s", sensor.name.c_str());
+                    sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
+                    setDirectChannelFlags(&sensor, subHal);
+                    mSensors[sensor.sensorHandle] = sensor;
+                }
+            }
+        });
+        if (!result.isOk()) {
+            ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str());
+        }
+    }
+}
+
+void HalProxy::init() {
+    initializeSubHalCallbacks();
+    initializeSensorList();
+}
+
+void HalProxy::stopThreads() {
+    mThreadsRun.store(false);
+    if (mEventQueueFlag != nullptr && mEventQueue != nullptr) {
+        size_t numToRead = mEventQueue->availableToRead();
+        std::vector<Event> events(numToRead);
+        mEventQueue->read(events.data(), numToRead);
+        mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ));
+    }
+    if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) {
+        uint32_t kZero = 0;
+        mWakeLockQueue->write(&kZero);
+        mWakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+    }
+    mWakelockCV.notify_one();
+    mEventQueueWriteCV.notify_one();
+    if (mPendingWritesThread.joinable()) {
+        mPendingWritesThread.join();
+    }
+    if (mWakelockThread.joinable()) {
+        mWakelockThread.join();
+    }
+}
+
+void HalProxy::disableAllSensors() {
+    for (const auto& sensorEntry : mSensors) {
+        int32_t sensorHandle = sensorEntry.first;
+        activate(sensorHandle, false /* enabled */);
+    }
+    std::lock_guard<std::mutex> dynamicSensorsLock(mDynamicSensorsMutex);
+    for (const auto& sensorEntry : mDynamicSensors) {
+        int32_t sensorHandle = sensorEntry.first;
+        activate(sensorHandle, false /* enabled */);
+    }
+}
+
+void HalProxy::startPendingWritesThread(HalProxy* halProxy) {
+    halProxy->handlePendingWrites();
+}
+
+void HalProxy::handlePendingWrites() {
+    // TODO(b/143302327): Find a way to optimize locking strategy maybe using two mutexes instead of
+    // one.
+    std::unique_lock<std::mutex> lock(mEventQueueWriteMutex);
+    while (mThreadsRun.load()) {
+        mEventQueueWriteCV.wait(
+                lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); });
+        if (mThreadsRun.load()) {
+            std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front().first;
+            size_t numWakeupEvents = mPendingWriteEventsQueue.front().second;
+            size_t eventQueueSize = mEventQueue->getQuantumCount();
+            size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
+            lock.unlock();
+            if (!mEventQueue->writeBlocking(
+                        pendingWriteEvents.data(), numToWrite,
+                        static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+                        static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+                        kPendingWriteTimeoutNs, mEventQueueFlag)) {
+                ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite);
+                if (numWakeupEvents > 0) {
+                    if (pendingWriteEvents.size() > eventQueueSize) {
+                        decrementRefCountAndMaybeReleaseWakelock(
+                                countNumWakeupEvents(pendingWriteEvents, eventQueueSize));
+                    } else {
+                        decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents);
+                    }
+                }
+            }
+            lock.lock();
+            if (pendingWriteEvents.size() > eventQueueSize) {
+                // TODO(b/143302327): Check if this erase operation is too inefficient. It will copy
+                // all the events ahead of it down to fill gap off array at front after the erase.
+                pendingWriteEvents.erase(pendingWriteEvents.begin(),
+                                         pendingWriteEvents.begin() + eventQueueSize);
+                mSizePendingWriteEventsQueue -= eventQueueSize;
+            } else {
+                mPendingWriteEventsQueue.pop();
+                mSizePendingWriteEventsQueue -= pendingWriteEvents.size();
+            }
+        }
+    }
+}
+
+void HalProxy::startWakelockThread(HalProxy* halProxy) {
+    halProxy->handleWakelocks();
+}
+
+void HalProxy::handleWakelocks() {
+    std::unique_lock<std::recursive_mutex> lock(mWakelockMutex);
+    while (mThreadsRun.load()) {
+        mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); });
+        if (mThreadsRun.load()) {
+            int64_t timeLeft;
+            if (sharedWakelockDidTimeout(&timeLeft)) {
+                resetSharedWakelock();
+            } else {
+                uint32_t numWakeLocksProcessed;
+                lock.unlock();
+                bool success = mWakeLockQueue->readBlocking(
+                        &numWakeLocksProcessed, 1, 0,
+                        static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft);
+                lock.lock();
+                if (success) {
+                    decrementRefCountAndMaybeReleaseWakelock(
+                            static_cast<size_t>(numWakeLocksProcessed));
+                }
+            }
+        }
+    }
+    resetSharedWakelock();
+}
+
+bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) {
+    bool didTimeout;
+    int64_t duration = getTimeNow() - mWakelockTimeoutStartTime;
+    if (duration > kWakelockTimeoutNs) {
+        didTimeout = true;
+    } else {
+        didTimeout = false;
+        *timeLeft = kWakelockTimeoutNs - duration;
+    }
+    return didTimeout;
+}
+
+void HalProxy::resetSharedWakelock() {
+    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+    decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount);
+    mWakelockTimeoutResetTime = getTimeNow();
+}
+
+void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+                                        ScopedWakelock wakelock) {
+    size_t numToWrite = 0;
+    std::lock_guard<std::mutex> lock(mEventQueueWriteMutex);
+    if (wakelock.isLocked()) {
+        incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents);
+    }
+    if (mPendingWriteEventsQueue.empty()) {
+        numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
+        if (numToWrite > 0) {
+            if (mEventQueue->write(events.data(), numToWrite)) {
+                // TODO(b/143302327): While loop if mEventQueue->avaiableToWrite > 0 to possibly fit
+                // in more writes immediately
+                mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+            } else {
+                numToWrite = 0;
+            }
+        }
+    }
+    size_t numLeft = events.size() - numToWrite;
+    if (numToWrite < events.size() &&
+        mSizePendingWriteEventsQueue + numLeft <= kMaxSizePendingWriteEventsQueue) {
+        std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
+        mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
+        mSizePendingWriteEventsQueue += numLeft;
+        mEventQueueWriteCV.notify_one();
+    }
+}
+
+bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+                                                        int64_t* timeoutStart /* = nullptr */) {
+    if (!mThreadsRun.load()) return false;
+    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+    if (mWakelockRefCount == 0) {
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName);
+        mWakelockCV.notify_one();
+    }
+    mWakelockTimeoutStartTime = getTimeNow();
+    mWakelockRefCount += delta;
+    if (timeoutStart != nullptr) {
+        *timeoutStart = mWakelockTimeoutStartTime;
+    }
+    return true;
+}
+
+void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+                                                        int64_t timeoutStart /* = -1 */) {
+    if (!mThreadsRun.load()) return;
+    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+    if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
+    if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;
+    mWakelockRefCount -= std::min(mWakelockRefCount, delta);
+    if (mWakelockRefCount == 0) {
+        release_wake_lock(kWakelockName);
+    }
+}
+
+void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) {
+    bool sensorSupportsDirectChannel =
+            (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
+                                  V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0;
+    if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) {
+        mDirectChannelSubHal = subHal;
+    } else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) {
+        // disable direct channel capability for sensors in subHals that are not
+        // the only one we will enable
+        sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
+                               V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
+    }
+}
+
+ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) {
+    return mSubHalList[extractSubHalIndex(sensorHandle)];
+}
+
+bool HalProxy::isSubHalIndexValid(int32_t sensorHandle) {
+    return extractSubHalIndex(sensorHandle) < mSubHalList.size();
+}
+
+size_t HalProxy::countNumWakeupEvents(const std::vector<Event>& events, size_t n) {
+    size_t numWakeupEvents = 0;
+    for (size_t i = 0; i < n; i++) {
+        int32_t sensorHandle = events[i].sensorHandle;
+        if (mSensors[sensorHandle].flags & static_cast<uint32_t>(V1_0::SensorFlagBits::WAKE_UP)) {
+            numWakeupEvents++;
+        }
+    }
+    return numWakeupEvents;
+}
+
+int32_t HalProxy::clearSubHalIndex(int32_t sensorHandle) {
+    return sensorHandle & (~kSensorHandleSubHalIndexMask);
+}
+
+bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) {
+    return (sensorHandle & kSensorHandleSubHalIndexMask) == 0;
+}
+
+void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) {
+    if (events.empty() || !mHalProxy->areThreadsRunning()) return;
+    size_t numWakeupEvents;
+    std::vector<Event> processedEvents = processEvents(events, &numWakeupEvents);
+    if (numWakeupEvents > 0) {
+        ALOG_ASSERT(wakelock.isLocked(),
+                    "Wakeup events posted while wakelock unlocked for subhal"
+                    " w/ index %zu.",
+                    mSubHalIndex);
+    } else {
+        ALOG_ASSERT(!wakelock.isLocked(),
+                    "No Wakeup events posted but wakelock locked for subhal"
+                    " w/ index %zu.",
+                    mSubHalIndex);
+    }
+    mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock));
+}
+
+ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) {
+    ScopedWakelock wakelock(mHalProxy, lock);
+    return wakelock;
+}
+
+std::vector<Event> HalProxyCallback::processEvents(const std::vector<Event>& events,
+                                                   size_t* numWakeupEvents) const {
+    *numWakeupEvents = 0;
+    std::vector<Event> eventsOut;
+    for (Event event : events) {
+        event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex);
+        eventsOut.push_back(event);
+        const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle);
+        if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) {
+            (*numWakeupEvents)++;
+        }
+    }
+    return eventsOut;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/OWNERS b/sensors/2.0/multihal/OWNERS
new file mode 100644
index 0000000..e955670
--- /dev/null
+++ b/sensors/2.0/multihal/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
\ No newline at end of file
diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/2.0/multihal/ScopedWakelock.cpp
new file mode 100644
index 0000000..d85d4a7
--- /dev/null
+++ b/sensors/2.0/multihal/ScopedWakelock.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 "ScopedWakelock.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+int64_t getTimeNow() {
+    return std::chrono::duration_cast<std::chrono::nanoseconds>(
+                   std::chrono::system_clock::now().time_since_epoch())
+            .count();
+}
+
+ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked)
+    : mRefCounter(refCounter), mLocked(locked) {
+    if (mLocked) {
+        mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs);
+    }
+}
+
+ScopedWakelock::~ScopedWakelock() {
+    if (mLocked) {
+        mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
new file mode 100644
index 0000000..1acc8e6
--- /dev/null
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.sensors</name>
+        <transport>hwbinder</transport>
+        <version>2.0</version>
+        <interface>
+            <name>ISensors</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
new file mode 100644
index 0000000..a4da3b0
--- /dev/null
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
@@ -0,0 +1,7 @@
+service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal
+    class hal
+    user system
+    group system wakelock
+    writepid /dev/cpuset/system-background/tasks
+    capabilities BLOCK_SUSPEND
+    rlimit rtprio 10 10
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
new file mode 100644
index 0000000..ce28e67
--- /dev/null
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -0,0 +1,402 @@
+/*
+ * 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 "ScopedWakelock.h"
+#include "SubHal.h"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <android/hardware/sensors/2.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hardware_legacy/power.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <map>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptor;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+class HalProxy : public ISensors, public IScopedWakelockRefCounter {
+  public:
+    using Event = ::android::hardware::sensors::V1_0::Event;
+    using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
+    using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
+    using Result = ::android::hardware::sensors::V1_0::Result;
+    using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo;
+    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+    using ISensorsSubHal = ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
+
+    explicit HalProxy();
+    // Test only constructor.
+    explicit HalProxy(std::vector<ISensorsSubHal*>& subHalList);
+    ~HalProxy();
+
+    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+
+    Return<Result> setOperationMode(OperationMode mode) override;
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+    Return<Result> initialize(
+            const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+            const sp<ISensorsCallback>& sensorsCallback) override;
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override;
+
+    Return<Result> flush(int32_t sensorHandle) override;
+
+    Return<Result> injectSensorData(const Event& event) override;
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       registerDirectChannel_cb _hidl_cb) override;
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    configDirectReport_cb _hidl_cb) override;
+
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+    // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change
+    // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework
+    // via the binder, these methods are invoked from a callback provided to sub-HALs inside the
+    // same process as the HalProxy, but potentially running on different threads.
+    Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+                                           int32_t subHalIndex);
+
+    Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved,
+                                              int32_t subHalIndex);
+
+    // Below methods are for HalProxyCallback
+
+    /**
+     * Post events to the event message queue if there is room to write them. Otherwise post the
+     * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs
+     * timeout.
+     *
+     * @param events The list of events to post to the message queue.
+     * @param numWakeupEvents The number of wakeup events in events.
+     * @param wakelock The wakelock associated with this post of events.
+     */
+    void postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+                                  ScopedWakelock wakelock);
+
+    /**
+     * Get the sensor info associated with that sensorHandle.
+     *
+     * @param sensorHandle The sensor handle.
+     *
+     * @return The sensor info object in the mapping.
+     */
+    const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; }
+
+    bool areThreadsRunning() { return mThreadsRun.load(); }
+
+    // Below methods are from IScopedWakelockRefCounter interface
+    bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+                                                  int64_t* timeoutStart = nullptr) override;
+
+    void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override;
+
+  private:
+    using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
+    using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+    /**
+     * The Event FMQ where sensor events are written
+     */
+    std::unique_ptr<EventMessageQueue> mEventQueue;
+
+    /**
+     * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
+     */
+    std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
+
+    /**
+     * Event Flag to signal to the framework when sensor events are available to be read and to
+     * interrupt event queue blocking write.
+     */
+    EventFlag* mEventQueueFlag = nullptr;
+
+    //! Event Flag to signal internally that the wakelock queue should stop its blocking read.
+    EventFlag* mWakelockQueueFlag = nullptr;
+
+    /**
+     * Callback to the sensors framework to inform it that new sensors have been added or removed.
+     */
+    sp<ISensorsCallback> mDynamicSensorsCallback;
+
+    /**
+     * SubHal object pointers that have been saved from vendor dynamic libraries.
+     */
+    std::vector<ISensorsSubHal*> mSubHalList;
+
+    //! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList
+    std::vector<const sp<IHalProxyCallback>> mSubHalCallbacks;
+
+    /**
+     * Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as
+     * well as the modified sensor handle for the framework.
+     *
+     * The subhal index is encoded in the first byte of the sensor handle and the remaining
+     * bytes are generated by the subhal to identify the sensor.
+     */
+    std::map<int32_t, SensorInfo> mSensors;
+
+    //! Map of the dynamic sensors that have been added to halproxy.
+    std::map<int32_t, SensorInfo> mDynamicSensors;
+
+    //! The current operation mode for all subhals.
+    OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
+    //! The single subHal that supports directChannel reporting.
+    ISensorsSubHal* mDirectChannelSubHal = nullptr;
+
+    //! The timeout for each pending write on background thread for events.
+    static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
+
+    //! The bit mask used to get the subhal index from a sensor handle.
+    static constexpr int32_t kSensorHandleSubHalIndexMask = 0xFF000000;
+
+    /**
+     * A FIFO queue of pairs of vector of events and the number of wakeup events in that vector
+     * which are waiting to be written to the events fmq in the background thread.
+     */
+    std::queue<std::pair<std::vector<Event>, size_t>> mPendingWriteEventsQueue;
+
+    //! The max number of events allowed in the pending write events queue
+    static constexpr size_t kMaxSizePendingWriteEventsQueue = 100000;
+
+    //! The number of events in the pending write events queue
+    size_t mSizePendingWriteEventsQueue = 0;
+
+    //! The mutex protecting writing to the fmq and the pending events queue
+    std::mutex mEventQueueWriteMutex;
+
+    //! The condition variable waiting on pending write events to stack up
+    std::condition_variable mEventQueueWriteCV;
+
+    //! The thread object ptr that handles pending writes
+    std::thread mPendingWritesThread;
+
+    //! The thread object that handles wakelocks
+    std::thread mWakelockThread;
+
+    //! The bool indicating whether to end the threads started in initialize
+    std::atomic_bool mThreadsRun = true;
+
+    //! The mutex protecting access to the dynamic sensors added and removed methods.
+    std::mutex mDynamicSensorsMutex;
+
+    // WakelockRefCount membar vars below
+
+    //! The mutex protecting the wakelock refcount and subsequent wakelock releases and
+    //! acquisitions
+    std::recursive_mutex mWakelockMutex;
+
+    std::condition_variable_any mWakelockCV;
+
+    //! The refcount of how many ScopedWakelocks and pending wakeup events are active
+    size_t mWakelockRefCount = 0;
+
+    int64_t mWakelockTimeoutStartTime = getTimeNow();
+
+    int64_t mWakelockTimeoutResetTime = getTimeNow();
+
+    const char* kWakelockName = "SensorsHAL_WAKEUP";
+
+    /**
+     * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
+     * listed in a config file.
+     */
+    void initializeSubHalListFromConfigFile(const char* configFileName);
+
+    /**
+     * Initialize the HalProxyCallback vector using the list of subhals.
+     */
+    void initializeSubHalCallbacks();
+
+    /**
+     * Initialize the list of SensorInfo objects in mSensorList by getting sensors from each
+     * subhal.
+     */
+    void initializeSensorList();
+
+    /**
+     * Calls the helper methods that all ctors use.
+     */
+    void init();
+
+    /**
+     * Stops all threads by setting the threads running flag to false and joining to them.
+     */
+    void stopThreads();
+
+    /**
+     * Disable all the sensors observed by the HalProxy.
+     */
+    void disableAllSensors();
+
+    /**
+     * Starts the thread that handles pending writes to event fmq.
+     *
+     * @param halProxy The HalProxy object pointer.
+     */
+    static void startPendingWritesThread(HalProxy* halProxy);
+
+    //! Handles the pending writes on events to eventqueue.
+    void handlePendingWrites();
+
+    /**
+     * Starts the thread that handles decrementing the ref count on wakeup events processed by the
+     * framework and timing out wakelocks.
+     *
+     * @param halProxy The HalProxy object pointer.
+     */
+    static void startWakelockThread(HalProxy* halProxy);
+
+    //! Handles the wakelocks.
+    void handleWakelocks();
+
+    /**
+     * @param timeLeft The variable that should be set to the timeleft before timeout will occur or
+     * unmodified if timeout occurred.
+     *
+     * @return true if the shared wakelock has been held passed the timeout and should be released
+     */
+    bool sharedWakelockDidTimeout(int64_t* timeLeft);
+
+    /**
+     * Reset all the member variables associated with the wakelock ref count and maybe release
+     * the shared wakelock.
+     */
+    void resetSharedWakelock();
+
+    /**
+     * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
+     * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
+     * direct channel enabled sensor seen.
+     *
+     * @param sensorInfo The SensorInfo object that may be altered to have direct channel support
+     *    disabled.
+     * @param subHal The subhal pointer that the current sensorInfo object came from.
+     */
+    void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal);
+
+    /*
+     * Get the subhal pointer which can be found by indexing into the mSubHalList vector
+     * using the index from the first byte of sensorHandle.
+     *
+     * @param sensorHandle The handle used to identify a sensor in one of the subhals.
+     */
+    ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle);
+
+    /**
+     * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList.
+     *
+     * @param sensorHandle The sensor handle to check.
+     *
+     * @return true if sensorHandles's subhal index byte is valid.
+     */
+    bool isSubHalIndexValid(int32_t sensorHandle);
+
+    /**
+     * Count the number of wakeup events in the first n events of the vector.
+     *
+     * @param events The vector of Event objects.
+     * @param n The end index not inclusive of events to consider.
+     *
+     * @return The number of wakeup events of the considered events.
+     */
+    size_t countNumWakeupEvents(const std::vector<Event>& events, size_t n);
+
+    /*
+     * Clear out the subhal index bytes from a sensorHandle.
+     *
+     * @param sensorHandle The sensor handle to modify.
+     *
+     * @return The modified version of the sensor handle.
+     */
+    static int32_t clearSubHalIndex(int32_t sensorHandle);
+
+    /**
+     * @param sensorHandle The sensor handle to modify.
+     *
+     * @return true if subHalIndex byte of sensorHandle is zeroed.
+     */
+    static bool subHalIndexIsClear(int32_t sensorHandle);
+};
+
+/**
+ * Callback class used to provide the HalProxy with the index of which subHal is invoking
+ */
+class HalProxyCallback : public IHalProxyCallback {
+    using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo;
+
+  public:
+    HalProxyCallback(HalProxy* halProxy, int32_t subHalIndex)
+        : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {}
+
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+        return mHalProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex);
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+        return mHalProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex);
+    }
+
+    void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock);
+
+    ScopedWakelock createScopedWakelock(bool lock);
+
+  private:
+    HalProxy* mHalProxy;
+    int32_t mSubHalIndex;
+
+    std::vector<Event> processEvents(const std::vector<Event>& events,
+                                     size_t* numWakeupEvents) const;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/2.0/multihal/include/ScopedWakelock.h
new file mode 100644
index 0000000..aa6d9db
--- /dev/null
+++ b/sensors/2.0/multihal/include/ScopedWakelock.h
@@ -0,0 +1,104 @@
+/*
+ * 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 <android/hardware/sensors/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+
+const int64_t kWakelockTimeoutNs =
+        static_cast<int64_t>(SensorTimeout::WAKE_LOCK_SECONDS) * INT64_C(1000000000);
+
+int64_t getTimeNow();
+
+class IScopedWakelockRefCounter : public RefBase {
+  public:
+    /**
+     * Increment the wakelock ref count and maybe acquire the shared wakelock if incrementing
+     * from 0 then return the time of incrementing back to caller.
+     *
+     * @param delta The amount to change ref count by.
+     * @param timeoutStart The ptr to the timestamp in ns that the increment occurred which will be
+     *        set in the function or nullptr if not specified.
+     *
+     * @return true if successfully incremented the wakelock ref count.
+     */
+    virtual bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+                                                          int64_t* timeoutStart = nullptr) = 0;
+    /**
+     * Decrement the wakelock ref count and maybe release wakelock if ref count ends up 0.
+     *
+     * @param delta The amount to change ref count by.
+     * @param timeoutStart The timestamp in ns that the calling context kept track of when
+     *        incrementing the ref count or -1 by default
+     */
+    virtual void decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+                                                          int64_t timeoutStart = -1) = 0;
+    // Virtual dtor needed for compilation success
+    virtual ~IScopedWakelockRefCounter(){};
+};
+
+/**
+ * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a
+ * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block.
+ * When a ScopedWakelock is created, it increments the reference count stored in the HalProxy
+ * for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes
+ * out of scope, the ref count is decremented, potentially releasing the wake lock if no other
+ * references to the wake lock exist.
+ *
+ * This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback
+ * provided to sub-HALs during initialization and should be used for all wake lock acquisition
+ * inside of the sub-HAL to ensure wake locks are not held indefinitely.
+ *
+ * The most prevalent use case for this class will be for posting events to the framework through
+ * the postEvents HalProxy callback. The expectation is that sub-HALs will create this
+ * ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean
+ * provided to createScopedWakelock will be set the according to whether the sensor events are
+ * from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the
+ * postEvents callback passing in the previously created ScopedWakelock. At this point, ownership
+ * of the object will be passed to the HalProxy that will then be responsible for ensuring any
+ * wake locks continue to be held, if necessary.
+ */
+class ScopedWakelock {
+  public:
+    ScopedWakelock(ScopedWakelock&&) = default;
+    ScopedWakelock& operator=(ScopedWakelock&&) = default;
+    virtual ~ScopedWakelock();
+
+    bool isLocked() const { return mLocked; }
+
+  private:
+    friend class HalProxyCallback;
+    IScopedWakelockRefCounter* mRefCounter;
+    int64_t mCreatedAtTimeNs;
+    bool mLocked;
+    ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked);
+    ScopedWakelock(const ScopedWakelock&) = delete;
+    ScopedWakelock& operator=(const ScopedWakelock&) = delete;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h
new file mode 100644
index 0000000..92ae3a6
--- /dev/null
+++ b/sensors/2.0/multihal/include/SubHal.h
@@ -0,0 +1,170 @@
+/*
+ * 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 "ScopedWakelock.h"
+
+#include <android/hardware/sensors/1.0/types.h>
+#include <android/hardware/sensors/2.0/ISensors.h>
+
+#include <vector>
+
+// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 |
+// (HAL minor version) << 16 | (multiHAL version)
+#define SUB_HAL_2_0_VERSION 0x02000000
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+
+/**
+ * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor
+ * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure
+ * callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient
+ * manner.
+ */
+class IHalProxyCallback : public ISensorsCallback {
+  public:
+    /**
+     * Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this
+     * whenever new sensor events need to be delivered to the sensors framework. Once invoked, the
+     * HalProxy will attempt to send events to the sensors framework using a blocking write with a
+     * 5 second timeout. This write may be done asynchronously if the queue used to communicate
+     * with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the
+     * write fails, the events will be dropped and any wake locks held will be released.
+     *
+     * The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's
+     * not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant
+     * with the sensors HAL 2.0 specification. Additionally, since ScopedWakelock isn't copyable,
+     * the HalProxy will take ownership of the wake lock given when this method is invoked. Once the
+     * method returns, the HalProxy will handle holding the wake lock, if necessary, until the
+     * framework has successfully processed any wakeup events.
+     *
+     * No return type is used for this callback to avoid sub-HALs trying to resend events when
+     * writes fail. Writes should only fail when the framework is under inordinate stress which will
+     * likely result in a framework restart so retrying will likely only result in overloading the
+     * HalProxy. Sub-HALs should always assume that the write was a success and perform any
+     * necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and
+     * bug reports) it encounters during delivery to ensure it's obvious that a failure occurred.
+     *
+     * @param events the events that should be sent to the sensors framework
+     * @param wakelock ScopedWakelock that should be locked to send events from wake sensors and
+     *     unlocked otherwise.
+     */
+    virtual void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) = 0;
+
+    /**
+     * Initializes a ScopedWakelock on the stack that, when locked, will increment the reference
+     * count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class
+     * definition for how it should be used.
+     *
+     * @param lock whether the ScopedWakelock should be locked before it's returned.
+     * @return the created ScopedWakelock
+     */
+    virtual ScopedWakelock createScopedWakelock(bool lock) = 0;
+};
+
+/**
+ * ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with
+ * multihal 2.0 and in order for the HalProxy to successfully load and communicate with the sub-HAL.
+ *
+ * Any vendor wishing to implement this interface and support multihal 2.0 will need to create a
+ * dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by
+ * the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's
+ * implementation of sensorsHalGetSubHal.
+ *
+ * With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec.
+ * Any sensor handles given to the HalProxy, either through getSensorsList() or the
+ * onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL
+ * handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and
+ * sub-HALs can continue to use the lower 3 bytes of the handle.
+ */
+class ISensorsSubHal : public ISensors {
+  public:
+    // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement
+    // the version below to allow communciation logic to centralized in the HalProxy
+    Return<Result> initialize(
+            const ::android::hardware::MQDescriptorSync<Event>& /* eventQueueDescriptor */,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& /* wakeLockDescriptor */,
+            const sp<ISensorsCallback>& /* sensorsCallback */) final {
+        return Result::INVALID_OPERATION;
+    }
+
+    /**
+     * Method defined in ::android::hidl::base::V1_0::IBase.
+     *
+     * This method should write debug information to hidl_handle that is useful for debugging
+     * issues. Suggestions include:
+     * - Sensor info including handle values and any other state available in the SensorInfo class
+     * - List of active sensors and their current sampling period and reporting latency
+     * - Information about pending flush requests
+     * - Current operating mode
+     * - Currently registered direct channel info
+     * - A history of any of the above
+     */
+    virtual Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) = 0;
+
+    /**
+     * @return A human-readable name for use in wake locks and logging.
+     */
+    virtual const std::string getName() = 0;
+
+    /**
+     * This is the first method invoked on the sub-HAL after it's allocated through
+     * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and
+     * retain the callback given in order to communicate with the HalProxy. Method will be called
+     * anytime the sensors framework restarts. Therefore, this method will be responsible for
+     * reseting the state of the subhal and cleaning up and reallocating any previously allocated
+     * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state
+     * as well.
+     *
+     * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state
+     *     changes, new sensor events should be sent to the framework, and when a new ScopedWakelock
+     *     should be created.
+     * @return result OK on success
+     */
+    virtual Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) = 0;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+using ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
+
+/**
+ * Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic
+ * library. This function will only be invoked once at initialization time.
+ *
+ * NOTE: The supported sensors HAL version must match SUB_HAL_2_0_VERSION exactly or the HalProxy
+ * will fail to initialize.
+ *
+ * @param uint32_t when this function returns, this parameter must contain the HAL version that
+ *     this sub-HAL supports. To support this version of multi-HAL, this must be set to
+ *     SUB_HAL_2_0_VERSION.
+ * @return A statically allocated, valid ISensorsSubHal implementation.
+ */
+__attribute__((visibility("default"))) extern "C" ISensorsSubHal* sensorsHalGetSubHal(
+        uint32_t* version);
diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp
new file mode 100644
index 0000000..ef77048
--- /dev/null
+++ b/sensors/2.0/multihal/service.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 <android/hardware/sensors/2.0/ISensors.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include "HalProxy.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::sensors::V2_0::ISensors;
+using android::hardware::sensors::V2_0::implementation::HalProxy;
+
+int main(int /* argc */, char** /* argv */) {
+    configureRpcThreadpool(1, true);
+
+    android::sp<ISensors> halProxy = new HalProxy();
+    if (halProxy->registerAsService() != ::android::OK) {
+        ALOGE("Failed to register Sensors HAL instance");
+        return -1;
+    }
+
+    joinRpcThreadpool();
+    return 1;  // joinRpcThreadpool shouldn't exit
+}
diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp
new file mode 100644
index 0000000..1637312
--- /dev/null
+++ b/sensors/2.0/multihal/tests/Android.bp
@@ -0,0 +1,101 @@
+//
+// 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_defaults {
+    name: "android.hardware.sensors@2.0-fakesubhal-defaults",
+    srcs: [
+        "fake_subhal/*.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+    export_include_dirs: ["fake_subhal"],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+	"android.hardware.sensors@2.0-ScopedWakelock",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.sensors@2.0-HalProxy",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"FakeSubHal\""
+    ],
+}
+
+cc_library {
+    name: "android.hardware.sensors@2.0-fakesubhal-config1",
+    vendor: true,
+    defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+    cflags: [
+        "-DSUPPORT_CONTINUOUS_SENSORS",
+        "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"",
+    ],
+}
+
+cc_library {
+    name: "android.hardware.sensors@2.0-fakesubhal-config2",
+    vendor: true,
+    defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+    cflags: [
+        "-DSUPPORT_ON_CHANGE_SENSORS",
+        "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"",
+    ],
+}
+
+cc_test_library {
+    name: "android.hardware.sensors@2.0-fakesubhal-unittest",
+    vendor_available: true,
+    defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+    cflags: [
+        "-DSUPPORT_ON_CHANGE_SENSORS",
+        "-DSUPPORT_CONTINUOUS_SENSORS",
+        "-DSUB_HAL_NAME=\"FakeSubHal-Test\"",
+    ],
+}
+
+cc_test {
+    name: "android.hardware.sensors@2.0-halproxy-unit-tests",
+    srcs: ["HalProxy_test.cpp"],
+    vendor: true,
+    static_libs: [
+        "android.hardware.sensors@2.0-HalProxy",
+        "android.hardware.sensors@2.0-fakesubhal-unittest",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.0-ScopedWakelock",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    test_suites: ["device-tests"],
+    cflags: [
+        "-DLOG_TAG=\"HalProxyUnitTests\"",
+    ],
+}
diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp
new file mode 100644
index 0000000..1fd35d1
--- /dev/null
+++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp
@@ -0,0 +1,833 @@
+//
+// 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 <gtest/gtest.h>
+
+#include <android/hardware/sensors/2.0/types.h>
+#include <fmq/MessageQueue.h>
+
+#include "HalProxy.h"
+#include "ScopedWakelock.h"
+#include "SensorsSubHal.h"
+
+#include <chrono>
+#include <set>
+#include <thread>
+#include <vector>
+
+namespace {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Return;
+using ::android::hardware::sensors::V1_0::EventPayload;
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::ISensorsCallback;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::HalProxy;
+using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback;
+using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+        AllSupportDirectChannelSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+        DoesNotSupportDirectChannelSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+        SetOperationModeFailingSensorsSubHal;
+
+using EventMessageQueue = MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite>;
+using WakeupMessageQueue = MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite>;
+
+// The barebones sensors callback class passed into halproxy initialize calls
+class SensorsCallback : public ISensorsCallback {
+  public:
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo>& /*dynamicSensorsAdded*/) override {
+        // Nothing yet
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& /*dynamicSensorHandlesRemoved*/) override {
+        // Nothing yet
+        return Return<void>();
+    }
+};
+
+// The sensors callback that expects a variable list of sensors to be added
+class TestSensorsCallback : public ISensorsCallback {
+  public:
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+        mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(),
+                                 dynamicSensorsAdded.end());
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+        mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(),
+                                          dynamicSensorHandlesRemoved.begin(),
+                                          dynamicSensorHandlesRemoved.end());
+        return Return<void>();
+    }
+
+    const std::vector<SensorInfo>& getSensorsConnected() const { return mSensorsConnected; }
+    const std::vector<int32_t>& getSensorHandlesDisconnected() const {
+        return mSensorHandlesDisconnected;
+    }
+
+  private:
+    std::vector<SensorInfo> mSensorsConnected;
+    std::vector<int32_t> mSensorHandlesDisconnected;
+};
+
+// Helper declarations follow
+
+/**
+ * Tests that for each SensorInfo object from a proxy getSensorsList call each corresponding
+ * object from a subhal getSensorsList call has the same type and its last 3 bytes are the
+ * same for sensorHandle field.
+ *
+ * @param proxySensorsList The list of SensorInfo objects from the proxy.getSensorsList callback.
+ * @param subHalSenosrsList The list of SensorInfo objects from the subHal.getSensorsList callback.
+ */
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+                                       const std::vector<SensorInfo>& subHalSensorsList);
+
+/**
+ * Tests that there is exactly one subhal that allows its sensors to have direct channel enabled.
+ * Therefore, all SensorInfo objects that are not from the enabled subhal should be disabled for
+ * direct channel.
+ *
+ * @param sensorsList The SensorInfo object list from proxy.getSensorsList call.
+ * @param enabledSubHalIndex The index of the subhal in the halproxy that is expected to be
+ *     enabled.
+ */
+void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
+                                                     size_t enabledSubHalIndex);
+
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+                               EventFlag* wakelockQueueFlag);
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
+                          EventFlag* eventQueueFlag);
+
+std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size);
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size);
+
+/**
+ * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
+ *    which is a wakeup type sensor.
+ *
+ * @return A proximity event.
+ */
+Event makeProximityEvent();
+
+/**
+ * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
+ *    which is a wakeup type sensor.
+ *
+ * @return A proximity event.
+ */
+Event makeAccelerometerEvent();
+
+/**
+ * Make a certain number of proximity type events with the sensorHandle field set to
+ * the proper number for AllSensorsSubHal subhal type.
+ *
+ * @param numEvents The number of events to make.
+ *
+ * @return The created list of events.
+ */
+std::vector<Event> makeMultipleProximityEvents(size_t numEvents);
+
+/**
+ * Make a certain number of accelerometer type events with the sensorHandle field set to
+ * the proper number for AllSensorsSubHal subhal type.
+ *
+ * @param numEvents The number of events to make.
+ *
+ * @return The created list of events.
+ */
+std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents);
+
+/**
+ * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo
+ * objects that have the sensorHandle property set to int32_ts from start to start + size
+ * (exclusive) and push those sensorHandles also onto 'sensorHandles'.
+ *
+ * @param start The starting sensorHandle value.
+ * @param size The ending (not included) sensorHandle value.
+ * @param sensors The SensorInfo object vector reference to push_back to.
+ * @param sensorHandles The sensor handles int32_t vector reference to push_back to.
+ */
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+                                                  std::vector<SensorInfo>& sensors,
+                                                  std::vector<int32_t>& sensorHandles);
+
+// Tests follow
+TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal};
+    HalProxy proxy(fakeSubHals);
+
+    proxy.getSensorsList([&](const auto& proxySensorsList) {
+        subHal.getSensorsList([&](const auto& subHalSensorsList) {
+            testSensorsListFromProxyAndSubHal(proxySensorsList, subHalSensorsList);
+        });
+    });
+}
+
+TEST(HalProxyTest, GetSensorsListTwoSubHalTest) {
+    ContinuousSensorsSubHal continuousSubHal;
+    OnChangeSensorsSubHal onChangeSubHal;
+    std::vector<ISensorsSubHal*> fakeSubHals;
+    fakeSubHals.push_back(&continuousSubHal);
+    fakeSubHals.push_back(&onChangeSubHal);
+    HalProxy proxy(fakeSubHals);
+
+    std::vector<SensorInfo> proxySensorsList, combinedSubHalSensorsList;
+
+    proxy.getSensorsList([&](const auto& list) { proxySensorsList = list; });
+    continuousSubHal.getSensorsList([&](const auto& list) {
+        combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+    });
+    onChangeSubHal.getSensorsList([&](const auto& list) {
+        combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+    });
+
+    testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList);
+}
+
+TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) {
+    ContinuousSensorsSubHal subHal1;
+    OnChangeSensorsSubHal subHal2;
+
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+    HalProxy proxy(fakeSubHals);
+
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+
+    Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+    EXPECT_EQ(result, Result::OK);
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::DATA_INJECTION);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::DATA_INJECTION);
+}
+
+TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) {
+    AllSensorsSubHal subHal1;
+    SetOperationModeFailingSensorsSubHal subHal2;
+
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+    HalProxy proxy(fakeSubHals);
+
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+
+    Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+    EXPECT_NE(result, Result::OK);
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+}
+
+TEST(HalProxyTest, InitDirectChannelTwoSubHalsUnitTest) {
+    AllSupportDirectChannelSensorsSubHal subHal1;
+    AllSupportDirectChannelSensorsSubHal subHal2;
+
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+    HalProxy proxy(fakeSubHals);
+
+    proxy.getSensorsList([&](const auto& sensorsList) {
+        testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0);
+    });
+}
+
+TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) {
+    DoesNotSupportDirectChannelSensorsSubHal subHal1;
+    AllSupportDirectChannelSensorsSubHal subHal2, subHal3;
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2, &subHal3};
+    HalProxy proxy(fakeSubHals);
+
+    proxy.getSensorsList([&](const auto& sensorsList) {
+        testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1);
+    });
+}
+
+TEST(HalProxyTest, PostSingleNonWakeupEvent) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events{makeAccelerometerEvent()};
+    subHal.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), 1);
+}
+
+TEST(HalProxyTest, PostMultipleNonWakeupEvent) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 3;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+}
+
+TEST(HalProxyTest, PostSingleWakeupEvent) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    EventFlag* eventQueueFlag;
+    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+    EventFlag* wakelockQueueFlag;
+    EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
+    std::vector<Event> events{makeProximityEvent()};
+    subHal.postEvents(events, true /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), 1);
+
+    readEventsOutOfQueue(1, eventQueue, eventQueueFlag);
+    ackWakeupEventsToHalProxy(1, wakeLockQueue, wakelockQueueFlag);
+}
+
+TEST(HalProxyTest, PostMultipleWakeupEvents) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 3;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    EventFlag* eventQueueFlag;
+    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+    EventFlag* wakelockQueueFlag;
+    EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
+    std::vector<Event> events = makeMultipleProximityEvents(kNumEvents);
+    subHal.postEvents(events, true /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+    readEventsOutOfQueue(kNumEvents, eventQueue, eventQueueFlag);
+    ackWakeupEventsToHalProxy(kNumEvents, wakeLockQueue, wakelockQueueFlag);
+}
+
+TEST(HalProxyTest, PostEventsMultipleSubhals) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 2;
+    AllSensorsSubHal subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal1.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+    subHal2.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+TEST(HalProxyTest, PostEventsDelayedWrite) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 6;
+    AllSensorsSubHal subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    EventFlag* eventQueueFlag;
+    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal1.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
+
+    // readblock a full queue size worth of events out of queue, timeout for half a second
+    EXPECT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
+
+    // proxy background thread should have wrote remaining events when it saw space
+    EXPECT_TRUE(readEventsOutOfQueue(kNumEvents - kQueueSize, eventQueue, eventQueueFlag));
+
+    EXPECT_EQ(eventQueue->availableToRead(), 0);
+}
+
+TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 2;
+    AllSensorsSubHal subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+
+    std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false);
+    std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false);
+
+    t1.join();
+    t2.join();
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 6;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal.postEvents(events, false /* wakeup */);
+
+    // Destructing HalProxy object with events on the background thread
+}
+
+TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events{makeProximityEvent()};
+    subHal.postEvents(events, true /* wakeup */);
+
+    // Not sending any acks back through wakeLockQueue
+
+    // Destructing HalProxy object with unacked wakeup events posted
+}
+
+TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 10;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal.postEvents(events, false /* wakeup */);
+
+    eventQueue = makeEventFMQ(kQueueSize);
+    wakeLockQueue = makeWakelockFMQ(kQueueSize);
+
+    Result secondInitResult =
+            proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+    EXPECT_EQ(secondInitResult, Result::OK);
+    // Small sleep so that pending writes thread has a change to hit writeBlocking call.
+    std::this_thread::sleep_for(std::chrono::milliseconds(5));
+    Event eventOut;
+    EXPECT_FALSE(eventQueue->read(&eventOut));
+}
+
+TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events{makeProximityEvent()};
+    subHal.postEvents(events, true /* wakeup */);
+
+    // Not sending any acks back through wakeLockQueue
+
+    eventQueue = makeEventFMQ(kQueueSize);
+    wakeLockQueue = makeWakelockFMQ(kQueueSize);
+
+    Result secondInitResult =
+            proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+    EXPECT_EQ(secondInitResult, Result::OK);
+}
+
+TEST(HalProxyTest, InitializeManyTimesInARow) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumTimesToInit = 100;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+
+    for (size_t i = 0; i < kNumTimesToInit; i++) {
+        Result secondInitResult =
+                proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+        EXPECT_EQ(secondInitResult, Result::OK);
+    }
+}
+
+TEST(HalProxyTest, OperationModeResetOnInitialize) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.setOperationMode(OperationMode::DATA_INJECTION);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+    Event event = makeAccelerometerEvent();
+    // Should not be able to inject a non AdditionInfo type event because operation mode should
+    // have been reset to NORMAL
+    EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
+}
+
+TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumSensors = 5;
+    AddAndRemoveDynamicSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    HalProxy proxy(subHals);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToAttemptToRemove;
+    makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToAttemptToRemove);
+
+    std::vector<int32_t> nonDynamicSensorHandles;
+    for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+        nonDynamicSensorHandles.push_back(sensorHandle);
+    }
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallback> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(sensorsToConnect);
+
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+    std::vector<int32_t> sensorHandlesActuallyRemoved = callback->getSensorHandlesDisconnected();
+
+    // Should not have received the sensorHandles for any dynamic sensors that were removed since
+    // all of them should have been removed in the second initialize call.
+    EXPECT_TRUE(sensorHandlesActuallyRemoved.empty());
+}
+
+TEST(HalProxyTest, DynamicSensorsConnectedTest) {
+    constexpr size_t kNumSensors = 3;
+    AddAndRemoveDynamicSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToExpect;
+    makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToExpect);
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallback> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(sensorsToConnect);
+
+    std::vector<SensorInfo> sensorsSeen = callback->getSensorsConnected();
+    EXPECT_EQ(kNumSensors, sensorsSeen.size());
+    for (size_t i = 0; i < kNumSensors; i++) {
+        auto sensorHandleSeen = sensorsSeen[i].sensorHandle;
+        // Note since only one subhal we do not need to change first byte for expected
+        auto sensorHandleExpected = sensorHandlesToExpect[i];
+        EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
+    }
+}
+
+TEST(HalProxyTest, DynamicSensorsDisconnectedTest) {
+    constexpr size_t kNumSensors = 3;
+    AddAndRemoveDynamicSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToExpect;
+    makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToExpect);
+
+    std::vector<int32_t> nonDynamicSensorHandles;
+    for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+        nonDynamicSensorHandles.push_back(sensorHandle);
+    }
+
+    std::set<int32_t> nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(),
+                                                 nonDynamicSensorHandles.end());
+
+    std::vector<int32_t> sensorHandlesToAttemptToRemove;
+    sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+                                          sensorHandlesToExpect.begin(),
+                                          sensorHandlesToExpect.end());
+    sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+                                          nonDynamicSensorHandles.begin(),
+                                          nonDynamicSensorHandles.end());
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallback> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(sensorsToConnect);
+    subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+    std::vector<int32_t> sensorHandlesSeen = callback->getSensorHandlesDisconnected();
+    EXPECT_EQ(kNumSensors, sensorHandlesSeen.size());
+    for (size_t i = 0; i < kNumSensors; i++) {
+        auto sensorHandleSeen = sensorHandlesSeen[i];
+        // Note since only one subhal we do not need to change first byte for expected
+        auto sensorHandleExpected = sensorHandlesToExpect[i];
+        EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
+        EXPECT_TRUE(nonDynamicSensorHandlesSet.find(sensorHandleSeen) ==
+                    nonDynamicSensorHandlesSet.end());
+    }
+}
+
+TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) {
+    constexpr size_t kNumSubHals = 3;
+    constexpr size_t kQueueSize = 5;
+    int32_t kNumSubHalsInt32 = static_cast<int32_t>(kNumSubHals);
+    std::vector<AllSensorsSubHal> subHalObjs(kNumSubHals);
+    std::vector<ISensorsSubHal*> subHals;
+    for (const auto& subHal : subHalObjs) {
+        subHals.push_back((ISensorsSubHal*)(&subHal));
+    }
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    // Initialize for the injectSensorData call so callback postEvents is valid
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    // For testing proxy.injectSensorData properly
+    proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+    // kNumSubHalsInt32 index is one off the end of mSubHalList in proxy object
+    EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE);
+    EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE);
+    EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE);
+    Event event;
+    event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24);
+    EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
+}
+
+TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) {
+    constexpr size_t kQueueSize = 5;
+    constexpr int32_t subhal1Index = 0;
+    constexpr int32_t subhal2Index = 1;
+    AllSensorsSubHal subhal1;
+    AllSensorsSubHal subhal2;
+    std::vector<ISensorsSubHal*> subHals{&subhal1, &subhal2};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    int32_t sensorHandleToPost = 0x00000001;
+    Event eventIn = makeAccelerometerEvent();
+    eventIn.sensorHandle = sensorHandleToPost;
+    std::vector<Event> eventsToPost{eventIn};
+    subhal1.postEvents(eventsToPost, false);
+
+    Event eventOut;
+    EXPECT_TRUE(eventQueue->read(&eventOut));
+
+    EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost);
+
+    subhal2.postEvents(eventsToPost, false);
+
+    EXPECT_TRUE(eventQueue->read(&eventOut));
+
+    EXPECT_EQ(eventOut.sensorHandle, (subhal2Index << 24) | sensorHandleToPost);
+}
+
+// Helper implementations follow
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+                                       const std::vector<SensorInfo>& subHalSensorsList) {
+    EXPECT_EQ(proxySensorsList.size(), subHalSensorsList.size());
+
+    for (size_t i = 0; i < proxySensorsList.size(); i++) {
+        const SensorInfo& proxySensor = proxySensorsList[i];
+        const SensorInfo& subHalSensor = subHalSensorsList[i];
+
+        EXPECT_EQ(proxySensor.type, subHalSensor.type);
+        EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle);
+    }
+}
+
+void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
+                                                     size_t enabledSubHalIndex) {
+    for (const SensorInfo& sensor : sensorsList) {
+        size_t subHalIndex = static_cast<size_t>(sensor.sensorHandle >> 24);
+        if (subHalIndex == enabledSubHalIndex) {
+            // First subhal should have been picked as the direct channel subhal
+            // and so have direct channel enabled on all of its sensors
+            EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
+            EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
+        } else {
+            // All other subhals should have direct channel disabled for all sensors
+            EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
+            EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
+        }
+    }
+}
+
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+                               EventFlag* wakelockQueueFlag) {
+    uint32_t numEventsUInt32 = static_cast<uint32_t>(numEvents);
+    wakelockQueue->write(&numEventsUInt32);
+    wakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+}
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
+                          EventFlag* eventQueueFlag) {
+    constexpr int64_t kReadBlockingTimeout = INT64_C(500000000);
+    std::vector<Event> events(numEvents);
+    return eventQueue->readBlocking(events.data(), numEvents,
+                                    static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+                                    static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+                                    kReadBlockingTimeout, eventQueueFlag);
+}
+
+std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size) {
+    return std::make_unique<EventMessageQueue>(size, true);
+}
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size) {
+    return std::make_unique<WakeupMessageQueue>(size, true);
+}
+
+Event makeProximityEvent() {
+    Event event;
+    event.timestamp = 0xFF00FF00;
+    // This is the sensorhandle of proximity, which is wakeup type
+    event.sensorHandle = 0x00000008;
+    event.sensorType = SensorType::PROXIMITY;
+    event.u = EventPayload();
+    return event;
+}
+
+Event makeAccelerometerEvent() {
+    Event event;
+    event.timestamp = 0xFF00FF00;
+    // This is the sensorhandle of proximity, which is wakeup type
+    event.sensorHandle = 0x00000001;
+    event.sensorType = SensorType::ACCELEROMETER;
+    event.u = EventPayload();
+    return event;
+}
+
+std::vector<Event> makeMultipleProximityEvents(size_t numEvents) {
+    std::vector<Event> events;
+    for (size_t i = 0; i < numEvents; i++) {
+        events.push_back(makeProximityEvent());
+    }
+    return events;
+}
+
+std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents) {
+    std::vector<Event> events;
+    for (size_t i = 0; i < numEvents; i++) {
+        events.push_back(makeAccelerometerEvent());
+    }
+    return events;
+}
+
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+                                                  std::vector<SensorInfo>& sensors,
+                                                  std::vector<int32_t>& sensorHandles) {
+    for (int32_t sensorHandle = start; sensorHandle < start + static_cast<int32_t>(size);
+         sensorHandle++) {
+        SensorInfo sensor;
+        // Just set the sensorHandle field to the correct value so as to not have
+        // to compare every field
+        sensor.sensorHandle = sensorHandle;
+        sensors.push_back(sensor);
+        sensorHandles.push_back(sensorHandle);
+    }
+}
+
+}  // namespace
diff --git a/sensors/2.0/multihal/tests/fake_subhal/README b/sensors/2.0/multihal/tests/fake_subhal/README
new file mode 100644
index 0000000..ddcc584
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/README
@@ -0,0 +1,19 @@
+This directory contains a modified version of the default implementation
+provided for sensors HAL 2.0 to support multi-HAL 2.0. It should be used as a
+means to verify the multi-HAL 2.0 implementation can successfully load and
+interact with sub-HALs.
+
+This sub-HAL implementation has two macros that can be used to configure support
+for different sets of sensors. One "SUPPORT_CONTINUOUS_SENSORS", enables
+support for continuous sensors like accel, and gyro whereas the other
+"SUPPORT_ON_CHANGE_SENSORS" enables support for on change sensors like the
+light and proximity sensor. A build target is defined for each of these macros,
+but more targets could be added to support both in one sub-HAL or none at all,
+if necessary.
+
+When built, the library will be written to
+out/target/product/<device>/vendor/lib64/android.hardware.sensors@2.0-fakesubhal.so
+
+Take this .so and place it where the multi-HAL config will cause the HalProxy to
+look and then restart the system server with adb shell stop / adb shell start
+to cause the multi-HAL to restart and attempt to load in the sub-HAL.
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
new file mode 100644
index 0000000..de89a00
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
@@ -0,0 +1,349 @@
+/*
+ * 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 "Sensor.h"
+
+#include <hardware/sensors.h>
+#include <utils/SystemClock.h>
+
+#include <cmath>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::MetaDataEventType;
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorStatus;
+
+Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : mIsEnabled(false),
+      mSamplingPeriodNs(0),
+      mLastSampleTimeNs(0),
+      mCallback(callback),
+      mMode(OperationMode::NORMAL) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    constexpr float kDefaultMaxDelayUs = 1000 * 1000;
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = 0;
+    mRunThread = std::thread(startThread, this);
+}
+
+Sensor::~Sensor() {
+    // Ensure that lock is unlocked before calling mRunThread.join() or a
+    // deadlock will occur.
+    {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mStopThread = true;
+        mIsEnabled = false;
+        mWaitCV.notify_all();
+    }
+    mRunThread.join();
+}
+
+const SensorInfo& Sensor::getSensorInfo() const {
+    return mSensorInfo;
+}
+
+void Sensor::batch(int32_t samplingPeriodNs) {
+    samplingPeriodNs =
+            std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000);
+
+    if (mSamplingPeriodNs != samplingPeriodNs) {
+        mSamplingPeriodNs = samplingPeriodNs;
+        // Wake up the 'run' thread to check if a new event should be generated now
+        mWaitCV.notify_all();
+    }
+}
+
+void Sensor::activate(bool enable) {
+    if (mIsEnabled != enable) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mIsEnabled = enable;
+        mWaitCV.notify_all();
+    }
+}
+
+Result Sensor::flush() {
+    // Only generate a flush complete event if the sensor is enabled and if the sensor is not a
+    // one-shot sensor.
+    if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) {
+        return Result::BAD_VALUE;
+    }
+
+    // Note: If a sensor supports batching, write all of the currently batched events for the sensor
+    // to the Event FMQ prior to writing the flush complete event.
+    Event ev;
+    ev.sensorHandle = mSensorInfo.sensorHandle;
+    ev.sensorType = SensorType::META_DATA;
+    ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
+    std::vector<Event> evs{ev};
+    mCallback->postEvents(evs, isWakeUpSensor());
+
+    return Result::OK;
+}
+
+void Sensor::startThread(Sensor* sensor) {
+    sensor->run();
+}
+
+void Sensor::run() {
+    std::unique_lock<std::mutex> runLock(mRunMutex);
+    constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
+
+    while (!mStopThread) {
+        if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
+            mWaitCV.wait(runLock, [&] {
+                return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
+            });
+        } else {
+            timespec curTime;
+            clock_gettime(CLOCK_REALTIME, &curTime);
+            int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
+            int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+
+            if (now >= nextSampleTime) {
+                mLastSampleTimeNs = now;
+                nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+                mCallback->postEvents(readEvents(), isWakeUpSensor());
+            }
+
+            mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
+        }
+    }
+}
+
+bool Sensor::isWakeUpSensor() {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+}
+
+std::vector<Event> Sensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 0;
+    event.u.vec3.z = 0;
+    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+    events.push_back(event);
+    return events;
+}
+
+void Sensor::setOperationMode(OperationMode mode) {
+    if (mMode != mode) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mMode = mode;
+        mWaitCV.notify_all();
+    }
+}
+
+bool Sensor::supportsDataInjection() const {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
+}
+
+Result Sensor::injectEvent(const Event& event) {
+    Result result = Result::OK;
+    if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+        // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
+        // environment data into the device.
+    } else if (!supportsDataInjection()) {
+        result = Result::INVALID_OPERATION;
+    } else if (mMode == OperationMode::DATA_INJECTION) {
+        mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
+    } else {
+        result = Result::BAD_VALUE;
+    }
+    return result;
+}
+
+OnChangeSensor::OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : Sensor(sensorHandle, callback), mPreviousEventSet(false) {
+    mSensorInfo.flags |= SensorFlagBits::ON_CHANGE_MODE;
+}
+
+void OnChangeSensor::activate(bool enable) {
+    Sensor::activate(enable);
+    if (!enable) {
+        mPreviousEventSet = false;
+    }
+}
+
+std::vector<Event> OnChangeSensor::readEvents() {
+    std::vector<Event> events = Sensor::readEvents();
+    std::vector<Event> outputEvents;
+
+    for (auto iter = events.begin(); iter != events.end(); ++iter) {
+        Event ev = *iter;
+        if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) {
+            outputEvents.push_back(ev);
+            mPreviousEvent = ev;
+            mPreviousEventSet = true;
+        }
+    }
+    return outputEvents;
+}
+
+ContinuousSensor::ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : Sensor(sensorHandle, callback) {
+    mSensorInfo.flags |= SensorFlagBits::CONTINUOUS_MODE;
+}
+
+AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Accel Sensor";
+    mSensorInfo.type = SensorType::ACCELEROMETER;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_ACCELEROMETER;
+    mSensorInfo.maxRange = 78.4f;  // +/- 8g
+    mSensorInfo.resolution = 1.52e-5;
+    mSensorInfo.power = 0.001f;        // mA
+    mSensorInfo.minDelay = 20 * 1000;  // microseconds
+    mSensorInfo.flags |= SensorFlagBits::DATA_INJECTION;
+}
+
+std::vector<Event> AccelSensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 0;
+    event.u.vec3.z = -9.815;
+    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+    events.push_back(event);
+    return events;
+}
+
+PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Pressure Sensor";
+    mSensorInfo.type = SensorType::PRESSURE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PRESSURE;
+    mSensorInfo.maxRange = 1100.0f;     // hPa
+    mSensorInfo.resolution = 0.005f;    // hPa
+    mSensorInfo.power = 0.001f;         // mA
+    mSensorInfo.minDelay = 100 * 1000;  // microseconds
+}
+
+MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Magnetic Field Sensor";
+    mSensorInfo.type = SensorType::MAGNETIC_FIELD;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_MAGNETIC_FIELD;
+    mSensorInfo.maxRange = 1300.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;        // mA
+    mSensorInfo.minDelay = 20 * 1000;  // microseconds
+}
+
+LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Light Sensor";
+    mSensorInfo.type = SensorType::LIGHT;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_LIGHT;
+    mSensorInfo.maxRange = 43000.0f;
+    mSensorInfo.resolution = 10.0f;
+    mSensorInfo.power = 0.001f;         // mA
+    mSensorInfo.minDelay = 200 * 1000;  // microseconds
+}
+
+ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Proximity Sensor";
+    mSensorInfo.type = SensorType::PROXIMITY;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PROXIMITY;
+    mSensorInfo.maxRange = 5.0f;
+    mSensorInfo.resolution = 1.0f;
+    mSensorInfo.power = 0.012f;         // mA
+    mSensorInfo.minDelay = 200 * 1000;  // microseconds
+    mSensorInfo.flags |= SensorFlagBits::WAKE_UP;
+}
+
+GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Gyro Sensor";
+    mSensorInfo.type = SensorType::GYROSCOPE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_GYROSCOPE;
+    mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
+    mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 2.5f * 1000;  // microseconds
+}
+
+std::vector<Event> GyroSensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 0;
+    event.u.vec3.z = 0;
+    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+    events.push_back(event);
+    return events;
+}
+
+AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Ambient Temp Sensor";
+    mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
+    mSensorInfo.maxRange = 80.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+}
+
+DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Device Temp Sensor";
+    mSensorInfo.type = SensorType::TEMPERATURE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE;
+    mSensorInfo.maxRange = 80.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+}
+
+RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
+                                               ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Relative Humidity Sensor";
+    mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
+    mSensorInfo.maxRange = 100.0f;
+    mSensorInfo.resolution = 0.1f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+}
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
new file mode 100644
index 0000000..60f5d3d
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
@@ -0,0 +1,157 @@
+/*
+ * 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 <android/hardware/sensors/1.0/types.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+class ISensorsEventCallback {
+  public:
+    virtual ~ISensorsEventCallback(){};
+    virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
+};
+
+class Sensor {
+  public:
+    Sensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+    virtual ~Sensor();
+
+    const SensorInfo& getSensorInfo() const;
+    void batch(int32_t samplingPeriodNs);
+    virtual void activate(bool enable);
+    Result flush();
+
+    void setOperationMode(OperationMode mode);
+    bool supportsDataInjection() const;
+    Result injectEvent(const Event& event);
+
+  protected:
+    void run();
+    virtual std::vector<Event> readEvents();
+    static void startThread(Sensor* sensor);
+
+    bool isWakeUpSensor();
+
+    bool mIsEnabled;
+    int64_t mSamplingPeriodNs;
+    int64_t mLastSampleTimeNs;
+    SensorInfo mSensorInfo;
+
+    std::atomic_bool mStopThread;
+    std::condition_variable mWaitCV;
+    std::mutex mRunMutex;
+    std::thread mRunThread;
+
+    ISensorsEventCallback* mCallback;
+
+    OperationMode mMode;
+};
+
+class OnChangeSensor : public Sensor {
+  public:
+    OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+    virtual void activate(bool enable) override;
+
+  protected:
+    virtual std::vector<Event> readEvents() override;
+
+  protected:
+    Event mPreviousEvent;
+    bool mPreviousEventSet;
+};
+
+class ContinuousSensor : public Sensor {
+  public:
+    ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class AccelSensor : public ContinuousSensor {
+  public:
+    AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    std::vector<Event> readEvents() override;
+};
+
+class GyroSensor : public ContinuousSensor {
+  public:
+    GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    std::vector<Event> readEvents() override;
+};
+
+class DeviceTempSensor : public ContinuousSensor {
+  public:
+    DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class PressureSensor : public ContinuousSensor {
+  public:
+    PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class MagnetometerSensor : public ContinuousSensor {
+  public:
+    MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class AmbientTempSensor : public OnChangeSensor {
+  public:
+    AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class LightSensor : public OnChangeSensor {
+  public:
+    LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class ProximitySensor : public OnChangeSensor {
+  public:
+    ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class RelativeHumiditySensor : public OnChangeSensor {
+  public:
+    RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
new file mode 100644
index 0000000..ff5ff38
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
@@ -0,0 +1,240 @@
+/*
+ * 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 "SensorsSubHal.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+#include <log/log.h>
+
+ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) {
+#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+    static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal;
+#elif defined SUPPORT_CONTINUOUS_SENSORS
+    static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal
+            subHal;
+#elif defined SUPPORT_ON_CHANGE_SENSORS
+    static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal;
+#else
+    static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal;
+#endif  // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+    *version = SUB_HAL_2_0_VERSION;
+    return &subHal;
+}
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::RateLevel;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
+
+SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {}
+
+// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+Return<void> SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        sensors.push_back(sensor.second->getSensorInfo());
+    }
+
+    _hidl_cb(sensors);
+    return Void();
+}
+
+Return<Result> SensorsSubHal::setOperationMode(OperationMode mode) {
+    for (auto sensor : mSensors) {
+        sensor.second->setOperationMode(mode);
+    }
+    mCurrentOperationMode = mode;
+    return Result::OK;
+}
+
+Return<Result> SensorsSubHal::activate(int32_t sensorHandle, bool enabled) {
+    auto sensor = mSensors.find(sensorHandle);
+    if (sensor != mSensors.end()) {
+        sensor->second->activate(enabled);
+        return Result::OK;
+    }
+    return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                                    int64_t /* maxReportLatencyNs */) {
+    auto sensor = mSensors.find(sensorHandle);
+    if (sensor != mSensors.end()) {
+        sensor->second->batch(samplingPeriodNs);
+        return Result::OK;
+    }
+    return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::flush(int32_t sensorHandle) {
+    auto sensor = mSensors.find(sensorHandle);
+    if (sensor != mSensors.end()) {
+        return sensor->second->flush();
+    }
+    return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::injectSensorData(const Event& event) {
+    auto sensor = mSensors.find(event.sensorHandle);
+    if (sensor != mSensors.end()) {
+        return sensor->second->injectEvent(event);
+    }
+
+    return Result::BAD_VALUE;
+}
+
+Return<void> SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */,
+                                                  registerDirectChannel_cb _hidl_cb) {
+    _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+    return Return<void>();
+}
+
+Return<Result> SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) {
+    return Result::INVALID_OPERATION;
+}
+
+Return<void> SensorsSubHal::configDirectReport(int32_t /* sensorHandle */,
+                                               int32_t /* channelHandle */, RateLevel /* rate */,
+                                               configDirectReport_cb _hidl_cb) {
+    _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
+    return Return<void>();
+}
+
+Return<void> SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+        ALOGE("%s: missing fd for writing", __FUNCTION__);
+        return Void();
+    }
+
+    FILE* out = fdopen(dup(fd->data[0]), "w");
+
+    if (args.size() != 0) {
+        fprintf(out,
+                "Note: sub-HAL %s currently does not support args. Input arguments are "
+                "ignored.\n",
+                getName().c_str());
+    }
+
+    std::ostringstream stream;
+    stream << "Available sensors:" << std::endl;
+    for (auto sensor : mSensors) {
+        SensorInfo info = sensor.second->getSensorInfo();
+        stream << "Name: " << info.name << std::endl;
+        stream << "Min delay: " << info.minDelay << std::endl;
+        stream << "Flags: " << info.flags << std::endl;
+    }
+    stream << std::endl;
+
+    fprintf(out, "%s", stream.str().c_str());
+
+    fclose(out);
+    return Return<void>();
+}
+
+Return<Result> SensorsSubHal::initialize(const sp<IHalProxyCallback>& halProxyCallback) {
+    mCallback = halProxyCallback;
+    setOperationMode(OperationMode::NORMAL);
+    return Result::OK;
+}
+
+void SensorsSubHal::postEvents(const std::vector<Event>& events, bool wakeup) {
+    ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup);
+    mCallback->postEvents(events, std::move(wakelock));
+}
+
+ContinuousSensorsSubHal::ContinuousSensorsSubHal() {
+    AddSensor<AccelSensor>();
+    AddSensor<GyroSensor>();
+    AddSensor<MagnetometerSensor>();
+    AddSensor<PressureSensor>();
+    AddSensor<DeviceTempSensor>();
+}
+
+OnChangeSensorsSubHal::OnChangeSensorsSubHal() {
+    AddSensor<AmbientTempSensor>();
+    AddSensor<LightSensor>();
+    AddSensor<ProximitySensor>();
+    AddSensor<RelativeHumiditySensor>();
+}
+
+AllSensorsSubHal::AllSensorsSubHal() {
+    AddSensor<AccelSensor>();
+    AddSensor<GyroSensor>();
+    AddSensor<MagnetometerSensor>();
+    AddSensor<PressureSensor>();
+    AddSensor<DeviceTempSensor>();
+    AddSensor<AmbientTempSensor>();
+    AddSensor<LightSensor>();
+    AddSensor<ProximitySensor>();
+    AddSensor<RelativeHumiditySensor>();
+}
+
+Return<Result> SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) {
+    return Result::BAD_VALUE;
+}
+
+Return<void> AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        SensorInfo sensorInfo = sensor.second->getSensorInfo();
+        sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL;
+        sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT;
+        sensors.push_back(sensorInfo);
+    }
+    _hidl_cb(sensors);
+    return Void();
+}
+
+Return<void> DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        SensorInfo sensorInfo = sensor.second->getSensorInfo();
+        sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
+        sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_REPORT);
+        sensors.push_back(sensorInfo);
+    }
+    _hidl_cb(sensors);
+    return Void();
+}
+
+void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors(
+        const std::vector<SensorInfo>& sensorsAdded) {
+    mCallback->onDynamicSensorsConnected(sensorsAdded);
+}
+
+void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors(
+        const std::vector<int32_t>& sensorHandlesRemoved) {
+    mCallback->onDynamicSensorsDisconnected(sensorHandlesRemoved);
+}
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
new file mode 100644
index 0000000..c1e3647
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
@@ -0,0 +1,165 @@
+/*
+ * 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 "SubHal.h"
+
+#include "Sensor.h"
+
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback;
+
+/**
+ * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0.
+ * See the README file for more details on how this class can be used for testing.
+ */
+class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback {
+    using Event = ::android::hardware::sensors::V1_0::Event;
+    using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
+    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+
+  public:
+    SensorsSubHal();
+
+    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+    virtual Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+
+    virtual Return<Result> setOperationMode(OperationMode mode) override;
+
+    OperationMode getOperationMode() const { return mCurrentOperationMode; }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override;
+
+    Return<Result> flush(int32_t sensorHandle) override;
+
+    Return<Result> injectSensorData(const Event& event) override;
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       registerDirectChannel_cb _hidl_cb) override;
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    configDirectReport_cb _hidl_cb) override;
+
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+    // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow.
+    const std::string getName() override {
+#ifdef SUB_HAL_NAME
+        return SUB_HAL_NAME;
+#else   // SUB_HAL_NAME
+        return "FakeSubHal";
+#endif  // SUB_HAL_NAME
+    }
+
+    Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) override;
+
+    // Method from ISensorsEventCallback.
+    void postEvents(const std::vector<Event>& events, bool wakeup) override;
+
+  protected:
+    template <class SensorType>
+    void AddSensor() {
+        std::shared_ptr<SensorType> sensor =
+                std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
+        mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
+    }
+
+    /**
+     * A map of the available sensors
+     */
+    std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
+
+    /**
+     * Callback used to communicate to the HalProxy when dynamic sensors are connected /
+     * disconnected, sensor events need to be sent to the framework, and when a wakelock should be
+     * acquired.
+     */
+    sp<IHalProxyCallback> mCallback;
+
+  private:
+    /**
+     * The current operation mode of the multihal framework. Ensures that all subhals are set to
+     * the same operation mode.
+     */
+    OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
+    /**
+     * The next available sensor handle
+     */
+    int32_t mNextHandle;
+};
+
+// SubHal that has continuous sensors for testing purposes.
+class ContinuousSensorsSubHal : public SensorsSubHal {
+  public:
+    ContinuousSensorsSubHal();
+};
+
+// SubHal that has on-change sensors for testing purposes.
+class OnChangeSensorsSubHal : public SensorsSubHal {
+  public:
+    OnChangeSensorsSubHal();
+};
+
+// SubHal that has both continuous and on-change sensors for testing purposes.
+class AllSensorsSubHal : public SensorsSubHal {
+  public:
+    AllSensorsSubHal();
+};
+
+class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal {
+  public:
+    Return<Result> setOperationMode(OperationMode mode) override;
+};
+
+class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
+  public:
+    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+};
+
+class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
+  public:
+    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+};
+
+class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal {
+  public:
+    void addDynamicSensors(const std::vector<SensorInfo>& sensorsAdded);
+    void removeDynamicSensors(const std::vector<int32_t>& sensorHandlesAdded);
+};
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/vts/functional/AndroidTest.xml b/sensors/2.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..b710ed0
--- /dev/null
+++ b/sensors/2.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,39 @@
+<?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 VtsHalSensorsV2_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.RunCommandTargetPreparer">
+        <option name="run-command" value="stop"/>
+        <option name="teardown-command" value="start"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalSensorsV2_0TargetTest->/data/local/tmp/VtsHalSensorsV2_0TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-timeout" value="900000" />
+        <option name="runtime-hint" value="300000"/>
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalSensorsV2_0TargetTest" />
+    </test>
+</configuration>
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
index 03fcc17..2071c5a 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
@@ -58,8 +58,7 @@
 bool SensorsHidlEnvironmentV2_0::resetHal() {
     bool succeed = false;
     do {
-        mSensors = ISensors::getService(
-            SensorsHidlEnvironmentV2_0::Instance()->getServiceName<ISensors>());
+        mSensors = ISensors::getService(mServiceName);
         if (mSensors == nullptr) {
             break;
         }
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
index b0dbd90..819cdd4 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
@@ -42,22 +42,12 @@
 class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase {
    public:
     using Event = ::android::hardware::sensors::V1_0::Event;
-    // get the test environment singleton
-    static SensorsHidlEnvironmentV2_0* Instance() {
-        static SensorsHidlEnvironmentV2_0* instance = new SensorsHidlEnvironmentV2_0();
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<android::hardware::sensors::V2_0::ISensors>();
-    }
-
     virtual void HidlTearDown() override;
 
    protected:
     friend SensorsHidlTest;
-
-    SensorsHidlEnvironmentV2_0() : mEventQueueFlag(nullptr) {}
+    SensorsHidlEnvironmentV2_0(const std::string& service_name)
+        : SensorsHidlEnvironmentBase(service_name), mEventQueueFlag(nullptr) {}
 
     /**
      * Resets the HAL with new FMQs and a new Event Flag
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index 8364ba9..c5eb442 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -20,6 +20,8 @@
 
 #include <android/hardware/sensors/2.0/ISensors.h>
 #include <android/hardware/sensors/2.0/types.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 #include <utils/SystemClock.h>
 
@@ -120,10 +122,14 @@
 class SensorsHidlTest : public SensorsHidlTestBase {
   public:
     virtual void SetUp() override {
+        mEnvironment = new SensorsHidlEnvironmentV2_0(GetParam());
+        mEnvironment->HidlSetUp();
         // Ensure that we have a valid environment before performing tests
         ASSERT_NE(getSensors(), nullptr);
     }
 
+    virtual void TearDown() override { mEnvironment->HidlTearDown(); }
+
   protected:
     SensorInfo defaultSensorByType(SensorType type) override;
     std::vector<SensorInfo> getSensorsList();
@@ -160,12 +166,10 @@
     }
 
     inline sp<::android::hardware::sensors::V2_0::ISensors>& getSensors() {
-        return SensorsHidlEnvironmentV2_0::Instance()->mSensors;
+        return mEnvironment->mSensors;
     }
 
-    SensorsHidlEnvironmentBase* getEnvironment() override {
-        return SensorsHidlEnvironmentV2_0::Instance();
-    }
+    SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; }
 
     // Test helpers
     void runSingleFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
@@ -191,6 +195,10 @@
     void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel);
     void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
                                    bool* supportsAnyDirectChannel);
+
+  private:
+    // Test environment for sensors HAL.
+    SensorsHidlEnvironmentV2_0* mEnvironment;
 };
 
 Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
@@ -301,7 +309,7 @@
 }
 
 // Test if sensor list returned is valid
-TEST_F(SensorsHidlTest, SensorListValid) {
+TEST_P(SensorsHidlTest, SensorListValid) {
     getSensors()->getSensorsList([&](const auto& list) {
         const size_t count = list.size();
         for (size_t i = 0; i < count; ++i) {
@@ -346,7 +354,7 @@
 }
 
 // Test that SetOperationMode returns the expected value
-TEST_F(SensorsHidlTest, SetOperationMode) {
+TEST_P(SensorsHidlTest, SetOperationMode) {
     std::vector<SensorInfo> sensors = getInjectEventSensors();
     if (getInjectEventSensors().size() > 0) {
         ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
@@ -358,7 +366,7 @@
 }
 
 // Test that an injected event is written back to the Event FMQ
-TEST_F(SensorsHidlTest, InjectSensorEventData) {
+TEST_P(SensorsHidlTest, InjectSensorEventData) {
     std::vector<SensorInfo> sensors = getInjectEventSensors();
     if (sensors.size() == 0) {
         return;
@@ -414,196 +422,196 @@
 }
 
 // Test if sensor hal can do UI speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
     testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200),
                            std::chrono::seconds(5), sAccelNormChecker);
 }
 
 // Test if sensor hal can do normal speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
     testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20),
                            std::chrono::seconds(5), sAccelNormChecker);
 }
 
 // Test if sensor hal can do game speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationFast) {
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) {
     testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5),
                            std::chrono::seconds(5), sAccelNormChecker);
 }
 
 // Test if sensor hal can do UI speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
     testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200),
                            std::chrono::seconds(5), sGyroNormChecker);
 }
 
 // Test if sensor hal can do normal speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
     testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20),
                            std::chrono::seconds(5), sGyroNormChecker);
 }
 
 // Test if sensor hal can do game speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationFast) {
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) {
     testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5),
                            std::chrono::seconds(5), sGyroNormChecker);
 }
 
 // Test if sensor hal can do UI speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
     testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200),
                            std::chrono::seconds(5), NullChecker());
 }
 
 // Test if sensor hal can do normal speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
     testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20),
                            std::chrono::seconds(5), NullChecker());
 }
 
 // Test if sensor hal can do game speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) {
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) {
     testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5),
                            std::chrono::seconds(5), NullChecker());
 }
 
 // Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+TEST_P(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
     testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
     testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/);
 }
 
 // Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
+TEST_P(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
     testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
     testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/);
 }
 
 // Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
+TEST_P(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
     testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
     testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
 }
 
 // Test if sensor hal can do accelerometer batching properly
-TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
+TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) {
     testBatchingOperation(SensorType::ACCELEROMETER);
 }
 
 // Test if sensor hal can do gyroscope batching properly
-TEST_F(SensorsHidlTest, GyroscopeBatchingOperation) {
+TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) {
     testBatchingOperation(SensorType::GYROSCOPE);
 }
 
 // Test if sensor hal can do magnetometer batching properly
-TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) {
+TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) {
     testBatchingOperation(SensorType::MAGNETIC_FIELD);
 }
 
 // Test sensor event direct report with ashmem for accel sensor at normal rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
                               sAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for accel sensor at fast rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
                               sAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for accel sensor at very fast rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM,
                               RateLevel::VERY_FAST, sAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at normal rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
                               sGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at fast rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
                               sGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at very fast rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
                               sGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for mag sensor at normal rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
                               NullChecker());
 }
 
 // Test sensor event direct report with ashmem for mag sensor at fast rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
                               NullChecker());
 }
 
 // Test sensor event direct report with ashmem for mag sensor at very fast rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM,
                               RateLevel::VERY_FAST, NullChecker());
 }
 
 // Test sensor event direct report with gralloc for accel sensor at normal rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
                               sAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for accel sensor at fast rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
                               sAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for accel sensor at very fast rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC,
                               RateLevel::VERY_FAST, sAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at normal rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
                               sGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at fast rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
                               sGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at very fast rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
                               sGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for mag sensor at normal rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
                               NullChecker());
 }
 
 // Test sensor event direct report with gralloc for mag sensor at fast rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
                               NullChecker());
 }
 
 // Test sensor event direct report with gralloc for mag sensor at very fast rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC,
                               RateLevel::VERY_FAST, NullChecker());
 }
@@ -619,9 +627,13 @@
 
 // Test that if initialize is called twice, then the HAL writes events to the FMQs from the second
 // call to the function.
-TEST_F(SensorsHidlTest, CallInitializeTwice) {
+TEST_P(SensorsHidlTest, CallInitializeTwice) {
     // Create a helper class so that a second environment is able to be instantiated
-    class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_0 {};
+    class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_0 {
+      public:
+        SensorsHidlEnvironmentTest(const std::string& service_name)
+            : SensorsHidlEnvironmentV2_0(service_name) {}
+    };
 
     if (getSensorsList().size() == 0) {
         // No sensors
@@ -633,7 +645,7 @@
 
     // Create a new environment that calls initialize()
     std::unique_ptr<SensorsHidlEnvironmentTest> newEnv =
-        std::make_unique<SensorsHidlEnvironmentTest>();
+            std::make_unique<SensorsHidlEnvironmentTest>(GetParam());
     newEnv->HidlSetUp();
     if (HasFatalFailure()) {
         return;  // Exit early if setting up the new environment failed
@@ -662,7 +674,7 @@
     activateAllSensors(false);
 }
 
-TEST_F(SensorsHidlTest, CleanupConnectionsOnInitialize) {
+TEST_P(SensorsHidlTest, CleanupConnectionsOnInitialize) {
     activateAllSensors(true);
 
     // Verify that events are received
@@ -731,7 +743,7 @@
     }
 }
 
-TEST_F(SensorsHidlTest, FlushSensor) {
+TEST_P(SensorsHidlTest, FlushSensor) {
     // Find a sensor that is not a one-shot sensor
     std::vector<SensorInfo> sensors = getNonOneShotSensors();
     if (sensors.size() == 0) {
@@ -743,7 +755,7 @@
     runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, Result::OK);
 }
 
-TEST_F(SensorsHidlTest, FlushOneShotSensor) {
+TEST_P(SensorsHidlTest, FlushOneShotSensor) {
     // Find a sensor that is a one-shot sensor
     std::vector<SensorInfo> sensors = getOneShotSensors();
     if (sensors.size() == 0) {
@@ -754,7 +766,7 @@
                        Result::BAD_VALUE);
 }
 
-TEST_F(SensorsHidlTest, FlushInactiveSensor) {
+TEST_P(SensorsHidlTest, FlushInactiveSensor) {
     // Attempt to find a non-one shot sensor, then a one-shot sensor if necessary
     std::vector<SensorInfo> sensors = getNonOneShotSensors();
     if (sensors.size() == 0) {
@@ -768,7 +780,7 @@
                        Result::BAD_VALUE);
 }
 
-TEST_F(SensorsHidlTest, FlushNonexistentSensor) {
+TEST_P(SensorsHidlTest, FlushNonexistentSensor) {
     SensorInfo sensor;
     std::vector<SensorInfo> sensors = getNonOneShotSensors();
     if (sensors.size() == 0) {
@@ -783,7 +795,7 @@
                        0 /* expectedFlushCount */, Result::BAD_VALUE);
 }
 
-TEST_F(SensorsHidlTest, Batch) {
+TEST_P(SensorsHidlTest, Batch) {
     if (getSensorsList().size() == 0) {
         return;
     }
@@ -815,7 +827,7 @@
               Result::BAD_VALUE);
 }
 
-TEST_F(SensorsHidlTest, Activate) {
+TEST_P(SensorsHidlTest, Activate) {
     if (getSensorsList().size() == 0) {
         return;
     }
@@ -841,7 +853,7 @@
     ASSERT_EQ(activate(invalidHandle, false), Result::BAD_VALUE);
 }
 
-TEST_F(SensorsHidlTest, NoStaleEvents) {
+TEST_P(SensorsHidlTest, NoStaleEvents) {
     constexpr milliseconds kFiveHundredMs(500);
     constexpr milliseconds kOneSecond(1000);
 
@@ -1021,11 +1033,11 @@
     }
 }
 
-TEST_F(SensorsHidlTest, DirectChannelAshmem) {
+TEST_P(SensorsHidlTest, DirectChannelAshmem) {
     verifyDirectChannel(SharedMemType::ASHMEM);
 }
 
-TEST_F(SensorsHidlTest, DirectChannelGralloc) {
+TEST_P(SensorsHidlTest, DirectChannelGralloc) {
     verifyDirectChannel(SharedMemType::GRALLOC);
 }
 
@@ -1064,7 +1076,7 @@
     return found;
 }
 
-TEST_F(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) {
+TEST_P(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) {
     SensorInfo sensor;
     SharedMemType memType;
     RateLevel rate;
@@ -1078,7 +1090,7 @@
     });
 }
 
-TEST_F(SensorsHidlTest, CleanupDirectConnectionOnInitialize) {
+TEST_P(SensorsHidlTest, CleanupDirectConnectionOnInitialize) {
     constexpr size_t kNumEvents = 1;
     constexpr size_t kMemSize = kNumEvents * kEventSize;
 
@@ -1124,12 +1136,8 @@
     mDirectChannelHandles = handles;
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV2_0::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    SensorsHidlEnvironmentV2_0::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 android::hardware::sensors::V2_0::ISensors::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
 // vim: set ts=2 sw=2
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index 02dc608..bb4d329 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -16,6 +16,7 @@
 
 cc_library_static {
     name: "VtsHalSensorsTargetTestUtils",
+    defaults: ["VtsHalTargetTestDefaults"],
     cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
     srcs: [
         "GrallocWrapper.cpp",
@@ -36,6 +37,5 @@
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
-        "VtsHalHidlTargetTestBase",
     ],
 }
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
index 1cad913..e63faa2 100644
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -147,8 +147,8 @@
             .width = size,
             .height = 1,
             .layerCount = 1,
-            .usage = kBufferUsage,
             .format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
+            .usage = kBufferUsage,
     };
 
     BufferDescriptor descriptor;
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
index 6499fba..dbc9392 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
@@ -17,9 +17,8 @@
 #ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
 #define ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
 
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 #include <android/hardware/sensors/1.0/types.h>
+#include <gtest/gtest.h>
 
 #include <atomic>
 #include <memory>
@@ -33,11 +32,11 @@
     virtual void onEvent(const ::android::hardware::sensors::V1_0::Event& event) = 0;
 };
 
-class SensorsHidlEnvironmentBase : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
+class SensorsHidlEnvironmentBase {
+  public:
     using Event = ::android::hardware::sensors::V1_0::Event;
-    virtual void HidlSetUp() override;
-    virtual void HidlTearDown() override;
+    virtual void HidlSetUp();
+    virtual void HidlTearDown();
 
     // Get and clear all events collected so far (like "cat" shell command).
     // If output is nullptr, it clears all collected events.
@@ -50,22 +49,27 @@
     void unregisterCallback();
 
    protected:
-    SensorsHidlEnvironmentBase() : mCollectionEnabled(false), mCallback(nullptr) {}
+     SensorsHidlEnvironmentBase(const std::string& service_name)
+         : mCollectionEnabled(false), mCallback(nullptr) {
+         mServiceName = service_name;
+     }
+     virtual ~SensorsHidlEnvironmentBase(){};
 
-    void addEvent(const Event& ev);
+     void addEvent(const Event& ev);
 
-    virtual void startPollingThread() = 0;
-    virtual bool resetHal() = 0;
+     virtual void startPollingThread() = 0;
+     virtual bool resetHal() = 0;
 
-    bool mCollectionEnabled;
-    std::atomic_bool mStopThread;
-    std::thread mPollThread;
-    std::vector<Event> mEvents;
-    std::mutex mEventsMutex;
+     std::string mServiceName;
+     bool mCollectionEnabled;
+     std::atomic_bool mStopThread;
+     std::thread mPollThread;
+     std::vector<Event> mEvents;
+     std::mutex mEventsMutex;
 
-    IEventCallback* mCallback;
+     IEventCallback* mCallback;
 
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase);
+     GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase);
 };
 
 #endif  // ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
\ No newline at end of file
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
index 6fd9a2b..5fb6c5c 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
@@ -23,6 +23,7 @@
 #include <VtsHalHidlTargetTestBase.h>
 #include <android/hardware/sensors/1.0/ISensors.h>
 #include <android/hardware/sensors/1.0/types.h>
+#include <gtest/gtest.h>
 
 #include <unordered_set>
 #include <vector>
@@ -44,8 +45,8 @@
 using ::android::hardware::sensors::V1_0::SharedMemInfo;
 using ::android::hardware::sensors::V1_0::SharedMemType;
 
-class SensorsHidlTestBase : public ::testing::VtsHalHidlTargetTestBase {
-   public:
+class SensorsHidlTestBase : public testing::TestWithParam<std::string> {
+  public:
     virtual SensorsHidlEnvironmentBase* getEnvironment() = 0;
     virtual void SetUp() override {}
 
diff --git a/soundtrigger/2.0/Android.bp b/soundtrigger/2.0/Android.bp
index b805be8..07c05bc 100644
--- a/soundtrigger/2.0/Android.bp
+++ b/soundtrigger/2.0/Android.bp
@@ -15,6 +15,5 @@
         "android.hardware.audio.common@2.0",
         "android.hidl.base@1.0",
     ],
-    gen_java: false,
+    gen_java: true,
 }
-
diff --git a/soundtrigger/2.0/ISoundTriggerHwCallback.hal b/soundtrigger/2.0/ISoundTriggerHwCallback.hal
index 90132d9..84b11c8 100644
--- a/soundtrigger/2.0/ISoundTriggerHwCallback.hal
+++ b/soundtrigger/2.0/ISoundTriggerHwCallback.hal
@@ -46,7 +46,6 @@
         int32_t           captureSession;
         /**
          * Delay in ms between end of model detection and start of audio
-        /**
          * available for capture. A negative value is possible
          * (e.g. if key phrase is also available for capture */
         int32_t           captureDelayMs;
diff --git a/soundtrigger/2.0/default/Android.bp b/soundtrigger/2.0/default/Android.bp
index cc20f91..1f9ae45 100644
--- a/soundtrigger/2.0/default/Android.bp
+++ b/soundtrigger/2.0/default/Android.bp
@@ -28,7 +28,6 @@
 
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "libhardware",
diff --git a/soundtrigger/2.0/vts/functional/Android.bp b/soundtrigger/2.0/vts/functional/Android.bp
index f6207c4..13dcdec 100644
--- a/soundtrigger/2.0/vts/functional/Android.bp
+++ b/soundtrigger/2.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalSoundtriggerV2_0TargetTest.cpp"],
     static_libs: ["android.hardware.soundtrigger@2.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
index 59ac13e..d7a7d08 100644
--- a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
+++ b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
@@ -23,15 +23,15 @@
 
 #include <android/log.h>
 #include <cutils/native_handle.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 #include <android/hardware/audio/common/2.0/types.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.0/types.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 #define SHORT_TIMEOUT_PERIOD (1)
 
 using ::android::hardware::audio::common::V2_0::AudioDevice;
@@ -86,27 +86,11 @@
   int mCount;
 };
 
-// Test environment for SoundTrigger HIDL HAL.
-class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static SoundTriggerHidlEnvironment* Instance() {
-        static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
-
-   private:
-    SoundTriggerHidlEnvironment() {}
-};
-
 // The main test class for Sound Trigger HIDL HAL.
-class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SoundTriggerHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-      mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
-          SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
+      mSoundTriggerHal = ISoundTriggerHw::getService(GetParam());
       ASSERT_NE(nullptr, mSoundTriggerHal.get());
       mCallback = new SoundTriggerHwCallback(*this);
       ASSERT_NE(nullptr, mCallback.get());
@@ -167,7 +151,7 @@
  *  - the implementation supports at least one sound model and one key phrase
  *  - the implementation supports at least VOICE_TRIGGER recognition mode
  */
-TEST_F(SoundTriggerHidlTest, GetProperties) {
+TEST_P(SoundTriggerHidlTest, GetProperties) {
   ISoundTriggerHw::Properties halProperties;
   Return<void> hidlReturn;
   int ret = -ENODEV;
@@ -194,7 +178,7 @@
  * There is no way to verify that implementation actually can load a sound model because each
  * sound model is vendor specific.
  */
-TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) {
+TEST_P(SoundTriggerHidlTest, LoadInvalidModelFail) {
   Return<void> hidlReturn;
   int ret = -ENODEV;
   ISoundTriggerHw::PhraseSoundModel model;
@@ -220,7 +204,7 @@
  * Verifies that:
  *  - the implementation returns error when passed a sound model with random data.
  */
-TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
+TEST_P(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
   int ret = -ENODEV;
   ISoundTriggerHw::SoundModel model;
   SoundModelHandle handle = 0;
@@ -251,7 +235,7 @@
  *  - the implementation returns an error when called without a valid loaded sound model
  *
  */
-TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) {
+TEST_P(SoundTriggerHidlTest, UnloadModelNoModelFail) {
   Return<int32_t> hidlReturn(0);
   SoundModelHandle halHandle = 0;
 
@@ -271,7 +255,7 @@
  * There is no way to verify that implementation actually starts recognition because no model can
  * be loaded.
  */
-TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
+TEST_P(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle handle = 0;
     PhraseRecognitionExtra phrase;
@@ -299,7 +283,7 @@
  *  - the implementation returns an error when called without an active recognition running
  *
  */
-TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
+TEST_P(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle handle = 0;
 
@@ -316,7 +300,7 @@
  *  - the implementation implements this optional method or indicates it is not support by
  *  returning -ENOSYS
  */
-TEST_F(SoundTriggerHidlTest, stopAllRecognitions) {
+TEST_P(SoundTriggerHidlTest, stopAllRecognitions) {
     Return<int32_t> hidlReturn(0);
 
     hidlReturn = mSoundTriggerHal->stopAllRecognitions();
@@ -325,11 +309,7 @@
     EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, SoundTriggerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/soundtrigger/2.1/Android.bp b/soundtrigger/2.1/Android.bp
index ed1ec3d..30173cb 100644
--- a/soundtrigger/2.1/Android.bp
+++ b/soundtrigger/2.1/Android.bp
@@ -15,6 +15,5 @@
         "android.hardware.soundtrigger@2.0",
         "android.hidl.base@1.0",
     ],
-    gen_java: false,
+    gen_java: true,
 }
-
diff --git a/soundtrigger/2.1/default/Android.mk b/soundtrigger/2.1/default/Android.mk
index 5851d63..b8d0407 100644
--- a/soundtrigger/2.1/default/Android.mk
+++ b/soundtrigger/2.1/default/Android.mk
@@ -29,7 +29,6 @@
         libhardware \
         libhidlbase \
         libhidlmemory \
-        libhidltransport \
         liblog \
         libutils \
         android.hardware.soundtrigger@2.1 \
diff --git a/soundtrigger/2.1/vts/functional/Android.bp b/soundtrigger/2.1/vts/functional/Android.bp
index f1eb35d..7830fe2 100644
--- a/soundtrigger/2.1/vts/functional/Android.bp
+++ b/soundtrigger/2.1/vts/functional/Android.bp
@@ -25,5 +25,5 @@
                  "android.hardware.soundtrigger@2.1",
                  "libhidlmemory"
                  ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
index 0a2eeac..7f06ed9 100644
--- a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
+++ b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
@@ -23,6 +23,9 @@
 
 #include <android/log.h>
 #include <cutils/native_handle.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 #include <android/hardware/audio/common/2.0/types.h>
@@ -32,9 +35,6 @@
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <hidlmemory/mapping.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 #define SHORT_TIMEOUT_PERIOD (1)
 
 using ::android::sp;
@@ -94,27 +94,11 @@
     int mCount;
 };
 
-// Test environment for SoundTrigger HIDL HAL.
-class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static SoundTriggerHidlEnvironment* Instance() {
-        static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
-
-   private:
-    SoundTriggerHidlEnvironment() {}
-};
-
 // The main test class for Sound Trigger HIDL HAL.
-class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SoundTriggerHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
-            SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
+        mSoundTriggerHal = ISoundTriggerHw::getService(GetParam());
         ASSERT_NE(nullptr, mSoundTriggerHal.get());
         mCallback = new SoundTriggerHwCallback(*this);
         ASSERT_NE(nullptr, mCallback.get());
@@ -196,7 +180,7 @@
  *  - the implementation supports at least one sound model and one key phrase
  *  - the implementation supports at least VOICE_TRIGGER recognition mode
  */
-TEST_F(SoundTriggerHidlTest, GetProperties) {
+TEST_P(SoundTriggerHidlTest, GetProperties) {
     ISoundTriggerHw::Properties halProperties;
     Return<void> hidlReturn;
     int ret = -ENODEV;
@@ -223,7 +207,7 @@
  * There is no way to verify that implementation actually can load a sound model because each
  * sound model is vendor specific.
  */
-TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) {
+TEST_P(SoundTriggerHidlTest, LoadInvalidModelFail) {
     Return<void> hidlReturn;
     int ret = -ENODEV;
     V2_0_ISoundTriggerHw::PhraseSoundModel model;
@@ -252,7 +236,7 @@
  * There is no way to verify that implementation actually can load a sound model because each
  * sound model is vendor specific.
  */
-TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail_2_1) {
+TEST_P(SoundTriggerHidlTest, LoadInvalidModelFail_2_1) {
     Return<void> hidlReturn;
     int ret = -ENODEV;
     ISoundTriggerHw::PhraseSoundModel model;
@@ -277,7 +261,7 @@
  * Verifies that:
  *  - the implementation returns an error when passed an empty sound model
  */
-TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail) {
+TEST_P(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail) {
     int ret = -ENODEV;
     V2_0_ISoundTriggerHw::SoundModel model;
     SoundModelHandle handle = 0;
@@ -301,7 +285,7 @@
  * Verifies that:
  *  - the implementation returns error when passed a sound model with random data.
  */
-TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
+TEST_P(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
     int ret = -ENODEV;
     V2_0_ISoundTriggerHw::SoundModel model;
     SoundModelHandle handle = 0;
@@ -329,7 +313,7 @@
  * Verifies that:
  *  - the implementation returns error when passed a sound model with random data.
  */
-TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail_2_1) {
+TEST_P(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail_2_1) {
     int ret = -ENODEV;
     ISoundTriggerHw::SoundModel model;
     SoundModelHandle handle = 0;
@@ -353,7 +337,7 @@
  * Verifies that:
  *  - the implementation returns error when passed a sound model with random data.
  */
-TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail_2_1) {
+TEST_P(SoundTriggerHidlTest, LoadGenericSoundModelFail_2_1) {
     int ret = -ENODEV;
     ISoundTriggerHw::SoundModel model;
     SoundModelHandle handle = 0;
@@ -394,7 +378,7 @@
  *  - the implementation returns an error when called without a valid loaded sound model
  *
  */
-TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) {
+TEST_P(SoundTriggerHidlTest, UnloadModelNoModelFail) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle halHandle = 0;
 
@@ -414,7 +398,7 @@
  * There is no way to verify that implementation actually starts recognition because no model can
  * be loaded.
  */
-TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
+TEST_P(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle handle = 0;
     PhraseRecognitionExtra phrase;
@@ -444,7 +428,7 @@
  * There is no way to verify that implementation actually starts recognition because no model can
  * be loaded.
  */
-TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail_2_1) {
+TEST_P(SoundTriggerHidlTest, StartRecognitionNoModelFail_2_1) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle handle = 0;
     PhraseRecognitionExtra phrase;
@@ -472,7 +456,7 @@
  *  - the implementation returns an error when called without an active recognition running
  *
  */
-TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
+TEST_P(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle handle = 0;
 
@@ -489,7 +473,7 @@
  *  - the implementation implements this optional method or indicates it is not supported by
  *  returning -ENOSYS
  */
-TEST_F(SoundTriggerHidlTest, stopAllRecognitions) {
+TEST_P(SoundTriggerHidlTest, stopAllRecognitions) {
     Return<int32_t> hidlReturn(0);
 
     hidlReturn = mSoundTriggerHal->stopAllRecognitions();
@@ -498,11 +482,7 @@
     EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, SoundTriggerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/soundtrigger/2.2/Android.bp b/soundtrigger/2.2/Android.bp
index 0a7c2d8..7556aa4 100644
--- a/soundtrigger/2.2/Android.bp
+++ b/soundtrigger/2.2/Android.bp
@@ -15,6 +15,5 @@
         "android.hardware.soundtrigger@2.1",
         "android.hidl.base@1.0",
     ],
-    gen_java: false,
+    gen_java: true,
 }
-
diff --git a/soundtrigger/2.2/default/Android.bp b/soundtrigger/2.2/default/Android.bp
index 78bb69f..db37c5b 100644
--- a/soundtrigger/2.2/default/Android.bp
+++ b/soundtrigger/2.2/default/Android.bp
@@ -22,7 +22,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libhidlmemory",
         "libutils",
diff --git a/soundtrigger/2.2/vts/functional/Android.bp b/soundtrigger/2.2/vts/functional/Android.bp
index 08ccd7b..b5d241d 100644
--- a/soundtrigger/2.2/vts/functional/Android.bp
+++ b/soundtrigger/2.2/vts/functional/Android.bp
@@ -23,5 +23,5 @@
         "android.hardware.soundtrigger@2.1",
         "android.hardware.soundtrigger@2.2",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp b/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp
index 0f37816..1cce5a1 100644
--- a/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp
+++ b/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp
@@ -23,42 +23,26 @@
 
 #include <android/log.h>
 #include <cutils/native_handle.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 #include <android/hardware/audio/common/2.0/types.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 using ::android::sp;
 using ::android::hardware::Return;
 using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
 using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
 using ::android::hardware::soundtrigger::V2_2::ISoundTriggerHw;
 
-// Test environment for SoundTrigger HIDL HAL.
-class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static SoundTriggerHidlEnvironment* Instance() {
-        static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
-        return instance;
-    }
-
-    void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
-
-   private:
-    SoundTriggerHidlEnvironment() {}
-};
-
 // The main test class for Sound Trigger HIDL HAL.
-class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SoundTriggerHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     void SetUp() override {
-        mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
-            SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
+        mSoundTriggerHal = ISoundTriggerHw::getService(GetParam());
         ASSERT_NE(nullptr, mSoundTriggerHal.get());
     }
 
@@ -77,18 +61,13 @@
  *  - the implementation returns -ENOSYS with invalid model handle
  *
  */
-TEST_F(SoundTriggerHidlTest, GetModelStateInvalidModel) {
+TEST_P(SoundTriggerHidlTest, GetModelStateInvalidModel) {
     SoundModelHandle handle = 0;
     Return<int32_t> hidlReturn = mSoundTriggerHal->getModelState(handle);
     EXPECT_TRUE(hidlReturn.isOk());
     EXPECT_EQ(-ENOSYS, hidlReturn);
 }
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, SoundTriggerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/tests/bar/1.0/Android.bp b/tests/bar/1.0/Android.bp
index a1b6b88..0aeccd6 100644
--- a/tests/bar/1.0/Android.bp
+++ b/tests/bar/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/bar/1.0/default/Android.bp b/tests/bar/1.0/default/Android.bp
index 8aa6135..8e3d072 100644
--- a/tests/bar/1.0/default/Android.bp
+++ b/tests/bar/1.0/default/Android.bp
@@ -13,8 +13,6 @@
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/baz/1.0/Android.bp b/tests/baz/1.0/Android.bp
index 618f4f8..ed18876 100644
--- a/tests/baz/1.0/Android.bp
+++ b/tests/baz/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/baz/1.0/IBaz.hal b/tests/baz/1.0/IBaz.hal
index 91ed1f2..7855446 100644
--- a/tests/baz/1.0/IBaz.hal
+++ b/tests/baz/1.0/IBaz.hal
@@ -29,6 +29,11 @@
         VALL = V0 | V1 | V2 | V3,
     };
 
+    struct BitFieldTester {
+      bitfield<BitField> scalar;
+      vec<bitfield<BitField>> vector;
+     };
+
     enum SomeOtherEnum : uint8_t {
         bar = 66
     };
@@ -108,6 +113,7 @@
 
     haveSomeStrings(string[3] array) generates (string[2] result);
     haveAStringVec(vec<string> vector) generates (vec<string> result);
+    repeatBitfieldVec(vec<bitfield<BitField>> vector) generates (vec<bitfield<BitField>> result);
 
     returnABunchOfStrings() generates (string a, string b, string c);
 
diff --git a/tests/baz/1.0/default/Android.bp b/tests/baz/1.0/default/Android.bp
index 492e0b4..4096d47 100644
--- a/tests/baz/1.0/default/Android.bp
+++ b/tests/baz/1.0/default/Android.bp
@@ -9,8 +9,6 @@
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/baz/1.0/default/Baz.cpp b/tests/baz/1.0/default/Baz.cpp
index e118122..2ce096c 100644
--- a/tests/baz/1.0/default/Baz.cpp
+++ b/tests/baz/1.0/default/Baz.cpp
@@ -364,6 +364,12 @@
     return Void();
 }
 
+Return<void> Baz::repeatBitfieldVec(const hidl_vec<uint8_t>& vector,
+                                    repeatBitfieldVec_cb _hidl_cb) {
+    _hidl_cb(vector);
+    return Void();
+}
+
 Return<void> Baz::returnABunchOfStrings(returnABunchOfStrings_cb _hidl_cb) {
     hidl_string eins; eins = "Eins";
     hidl_string zwei; zwei = "Zwei";
diff --git a/tests/baz/1.0/default/Baz.h b/tests/baz/1.0/default/Baz.h
index c264f47..1e24d52 100644
--- a/tests/baz/1.0/default/Baz.h
+++ b/tests/baz/1.0/default/Baz.h
@@ -86,6 +86,8 @@
                                  haveSomeStrings_cb _hidl_cb) override;
     Return<void> haveAStringVec(const hidl_vec<hidl_string>& vector,
                                 haveAStringVec_cb _hidl_cb) override;
+    Return<void> repeatBitfieldVec(const hidl_vec<uint8_t>& vector,
+                                   repeatBitfieldVec_cb _hidl_cb) override;
     Return<void> returnABunchOfStrings(returnABunchOfStrings_cb _hidl_cb) override;
     Return<uint8_t> returnABitField() override;
     Return<uint32_t> size(uint32_t size) override;
diff --git a/tests/expression/1.0/Android.bp b/tests/expression/1.0/Android.bp
index 61ca6ac..4bc3848 100644
--- a/tests/expression/1.0/Android.bp
+++ b/tests/expression/1.0/Android.bp
@@ -12,4 +12,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/expression/1.0/IExpression.hal b/tests/expression/1.0/IExpression.hal
index 36aed60..039897a 100644
--- a/tests/expression/1.0/IExpression.hal
+++ b/tests/expression/1.0/IExpression.hal
@@ -215,7 +215,6 @@
     MY_INT32_MIN_PLUS_1, // 0x80000001
   };
 
-  @callflow(key=Constants:CONST_FOO + 1)
   foo1(int32_t[Constants:CONST_FOO + 1] array);
   foo2(int32_t[5 + 8] array);
   foo3(int32_t[Constants:MAX_ARRAY_SIZE] array);
diff --git a/tests/expression/1.0/IExpressionExt.hal b/tests/expression/1.0/IExpressionExt.hal
index 8b56ec6..e721978 100644
--- a/tests/expression/1.0/IExpressionExt.hal
+++ b/tests/expression/1.0/IExpressionExt.hal
@@ -36,7 +36,6 @@
         SixteenColors my16Colors;
     };
 
-    @callflow(key=@1.0::IExpression.Constants:MAX_ARRAY_SIZE)
     foo3(int32_t[IExpression.Constants:MAX_ARRAY_SIZE] array);
     foo2(SixteenColors array);
     foo1(int32_t[Constants:CONST_FOO + 5] array);
diff --git a/tests/extension/light/2.0/Android.bp b/tests/extension/light/2.0/Android.bp
index 916af71..e19a913 100644
--- a/tests/extension/light/2.0/Android.bp
+++ b/tests/extension/light/2.0/Android.bp
@@ -13,4 +13,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/extension/light/2.0/default/Android.bp b/tests/extension/light/2.0/default/Android.bp
index dcac97c..d8d8dd5 100644
--- a/tests/extension/light/2.0/default/Android.bp
+++ b/tests/extension/light/2.0/default/Android.bp
@@ -27,7 +27,6 @@
 
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.light@2.0",
         "android.hardware.tests.extension.light@2.0",
diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp
new file mode 100644
index 0000000..ef9b39b
--- /dev/null
+++ b/tests/extension/vibrator/aidl/Android.bp
@@ -0,0 +1,29 @@
+aidl_interface {
+    // This is an example test interface showing how to add functionality
+    // with setExtension/getExtension
+    name: "test-vintf-vibrator-ext",
+    vendor_available: true,
+    srcs: [
+        // Using android.hardware as the package because this is in
+        // hardware/interfaces. For custom interfaces, normally you
+        // would use a different package.
+        "android/hardware/tests/extension/vibrator/Directionality.aidl",
+        "android/hardware/tests/extension/vibrator/ICustomVibrator.aidl",
+        "android/hardware/tests/extension/vibrator/VendorEffect.aidl",
+    ],
+
+    // This is agreeing to keep the interface stable.
+    stability: "vintf",
+
+    // This happens to use types from a core interface, so we import it, but
+    // this won't always be needed.
+    imports: [
+        "vintf-vibrator",
+    ],
+
+    backend: {
+        java: {
+            enabled: false,
+        },
+    },
+}
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/Directionality.aidl
similarity index 60%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/Directionality.aidl
index 8bb72a1..72bfd66 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/Directionality.aidl
@@ -13,14 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.hardware.tests.extension.vibrator;
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
-
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
-
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
-
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+/**
+ * Can add custom enums. If these need to be extended further, new values can
+ * simply be added.
+ */
+@Backing(type="int")
+@VintfStability
+enum Directionality {
+    NONE,
+    /** vibrations should be transverse wrt primary screen */
+    TRANSVERSE,
+    /** vibrations should be longitudinal wrt primary screen */
+    LONGITUDINAL,
+}
diff --git a/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl
new file mode 100644
index 0000000..0b21f46
--- /dev/null
+++ b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl
@@ -0,0 +1,55 @@
+/*
+ * 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.tests.extension.vibrator;
+
+// it's fine to use types from other interfaces
+import android.hardware.vibrator.IVibratorCallback;
+import android.hardware.tests.extension.vibrator.Directionality;
+import android.hardware.tests.extension.vibrator.VendorEffect;
+
+/**
+ * This is an example of an AIDL interface extension. Notice that it does not
+ * inherit from any other extension. Instead, it will be tagged onto that
+ * extension at runtime.
+ */
+@VintfStability
+interface ICustomVibrator {
+    /**
+     * Avoid conflicting with vendor properties. Giving this as an example
+     * because the core vibrator interface uses capabilities. In reality,
+     * since this is only one capability, it's probably not needed to construct
+     * a bitfield.
+     *
+     * This is for longitudinal/transverse waves, see setDirectionality.
+     */
+    const int CAP_VENDOR_DIRECTIONALITY = 1 << 0;
+
+    /**
+     * Any new methods can be added, this returns CAP_VENDOR_*.
+     */
+    int getVendorCapabilities();
+
+    /**
+     * Arbitrary new functionality can be added.
+     */
+    void setDirectionality(Directionality directionality);
+
+    /**
+     * Perform a custom vendor effect. Note, this is a separate effect enum to
+     * avoid conflicting with core types.
+     */
+    int perform(VendorEffect effect, IVibratorCallback callback);
+}
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/VendorEffect.aidl
similarity index 66%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/VendorEffect.aidl
index 8bb72a1..968532c 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/VendorEffect.aidl
@@ -13,14 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.hardware.tests.extension.vibrator;
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
-
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
-
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
-
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+/**
+ * Extending enum separately to avoid conflicts w/ upstream.
+ */
+@Backing(type="int")
+@VintfStability
+enum VendorEffect {
+    CRACKLE,
+    WIGGLE,
+}
diff --git a/tests/extension/vibrator/aidl/client/Android.bp b/tests/extension/vibrator/aidl/client/Android.bp
new file mode 100644
index 0000000..f7b71f7
--- /dev/null
+++ b/tests/extension/vibrator/aidl/client/Android.bp
@@ -0,0 +1,26 @@
+
+// This example client is written as a test, but it is executing from a system
+// context. All this code would look the same if it was running in system
+// server for example.
+
+cc_test {
+    name: "test-vintf-vibrator-ext-client",
+    srcs: [
+         // system code has the option to use the unstable C++ libbinder API
+         // or the NDK one. For maximum code portability, using the ndk client
+         // makes the most sense, but both are provided here as an example.
+         "test-cpp-client.cpp",
+         "test-ndk-client.cpp",
+    ],
+    shared_libs: [
+         "libbinder",
+         "libutils",
+         "vintf-vibrator-cpp",
+         "test-vintf-vibrator-ext-cpp",
+
+         "libbinder_ndk",
+         "vintf-vibrator-ndk_platform",
+         "test-vintf-vibrator-ext-ndk_platform",
+    ],
+}
+
diff --git a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp b/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
new file mode 100644
index 0000000..015a345
--- /dev/null
+++ b/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 <android/hardware/tests/extension/vibrator/ICustomVibrator.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+#include <gtest/gtest.h>
+
+using android::checked_interface_cast;
+using android::IBinder;
+using android::IInterface;
+using android::OK;
+using android::sp;
+using android::waitForVintfService;
+using android::hardware::tests::extension::vibrator::Directionality;
+using android::hardware::tests::extension::vibrator::ICustomVibrator;
+using android::hardware::vibrator::IVibrator;
+
+TEST(Cpp, CallRootMethod) {
+    sp<IVibrator> vib = waitForVintfService<IVibrator>();
+    ASSERT_NE(nullptr, vib.get());
+    ASSERT_TRUE(vib->off().isOk());
+}
+
+TEST(Cpp, CallExtMethod) {
+    // normally you would want to cache this
+    sp<IVibrator> vib = waitForVintfService<IVibrator>();
+    ASSERT_NE(nullptr, vib.get());
+
+    // getting the extension
+    sp<IBinder> ext;
+    ASSERT_EQ(OK, IInterface::asBinder(vib)->getExtension(&ext));
+    sp<ICustomVibrator> cvib = checked_interface_cast<ICustomVibrator>(ext);
+    ASSERT_NE(nullptr, cvib.get());
+
+    // calling extension method
+    ASSERT_TRUE(cvib->setDirectionality(Directionality::TRANSVERSE).isOk());
+}
diff --git a/tests/extension/vibrator/aidl/client/test-ndk-client.cpp b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
new file mode 100644
index 0000000..c846495
--- /dev/null
+++ b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 <aidl/android/hardware/tests/extension/vibrator/ICustomVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <android/binder_manager.h>
+
+#include <gtest/gtest.h>
+
+using aidl::android::hardware::tests::extension::vibrator::Directionality;
+using aidl::android::hardware::tests::extension::vibrator::ICustomVibrator;
+using aidl::android::hardware::vibrator::IVibrator;
+using ndk::SpAIBinder;
+
+static const std::string kInstance = std::string() + IVibrator::descriptor + "/default";
+
+TEST(Ndk, CallRootMethod) {
+    SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+    ASSERT_NE(nullptr, vibBinder.get());
+    std::shared_ptr<IVibrator> vib = IVibrator::fromBinder(vibBinder);
+    ASSERT_NE(nullptr, vib.get());
+    ASSERT_TRUE(vib->off().isOk());
+}
+
+TEST(Ndk, CallExtMethod) {
+    // normally you would want to cache this
+    //
+    SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+    ASSERT_NE(nullptr, vibBinder.get());
+    std::shared_ptr<IVibrator> vib = IVibrator::fromBinder(vibBinder);
+    ASSERT_NE(nullptr, vib.get());
+
+    // getting the extension
+    SpAIBinder cvibBinder;
+    ASSERT_EQ(STATUS_OK, AIBinder_getExtension(vibBinder.get(), cvibBinder.getR()));
+    ASSERT_NE(nullptr, cvibBinder.get());
+    std::shared_ptr<ICustomVibrator> cvib = ICustomVibrator::fromBinder(cvibBinder);
+    ASSERT_NE(nullptr, cvib.get());
+
+    // calling extension method
+    ASSERT_TRUE(cvib->setDirectionality(Directionality::TRANSVERSE).isOk());
+}
diff --git a/tests/extension/vibrator/aidl/default/Android.bp b/tests/extension/vibrator/aidl/default/Android.bp
new file mode 100644
index 0000000..9869657
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/Android.bp
@@ -0,0 +1,25 @@
+cc_binary {
+    name: "android.hardware.tests.extension.vibrator-service.example",
+    relative_install_path: "hw",
+    // normally you implement a service directly, but we are using an implementation
+    // from a library to attach our extension to.
+    static_libs: [
+        "libvibratorexampleimpl",
+    ],
+
+    // need to add this in the manifest and to init as well to use, see
+    // android.hardware.vibrator-service.example. This binary is being tested
+    // by running it manually as root.
+
+    vendor: true,
+    srcs: [
+        "service.cpp",
+        "CustomVibrator.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "vintf-vibrator-ndk_platform",
+        "test-vintf-vibrator-ext-ndk_platform",
+    ],
+}
diff --git a/tests/extension/vibrator/aidl/default/CustomVibrator.cpp b/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
new file mode 100644
index 0000000..2f3dfcb
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 "CustomVibrator.h"
+
+#include <android-base/logging.h>
+#include <thread>
+
+namespace aidl::android::hardware::tests::extension::vibrator {
+
+ndk::ScopedAStatus CustomVibrator::getVendorCapabilities(int32_t* _aidl_return) {
+    *_aidl_return = ICustomVibrator::CAP_VENDOR_DIRECTIONALITY;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus CustomVibrator::setDirectionality(Directionality directionality) {
+    LOG(INFO) << "Custom vibrator set directionality";
+    // do something cool in hardware
+    (void)directionality;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus CustomVibrator::perform(VendorEffect effect,
+                                           const std::shared_ptr<IVibratorCallback>& callback,
+                                           int32_t* _aidl_return) {
+    LOG(INFO) << "Custom vibrator perform";
+
+    if (effect != VendorEffect::CRACKLE && effect != VendorEffect::WIGGLE) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    constexpr size_t kEffectMillis = 100;
+
+    if (callback != nullptr) {
+        std::thread([=] {
+            LOG(INFO) << "Starting vendor perform on another thread";
+            usleep(kEffectMillis * 1000);
+            LOG(INFO) << "Notifying vendor perform complete";
+            callback->onComplete();
+        }).detach();
+    }
+
+    *_aidl_return = kEffectMillis;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::tests::extension::vibrator
diff --git a/tests/extension/vibrator/aidl/default/CustomVibrator.h b/tests/extension/vibrator/aidl/default/CustomVibrator.h
new file mode 100644
index 0000000..6dc5743
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/CustomVibrator.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <aidl/android/hardware/tests/extension/vibrator/BnCustomVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorCallback.h>
+
+namespace aidl::android::hardware::tests::extension::vibrator {
+
+using aidl::android::hardware::vibrator::IVibratorCallback;
+
+class CustomVibrator : public BnCustomVibrator {
+    ndk::ScopedAStatus getVendorCapabilities(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus setDirectionality(Directionality directionality) override;
+    ndk::ScopedAStatus perform(VendorEffect effect,
+                               const std::shared_ptr<IVibratorCallback>& callback,
+                               int32_t* _aidl_return) override;
+};
+
+}  // namespace aidl::android::hardware::tests::extension::vibrator
diff --git a/tests/extension/vibrator/aidl/default/service.cpp b/tests/extension/vibrator/aidl/default/service.cpp
new file mode 100644
index 0000000..16290df
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/service.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 <vibrator-impl/Vibrator.h>
+#include "CustomVibrator.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::tests::extension::vibrator::CustomVibrator;
+using aidl::android::hardware::vibrator::Vibrator;
+
+int main() {
+    // these are threads in addition to the one we are joining below, so this
+    // service will have a single thread
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    // making the core service
+    std::shared_ptr<Vibrator> vib = ndk::SharedRefBase::make<Vibrator>();
+    ndk::SpAIBinder vibBinder = vib->asBinder();
+
+    // making the extension service
+    std::shared_ptr<CustomVibrator> cvib = ndk::SharedRefBase::make<CustomVibrator>();
+
+    // need to attach the extension to the same binder we will be registering
+    CHECK(STATUS_OK == AIBinder_setExtension(vibBinder.get(), cvib->asBinder().get()));
+
+    const std::string instance = std::string() + Vibrator::descriptor + "/default";
+    CHECK(STATUS_OK == AServiceManager_addService(vibBinder.get(), instance.c_str()));
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/tests/foo/1.0/Android.bp b/tests/foo/1.0/Android.bp
index 1c3b3c5..2f97fca 100644
--- a/tests/foo/1.0/Android.bp
+++ b/tests/foo/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/foo/1.0/default/Android.bp b/tests/foo/1.0/default/Android.bp
index d9dfc69..48d6894 100644
--- a/tests/foo/1.0/default/Android.bp
+++ b/tests/foo/1.0/default/Android.bp
@@ -13,8 +13,6 @@
         "libcutils",
         "libfootest",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/foo/1.0/default/lib/Android.bp b/tests/foo/1.0/default/lib/Android.bp
index 2cc96c5..ba2081e 100644
--- a/tests/foo/1.0/default/lib/Android.bp
+++ b/tests/foo/1.0/default/lib/Android.bp
@@ -8,8 +8,6 @@
     shared_libs: [
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
     ],
     static_libs: ["android.hardware.tests.foo@1.0"],
diff --git a/tests/hash/1.0/Android.bp b/tests/hash/1.0/Android.bp
index 20334cd..1095576 100644
--- a/tests/hash/1.0/Android.bp
+++ b/tests/hash/1.0/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/hash/1.0/default/Android.bp b/tests/hash/1.0/default/Android.bp
index 6e6d6a8..410b759 100644
--- a/tests/hash/1.0/default/Android.bp
+++ b/tests/hash/1.0/default/Android.bp
@@ -8,8 +8,6 @@
     shared_libs: [
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/inheritance/1.0/Android.bp b/tests/inheritance/1.0/Android.bp
index 1d36d07..0042b57 100644
--- a/tests/inheritance/1.0/Android.bp
+++ b/tests/inheritance/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/inheritance/1.0/default/Android.bp b/tests/inheritance/1.0/default/Android.bp
index 891355b..4a0c876 100644
--- a/tests/inheritance/1.0/default/Android.bp
+++ b/tests/inheritance/1.0/default/Android.bp
@@ -14,8 +14,6 @@
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/libhwbinder/1.0/Android.bp b/tests/libhwbinder/1.0/Android.bp
index d561002..13af77c 100644
--- a/tests/libhwbinder/1.0/Android.bp
+++ b/tests/libhwbinder/1.0/Android.bp
@@ -12,4 +12,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/libhwbinder/1.0/default/Android.bp b/tests/libhwbinder/1.0/default/Android.bp
index aad1e31..3bf08ed 100644
--- a/tests/libhwbinder/1.0/default/Android.bp
+++ b/tests/libhwbinder/1.0/default/Android.bp
@@ -1,5 +1,5 @@
 cc_library {
-    name: "android.hardware.tests.libhwbinder@1.0-impl",
+    name: "android.hardware.tests.libhwbinder@1.0-impl.test",
     defaults: ["hidl_defaults"],
     relative_install_path: "hw",
     srcs: [
@@ -9,8 +9,6 @@
     shared_libs: [
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/libhwbinder/aidl/Android.bp b/tests/libhwbinder/aidl/Android.bp
index 6d49704..c9e09f7 100644
--- a/tests/libhwbinder/aidl/Android.bp
+++ b/tests/libhwbinder/aidl/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
     name: "android.hardware.tests.libbinder",
     defaults: ["hidl_defaults"],
 
diff --git a/tests/memory/1.0/Android.bp b/tests/memory/1.0/Android.bp
index cbee247..6612e31 100644
--- a/tests/memory/1.0/Android.bp
+++ b/tests/memory/1.0/Android.bp
@@ -11,6 +11,5 @@
         "android.hidl.memory.block@1.0",
         "android.hidl.memory.token@1.0",
     ],
-    gen_java: false,
+    gen_java: true,
 }
-
diff --git a/tests/memory/1.0/default/Android.bp b/tests/memory/1.0/default/Android.bp
index 3f13634..0293953 100644
--- a/tests/memory/1.0/default/Android.bp
+++ b/tests/memory/1.0/default/Android.bp
@@ -22,9 +22,7 @@
     shared_libs: [
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
         "libhidlmemory",
-        "libhwbinder",
         "liblog",
         "libutils",
         "android.hidl.memory@1.0",
diff --git a/tests/pointer/1.0/.hidl_for_test b/tests/memory/2.0/.hidl_for_test
similarity index 100%
rename from tests/pointer/1.0/.hidl_for_test
rename to tests/memory/2.0/.hidl_for_test
diff --git a/tests/pointer/1.0/Android.bp b/tests/memory/2.0/Android.bp
similarity index 60%
rename from tests/pointer/1.0/Android.bp
rename to tests/memory/2.0/Android.bp
index 3dc8e8a..d24bd21 100644
--- a/tests/pointer/1.0/Android.bp
+++ b/tests/memory/2.0/Android.bp
@@ -1,15 +1,14 @@
 // This file is autogenerated by hidl-gen -Landroidbp.
 
 hidl_interface {
-    name: "android.hardware.tests.pointer@1.0",
+    name: "android.hardware.tests.memory@2.0",
     root: "android.hardware",
     srcs: [
-        "IGraph.hal",
-        "IPointer.hal",
+        "types.hal",
+        "IMemoryInterface.hal",
     ],
     interfaces: [
         "android.hidl.base@1.0",
     ],
-    gen_java: false,
+    gen_java: true,
 }
-
diff --git a/tests/memory/2.0/IMemoryInterface.hal b/tests/memory/2.0/IMemoryInterface.hal
new file mode 100644
index 0000000..2c824bf
--- /dev/null
+++ b/tests/memory/2.0/IMemoryInterface.hal
@@ -0,0 +1,12 @@
+package android.hardware.tests.memory@2.0;
+
+interface IMemoryInterface {
+    // Flips all the bits in the given memory buffer.
+    bitwiseNot(memory mem);
+    // Returns a read-only buffer of size 8, containing the bytes 0..7.
+    getTestMem() generates(memory mem);
+    // Given two memory regions of the same size, returns two memory fields of
+    // equal size, the first contains the byte-wise sum and the other the byte-
+    // wise difference.
+    getSumDiff(TwoMemory in) generates(TwoMemory out);
+};
diff --git a/tests/memory/2.0/types.hal b/tests/memory/2.0/types.hal
new file mode 100644
index 0000000..9ec357b
--- /dev/null
+++ b/tests/memory/2.0/types.hal
@@ -0,0 +1,6 @@
+package android.hardware.tests.memory@2.0;
+
+struct TwoMemory {
+    memory mem1;
+    memory mem2;
+};
diff --git a/tests/msgq/1.0/Android.bp b/tests/msgq/1.0/Android.bp
index 2d8d565..eea1ce6 100644
--- a/tests/msgq/1.0/Android.bp
+++ b/tests/msgq/1.0/Android.bp
@@ -12,4 +12,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/msgq/1.0/default/Android.bp b/tests/msgq/1.0/default/Android.bp
index 6c8be6c..e6408aa 100644
--- a/tests/msgq/1.0/default/Android.bp
+++ b/tests/msgq/1.0/default/Android.bp
@@ -26,8 +26,6 @@
         "libcutils",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
@@ -49,7 +47,6 @@
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.tests.msgq@1.0"
@@ -68,8 +65,6 @@
         "libcutils",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/multithread/1.0/Android.bp b/tests/multithread/1.0/Android.bp
index 0d21b1b..ed3a687 100644
--- a/tests/multithread/1.0/Android.bp
+++ b/tests/multithread/1.0/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/multithread/1.0/default/Android.bp b/tests/multithread/1.0/default/Android.bp
index a94ee3e..ff89938 100644
--- a/tests/multithread/1.0/default/Android.bp
+++ b/tests/multithread/1.0/default/Android.bp
@@ -9,8 +9,6 @@
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/pointer/1.0/IGraph.hal b/tests/pointer/1.0/IGraph.hal
deleted file mode 100644
index 0853745..0000000
--- a/tests/pointer/1.0/IGraph.hal
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.tests.pointer@1.0;
-
-interface IGraph {
-
-  struct Node {
-    int32_t data;
-  };
-  struct Edge {
-    ref<Node> left;
-    ref<Node> right;
-  };
-  struct Graph {
-    vec<Node> nodes;
-    vec<Edge> edges;
-  };
-
-  struct Theta {
-    int32_t data;
-  };
-  struct Alpha {
-    ref<Theta> s_ptr;
-  };
-  struct Beta {
-    ref<Theta> s_ptr;
-  };
-  struct Gamma {
-    ref<Alpha> a_ptr;
-    ref<Beta> b_ptr;
-  };
-
-  passANode(Node n);
-  passAGraph(Graph g);
-  passTwoGraphs(ref<Graph> g1, ref<Graph> g2);
-  giveAGraph() generates (Graph g);
-  passAGamma(Gamma c);
-  passASimpleRef(ref<Alpha> a);
-  passASimpleRefS(ref<Theta> s);
-  giveASimpleRef() generates (ref<Alpha> a);
-
-  getErrors() generates (int32_t errors);
-};
diff --git a/tests/pointer/1.0/IPointer.hal b/tests/pointer/1.0/IPointer.hal
deleted file mode 100644
index 4560a4a..0000000
--- a/tests/pointer/1.0/IPointer.hal
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.tests.pointer@1.0;
-
-interface IPointer {
-  struct S { int32_t data; };
-  struct A { S s; };
-  // type declarations
-  struct Sam { int32_t data; };
-  struct Ada { ref<Sam> s_ptr; };
-  struct Bob { ref<Ada> a_ptr; ref<Sam> s_ptr; };
-  struct Cin { Ada a; ref<Bob> b_ptr; };
-  struct Dom { Cin c; };
-
-  typedef ref<int32_t> Int32Ptr;
-  typedef ref<Sam>     SamPtr;
-
-  struct Ptr {
-    ref<Ada>[5] ptr_array;
-    ref<Ada[5]> array_ptr;
-    Int32Ptr int_ptr;
-    ref<int32_t[5]> int_array_ptr;
-    ref<int32_t>[5] int_ptr_array;
-    ref<string> str_ref;
-    vec<ref<Ada>> a_ptr_vec;
-    ref<vec<Ada>> a_vec_ptr;
-  };
-
-  // test cases
-  foo1(Sam s, SamPtr s_ptr);
-  foo2(Sam s, Ada a);
-  foo3(Sam s, Ada a, Bob b);
-  foo4(ref<Sam> s_ptr);
-  foo5(Ada a, Bob b);
-  foo6(ref<Ada> a_ptr);
-  foo7(ref<Ada> a_ptr, ref<Bob> b_ptr);
-  foo8(Dom d);
-  foo9(ref<string> str_ref);
-  foo10(vec<ref<Sam>> s_ptr_vec);
-  foo11(ref<vec<Sam>> s_vec_ptr);
-  foo12(ref<Sam[5]> s_array_ref);
-  foo13(ref<Sam>[5] s_ref_array);
-  foo14(ref<ref<ref<Sam>>> s_3ptr);
-  foo15(ref<ref<ref<int32_t>>> i_3ptr);
-  foo16(Ptr p);
-  foo17(ref<Ptr> p);
-  foo18(ref<string> str_ref, ref<string> str_ref2, string str);
-  foo19(ref<vec<Ada>> a_vec_ref, vec<Ada> a_vec, ref<vec<Ada>> a_vec_ref2);
-  foo20(vec<ref<Sam>> s_ptr_vec);
-  foo21(ref<Ada[1][2][3]> a_array_ptr);
-  foo22(ref<Ada>[1][2][3] a_ptr_array);
-
-  bar1() generates (Sam s, ref<Sam> s_ptr);
-  bar2() generates (Sam s, Ada a);
-  bar3() generates (Sam s, Ada a, Bob b);
-  bar4() generates (ref<Sam> s_ptr);
-  bar5() generates (Ada a, Bob b);
-  bar6() generates (ref<Ada> a_ptr);
-  bar7() generates (ref<Ada> a_ptr, ref<Bob> b_ptr);
-  bar8() generates (Dom d);
-  bar9() generates (ref<string> str_ref);
-  bar10() generates (vec<ref<Sam>> s_ptr_vec);
-  bar11() generates (ref<vec<Sam>> s_vec_ptr);
-  bar12() generates (ref<Sam[5]> s_array_ref);
-  bar13() generates (ref<Sam>[5] s_ref_array);
-  bar14() generates (ref<ref<ref<Sam>>> s_3ptr);
-  bar15() generates (ref<ref<ref<int32_t>>> i_3ptr);
-  bar16() generates (Ptr p);
-  bar17() generates (ref<Ptr> p);
-  bar18() generates (ref<string> str_ref, ref<string> str_ref2, string str);
-  bar19() generates (ref<vec<Ada>> a_vec_ref, vec<Ada> a_vec, ref<vec<Ada>> a_vec_ref2);
-  bar20() generates (vec<ref<Sam>> s_ptr_vec);
-  bar21() generates (ref<Ada[1][2][3]> a_array_ptr);
-  bar22() generates (ref<Ada>[1][2][3] a_ptr_array);
-
-  getErrors() generates(int32_t errors);
-};
diff --git a/tests/pointer/1.0/default/Android.bp b/tests/pointer/1.0/default/Android.bp
deleted file mode 100644
index 4825ac7..0000000
--- a/tests/pointer/1.0/default/Android.bp
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-cc_library {
-    name: "android.hardware.tests.pointer@1.0-impl",
-    defaults: ["hidl_defaults"],
-    relative_install_path: "hw",
-    srcs: [
-        "Graph.cpp",
-        "Pointer.cpp",
-    ],
-
-    shared_libs: [
-        "libbase",
-        "libcutils",
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "libpointertest",
-        "liblog",
-        "libutils",
-    ],
-
-    // These are static libs only for testing purposes and portability. Shared
-    // libs should be used on device.
-    static_libs: ["android.hardware.tests.pointer@1.0"],
-
-}
diff --git a/tests/pointer/1.0/default/Graph.cpp b/tests/pointer/1.0/default/Graph.cpp
deleted file mode 100644
index 5c8098b..0000000
--- a/tests/pointer/1.0/default/Graph.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#define LOG_TAG "hidl_test"
-
-#include "Graph.h"
-
-#include <log/log.h>
-
-#include <hidl-test/PointerHelper.h>
-
-#define PUSH_ERROR_IF(__cond__) if(__cond__) { errors.push_back(std::to_string(__LINE__) + ": " + #__cond__); }
-
-namespace android {
-namespace hardware {
-namespace tests {
-namespace pointer {
-namespace V1_0 {
-namespace implementation {
-
-// Methods from ::android::hardware::tests::pointer::V1_0::IGraph follow.
-Return<void> Graph::passAGraph(const IGraph::Graph& g) {
-    ALOGI("SERVER(Graph) passAGraph start.");
-    PUSH_ERROR_IF(!isSimpleGraph(g));
-    // logSimpleGraph("SERVER(Graph) passAGraph:", g);
-    return Void();
-}
-
-Return<void> Graph::giveAGraph(giveAGraph_cb _cb) {
-    IGraph::Graph g;
-    simpleGraph(g);
-    _cb(g);
-    return Void();
-}
-
-Return<void> Graph::passANode(const IGraph::Node& n) {
-    PUSH_ERROR_IF(n.data != 10);
-    return Void();
-}
-
-Return<void> Graph::passTwoGraphs(IGraph::Graph const* g1, IGraph::Graph const* g2) {
-    PUSH_ERROR_IF(g1 != g2);
-    PUSH_ERROR_IF(!isSimpleGraph(*g1));
-    logSimpleGraph("SERVER(Graph): passTwoGraphs", *g2);
-    return Void();
-}
-
-Return<void> Graph::passAGamma(const IGraph::Gamma& c) {
-    if(c.a_ptr == nullptr && c.b_ptr == nullptr)
-      return Void();
-    ALOGI("SERVER(Graph) passAGamma received c.a = %p, c.b = %p, c.a->s = %p, c.b->s = %p",
-        c.a_ptr, c.b_ptr, c.a_ptr->s_ptr, c.b_ptr->s_ptr);
-    ALOGI("SERVER(Graph) passAGamma received data %d, %d",
-        (int)c.a_ptr->s_ptr->data, (int)c.b_ptr->s_ptr->data);
-    PUSH_ERROR_IF(c.a_ptr->s_ptr != c.b_ptr->s_ptr);
-    return Void();
-}
-Return<void> Graph::passASimpleRef(const IGraph::Alpha * a_ptr) {
-    ALOGI("SERVER(Graph) passASimpleRef received %d", a_ptr->s_ptr->data);
-    PUSH_ERROR_IF(a_ptr->s_ptr->data != 500);
-    return Void();
-}
-Return<void> Graph::passASimpleRefS(const IGraph::Theta * s_ptr) {
-    ALOGI("SERVER(Graph) passASimpleRefS received %d @ %p", s_ptr->data, s_ptr);
-    PUSH_ERROR_IF(s_ptr->data == 10);
-    return Void();
-}
-Return<void> Graph::giveASimpleRef(giveASimpleRef_cb _cb) {
-    IGraph::Theta s; s.data = 500;
-    IGraph::Alpha a; a.s_ptr = &s;
-    _cb(&a);
-    return Void();
-}
-
-Return<int32_t> Graph::getErrors() {
-    if(!errors.empty()) {
-        for(const auto& e : errors)
-            ALOGW("SERVER(Graph) error: %s", e.c_str());
-    }
-    return errors.size();
-}
-
-IGraph* HIDL_FETCH_IGraph(const char* /* name */) {
-    return new Graph();
-}
-
-} // namespace implementation
-}  // namespace V1_0
-}  // namespace pointer
-}  // namespace tests
-}  // namespace hardware
-}  // namespace android
diff --git a/tests/pointer/1.0/default/Graph.h b/tests/pointer/1.0/default/Graph.h
deleted file mode 100644
index 03bd163..0000000
--- a/tests/pointer/1.0/default/Graph.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef ANDROID_HARDWARE_TESTS_POINTER_V1_0_GRAPH_H
-#define ANDROID_HARDWARE_TESTS_POINTER_V1_0_GRAPH_H
-
-#include <android/hardware/tests/pointer/1.0/IGraph.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
-namespace android {
-namespace hardware {
-namespace tests {
-namespace pointer {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::tests::pointer::V1_0::IGraph;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct Graph : public IGraph {
-    // Methods from ::android::hardware::tests::pointer::V1_0::IGraph follow.
-    Return<void> passANode(const IGraph::Node& n)  override;
-    Return<void> passAGraph(const IGraph::Graph& g)  override;
-    Return<void> passTwoGraphs(::android::hardware::tests::pointer::V1_0::IGraph::Graph const* g1, ::android::hardware::tests::pointer::V1_0::IGraph::Graph const* g2)  override;
-    Return<void> giveAGraph(giveAGraph_cb _hidl_cb)  override;
-    Return<void> passAGamma(const IGraph::Gamma& c)  override;
-    Return<void> passASimpleRef(::android::hardware::tests::pointer::V1_0::IGraph::Alpha const* a)  override;
-    Return<void> passASimpleRefS(::android::hardware::tests::pointer::V1_0::IGraph::Theta const* s)  override;
-    Return<void> giveASimpleRef(giveASimpleRef_cb _hidl_cb)  override;
-    Return<int32_t> getErrors()  override;
-private:
-    std::vector<std::string> errors;
-
-};
-
-extern "C" IGraph* HIDL_FETCH_IGraph(const char* name);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace pointer
-}  // namespace tests
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_TESTS_POINTER_V1_0_GRAPH_H
diff --git a/tests/pointer/1.0/default/Pointer.cpp b/tests/pointer/1.0/default/Pointer.cpp
deleted file mode 100644
index 52712d4..0000000
--- a/tests/pointer/1.0/default/Pointer.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#define LOG_TAG "hidl_test"
-
-#include "Pointer.h"
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace tests {
-namespace pointer {
-namespace V1_0 {
-namespace implementation {
-
-Return<int32_t> Pointer::getErrors() {
-    if(!errors.empty()) {
-        for(const auto& e : errors)
-            ALOGW("SERVER(Pointer) error: %s", e.c_str());
-    }
-    return errors.size();
-}
-
-IPointer* HIDL_FETCH_IPointer(const char* /* name */) {
-    return new Pointer();
-}
-
-} // namespace implementation
-}  // namespace V1_0
-}  // namespace pointer
-}  // namespace tests
-}  // namespace hardware
-}  // namespace android
diff --git a/tests/pointer/1.0/default/Pointer.h b/tests/pointer/1.0/default/Pointer.h
deleted file mode 100644
index d6e3e48..0000000
--- a/tests/pointer/1.0/default/Pointer.h
+++ /dev/null
@@ -1,338 +0,0 @@
-#ifndef ANDROID_HARDWARE_TESTS_POINTER_V1_0_POINTER_H
-#define ANDROID_HARDWARE_TESTS_POINTER_V1_0_POINTER_H
-
-#include <android/hardware/tests/pointer/1.0/IPointer.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
-
-// TODO move to Pointer.cpp so that I won't have weird macros in headers
-#define PUSH_ERROR_IF(__cond__) if(__cond__) { errors.push_back(std::to_string(__LINE__) + ": " + #__cond__); }
-
-namespace android {
-namespace hardware {
-namespace tests {
-namespace pointer {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::tests::pointer::V1_0::IPointer;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct Pointer : public IPointer {
-private:
-    std::vector<std::string> errors;
-public:
-    Return<int32_t> getErrors() override;
-    Return<void> foo1(const IPointer::Sam& s, IPointer::Sam const* s_ptr) override {
-        PUSH_ERROR_IF(!(&s == s_ptr));
-        return Void();
-    }
-    Return<void> foo2(const IPointer::Sam& s, const IPointer::Ada& a) override {
-        PUSH_ERROR_IF(!(&s == a.s_ptr));
-        return Void();
-    }
-    Return<void> foo3(const IPointer::Sam& s, const IPointer::Ada& a, const IPointer::Bob& b) override {
-        PUSH_ERROR_IF(!(&a == b.a_ptr && a.s_ptr == b.s_ptr && a.s_ptr == &s));
-        return Void();
-    }
-    Return<void> foo4(IPointer::Sam const* s_ptr) override {
-        PUSH_ERROR_IF(!(s_ptr->data == 500));
-        return Void();
-    }
-    Return<void> foo5(const IPointer::Ada& a, const IPointer::Bob& b) override {
-        PUSH_ERROR_IF(!(a.s_ptr == b.s_ptr && b.a_ptr == &a));
-        return Void();
-    }
-    Return<void> foo6(IPointer::Ada const* a_ptr) override {
-        PUSH_ERROR_IF(!(a_ptr->s_ptr->data == 500));
-        return Void();
-    }
-    Return<void> foo7(IPointer::Ada const* a_ptr, IPointer::Bob const* b_ptr) override {
-        PUSH_ERROR_IF(!(a_ptr->s_ptr == b_ptr->s_ptr && a_ptr == b_ptr->a_ptr && a_ptr->s_ptr->data == 500));
-        return Void();
-    }
-    Return<void> foo8(const IPointer::Dom& d) override {
-        const IPointer::Cin& c = d.c;
-        PUSH_ERROR_IF(&c.a != c.b_ptr->a_ptr);
-        PUSH_ERROR_IF(c.a.s_ptr != c.b_ptr->s_ptr);
-        PUSH_ERROR_IF(c.a.s_ptr->data != 500);
-        return Void();
-    }
-    Return<void> foo9(::android::hardware::hidl_string const* str_ref) override {
-        PUSH_ERROR_IF(!(strcmp(str_ref->c_str(), "meowmeowmeow") == 0));
-        return Void();
-    }
-    Return<void> foo10(const ::android::hardware::hidl_vec<IPointer::Sam const*>& s_ptr_vec) override {
-        PUSH_ERROR_IF(s_ptr_vec[0]->data != 500);
-        if(s_ptr_vec.size() != 5) {
-            errors.push_back("foo10: s_ptr_vec.size() != 5");
-            return Void();
-        }
-        for(size_t i = 0; i < s_ptr_vec.size(); i++)
-            PUSH_ERROR_IF(s_ptr_vec[0] != s_ptr_vec[i]);
-        return Void();
-    }
-    Return<void> foo11(::android::hardware::hidl_vec<IPointer::Sam> const* s_vec_ptr) override {
-        if(s_vec_ptr->size() != 5) {
-            errors.push_back("foo11: s_vec_ptr->size() != 5");
-            return Void();
-        }
-        for(size_t i = 0; i < 5; i++)
-            PUSH_ERROR_IF((*s_vec_ptr)[i].data != 500);
-        return Void();
-    }
-    Return<void> foo12(hidl_array<IPointer::Sam, 5> const* s_array_ref) override {
-        for(size_t i = 0; i < 5; ++i)
-            PUSH_ERROR_IF((*s_array_ref)[i].data != 500);
-        return Void();
-    }
-    Return<void> foo13(const hidl_array<IPointer::Sam const*, 5>& s_ref_array) override {
-        PUSH_ERROR_IF(s_ref_array[0]->data != 500)
-        for(size_t i = 0; i < 5; i++)
-            PUSH_ERROR_IF(s_ref_array[i] != s_ref_array[0])
-        return Void();
-    }
-    Return<void> foo14(IPointer::Sam const* const* const* s_3ptr) override {
-        PUSH_ERROR_IF(!((***s_3ptr).data == 500))
-        return Void();
-    }
-    Return<void> foo15(int32_t const* const* const* i_3ptr) override {
-        PUSH_ERROR_IF(!((***i_3ptr) == 500))
-        return Void();
-    }
-
-    Return<void> foo16(const IPointer::Ptr& p) override {
-        PUSH_ERROR_IF((*p.array_ptr)[0].s_ptr->data != 500);
-        for(size_t i = 0; i < 5; i++) PUSH_ERROR_IF((*p.array_ptr)[i].s_ptr != (*p.array_ptr)[0].s_ptr);
-        PUSH_ERROR_IF(*(p.int_ptr) != 500);
-        for(size_t i = 0; i < 5; i++) PUSH_ERROR_IF((*p.int_array_ptr)[i] != 500);
-        for(size_t i = 0; i < 5; i++) PUSH_ERROR_IF(p.int_ptr_array[i] != p.int_ptr);
-        PUSH_ERROR_IF(p.a_ptr_vec.size() != 5);
-        PUSH_ERROR_IF(p.a_ptr_vec[0]->s_ptr->data != 500);
-        for(size_t i = 0; i < 5; i++) PUSH_ERROR_IF(p.a_ptr_vec[i]->s_ptr != p.a_ptr_vec[0]->s_ptr);
-        PUSH_ERROR_IF(strcmp(p.str_ref->c_str(), "meowmeowmeow") != 0);
-        PUSH_ERROR_IF(p.a_vec_ptr->size() != 5);
-        PUSH_ERROR_IF((*p.a_vec_ptr)[0].s_ptr->data != 500);
-        for(size_t i = 0; i < 5; i++) PUSH_ERROR_IF((*p.a_vec_ptr)[i].s_ptr != (*p.a_vec_ptr)[0].s_ptr);
-        return Void();
-    };
-    Return<void> foo17(IPointer::Ptr const* p) override {
-        return foo16(*p);
-    };
-    Return<void> foo18(hidl_string const* str_ref, hidl_string const* str_ref2, const hidl_string& str) override {
-        PUSH_ERROR_IF(&str != str_ref);
-        PUSH_ERROR_IF(str_ref != str_ref2);
-        PUSH_ERROR_IF(strcmp(str.c_str(), "meowmeowmeow") != 0)
-        return Void();
-    };
-    Return<void> foo19(
-                hidl_vec<IPointer::Ada> const* a_vec_ref,
-                const hidl_vec<IPointer::Ada>& a_vec,
-                hidl_vec<IPointer::Ada> const* a_vec_ref2) {
-        PUSH_ERROR_IF(&a_vec != a_vec_ref);
-        PUSH_ERROR_IF(a_vec_ref2 != a_vec_ref);
-        PUSH_ERROR_IF(a_vec.size() != 5);
-        PUSH_ERROR_IF(a_vec[0].s_ptr->data != 500);
-        for(size_t i = 0; i < 5; i++)
-            PUSH_ERROR_IF(a_vec[i].s_ptr != a_vec[0].s_ptr);
-        return Void();
-    };
-
-    Return<void> foo20(const hidl_vec<IPointer::Sam const*>&) override {
-        return Void();
-    }
-    Return<void> foo21(hidl_array<IPointer::Ada, 1, 2, 3> const* a_array_ptr) override {
-        const hidl_array<IPointer::Ada, 1, 2, 3>& a_array = *a_array_ptr;
-        PUSH_ERROR_IF(a_array[0][0][0].s_ptr->data != 500);
-        for(size_t i = 0; i < 1; i++)
-            for(size_t j = 0; j < 2; j++)
-                for(size_t k = 0; k < 3; k++)
-                    PUSH_ERROR_IF(a_array[i][j][k].s_ptr != a_array[0][0][0].s_ptr);
-        return Void();
-    }
-    Return<void> foo22(const hidl_array<IPointer::Ada const*, 1, 2, 3>& a_ptr_array) override {
-        PUSH_ERROR_IF(a_ptr_array[0][0][0]->s_ptr->data != 500);
-        for(size_t i = 0; i < 1; i++)
-            for(size_t j = 0; j < 2; j++)
-                for(size_t k = 0; k < 3; k++)
-                    PUSH_ERROR_IF(a_ptr_array[i][j][k] != a_ptr_array[0][0][0]);
-        return Void();
-    }
-
-    IPointer::Sam *s;
-    IPointer::Ada *a;
-    IPointer::Bob *b;
-    IPointer::Cin *c;
-    IPointer::Dom *d;
-
-    IPointer::Ptr p;
-    hidl_array<IPointer::Ada, 5> a_array;
-    int32_t someInt;
-    hidl_array<int32_t, 5> someIntArray;
-    hidl_string str;
-    hidl_vec<IPointer::Ada> a_vec;
-    Pointer() {
-        d = new IPointer::Dom();
-        s = new IPointer::Sam();
-        b = new IPointer::Bob();
-        c = &d->c;
-        a = &c->a;
-        b->s_ptr = a->s_ptr = s;
-        b->a_ptr = a;
-        c->b_ptr = b;
-        s->data = 500;
-
-        someInt = 500;
-        for(size_t i = 0; i < 5; i++) someIntArray[i] = 500;
-
-        for(size_t i = 0; i < 5; i++) a_array[i] = *a;
-
-        for(size_t i = 0; i < 5; i++) p.ptr_array[i] = a;
-        p.array_ptr = &a_array;
-        p.int_ptr = &someInt;
-        p.int_array_ptr = &someIntArray;
-        for(size_t i = 0; i < 5; i++) p.int_ptr_array[i] = &someInt;
-        p.a_ptr_vec.resize(5);
-        for(size_t i = 0; i < 5; i++) p.a_ptr_vec[i] = a;
-        str = "meowmeowmeow";
-        p.str_ref = &str;
-        a_vec.resize(5);
-        for(size_t i = 0; i < 5; i++) a_vec[i].s_ptr = s;
-        p.a_vec_ptr = &a_vec;
-    }
-    ~Pointer() {
-        delete d; delete s; delete b;
-    }
-    Return<void> bar1(bar1_cb _cb) override {
-        _cb(*s, s);
-        return Void();
-    }
-    Return<void> bar2(bar2_cb _cb) override {
-        _cb(*s, *a);
-        return Void();
-    }
-    Return<void> bar3(bar3_cb _cb) override {
-        _cb(*s, *a, *b);
-        return Void();
-    }
-    Return<void> bar4(bar4_cb _cb) override {
-        _cb(s);
-        return Void();
-    }
-    Return<void> bar5(bar5_cb _cb) override {
-        _cb(*a, *b);
-        return Void();
-    }
-    Return<void> bar6(bar6_cb _cb) override {
-        _cb(a);
-        return Void();
-    }
-    Return<void> bar7(bar7_cb _cb) override {
-        _cb(a, b);
-        return Void();
-    }
-    Return<void> bar8(bar8_cb _cb) override {
-        _cb(*d);
-        return Void();
-    }
-    Return<void> bar9(bar9_cb _cb) override {
-        _cb(&str);
-        return Void();
-    }
-    Return<void> bar10(bar10_cb _cb) override {
-        hidl_vec<const IPointer::Sam *> v; v.resize(5);
-        for(size_t i = 0; i < 5; i++) v[i] = s;
-        _cb(v);
-        return Void();
-    }
-    Return<void> bar11(bar11_cb _cb) override {
-        hidl_vec<IPointer::Sam> v; v.resize(5);
-        for(size_t i = 0; i < 5; i++) v[i].data = 500;
-            _cb(&v);
-        return Void();
-    }
-    Return<void> bar12(bar12_cb _cb) override {
-        hidl_array<IPointer::Sam, 5> array;
-        for(size_t i = 0; i < 5; i++) array[i] = *s;
-        _cb(&array);
-        return Void();
-    }
-    Return<void> bar13(bar13_cb _cb) override {
-        hidl_array<const IPointer::Sam *, 5> array;
-        for(size_t i = 0; i < 5; i++) array[i] = s;
-        _cb(array);
-        return Void();
-    }
-    Return<void> bar14(bar14_cb _cb) override {
-        IPointer::Sam const* p1 = s;
-        IPointer::Sam const* const* p2 = &p1;
-        _cb(&p2);
-        return Void();
-    }
-    Return<void> bar15(bar15_cb _cb) override {
-        int32_t const* p1 = &someInt;
-        int32_t const* const* p2 = &p1;
-        _cb(&p2);
-        return Void();
-    }
-    Return<void> bar16(bar16_cb _cb) override {
-        _cb(p);
-        return Void();
-    }
-    Return<void> bar17(bar17_cb _cb) override {
-        _cb(&p);
-        return Void();
-    }
-    Return<void> bar18(bar18_cb _cb) override {
-        _cb(&str, &str, str);
-        return Void();
-    }
-    Return<void> bar19(bar19_cb _cb) override {
-        _cb(&a_vec, a_vec, &a_vec);
-        return Void();
-    }
-    Return<void> bar20(bar20_cb _cb) override {
-        // 1026 == PARCEL_REF_CAP + 2.
-        // 1026 means 1 writeBuffer and 1025 writeReferences. 1025 > PARCEL_REF_CAP.
-        hidl_vec<const IPointer::Sam *> v; v.resize(1026);
-        for(size_t i = 0; i < 1026; i++) v[i] = s;
-        _cb(v);
-        return Void();
-    }
-    Return<void> bar21(bar21_cb _cb) override {
-        hidl_array<IPointer::Ada, 1, 2, 3> a_array;
-        for(size_t i = 0; i < 1; i++)
-            for(size_t j = 0; j < 2; j++)
-                for(size_t k = 0; k < 3; k++)
-                    a_array[i][j][k] = *a;
-        _cb(&a_array);
-        return Void();
-    }
-    Return<void> bar22(bar22_cb _cb) override {
-        hidl_array<const IPointer::Ada *, 1, 2, 3> a_ptr_array;
-        for(size_t i = 0; i < 1; i++)
-            for(size_t j = 0; j < 2; j++)
-                for(size_t k = 0; k < 3; k++)
-                    a_ptr_array[i][j][k] = a;
-        _cb(a_ptr_array);
-        return Void();
-    }
-};
-
-extern "C" IPointer* HIDL_FETCH_IPointer(const char* name);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace pointer
-}  // namespace tests
-}  // namespace hardware
-}  // namespace android
-
-#undef PUSH_ERROR_IF
-
-#endif  // ANDROID_HARDWARE_TESTS_POINTER_V1_0_POINTER_H
diff --git a/tests/pointer/1.0/default/lib/Android.bp b/tests/pointer/1.0/default/lib/Android.bp
deleted file mode 100644
index 180906b..0000000
--- a/tests/pointer/1.0/default/lib/Android.bp
+++ /dev/null
@@ -1,19 +0,0 @@
-cc_library {
-    name: "libpointertest",
-    defaults: ["hidl_defaults"],
-    srcs: [
-        "PointerHelper.cpp"
-    ],
-
-    shared_libs: [
-        "libbase",
-        "libhidlbase",
-        "libhidltransport",
-        "liblog",
-    ],
-    static_libs: ["android.hardware.tests.pointer@1.0"],
-
-    local_include_dirs: ["include/hidl-test"],
-    export_include_dirs: ["include"],
-
-}
diff --git a/tests/pointer/1.0/default/lib/PointerHelper.cpp b/tests/pointer/1.0/default/lib/PointerHelper.cpp
deleted file mode 100644
index 0a64cc3..0000000
--- a/tests/pointer/1.0/default/lib/PointerHelper.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#define LOG_TAG "hidl_test"
-
-#include <log/log.h>
-
-#include "PointerHelper.h"
-
-namespace android {
-
-void simpleGraph(IGraph::Graph& g) {
-    g.nodes.resize(2);
-    g.edges.resize(1);
-    g.nodes[0].data = 10;
-    g.nodes[1].data = 20;
-    g.edges[0].left = &g.nodes[0];
-    g.edges[0].right = &g.nodes[1];
-}
-
-bool isSimpleGraph(const IGraph::Graph &g) {
-    if(g.nodes.size() != 2) return false;
-    if(g.edges.size() != 1) return false;
-    if(g.nodes[0].data != 10) return false;
-    if(g.nodes[1].data != 20) return false;
-    if(g.edges[0].left != &g.nodes[0]) return false;
-    if(g.edges[0].right != &g.nodes[1]) return false;
-    return true;
-}
-
-void logSimpleGraph(const char *prefix, const IGraph::Graph& g) {
-    ALOGI("%s Graph %p, %d nodes, %d edges", prefix, &g, (int)g.nodes.size(), (int)g.edges.size());
-    std::ostringstream os;
-    for(size_t i = 0; i < g.nodes.size(); i++)
-      os << &g.nodes[i] << " = " << g.nodes[i].data << ", ";
-    ALOGI("%s Nodes: [%s]", prefix, os.str().c_str());
-    os.str("");
-    os.clear();
-    for(size_t i = 0; i < g.edges.size(); i++)
-      os << g.edges[i].left << " -> " << g.edges[i].right << ", ";
-    ALOGI("%s Edges: [%s]", prefix, os.str().c_str());
-}
-} // namespace android
diff --git a/tests/pointer/1.0/default/lib/include/hidl-test/PointerHelper.h b/tests/pointer/1.0/default/lib/include/hidl-test/PointerHelper.h
deleted file mode 100644
index cd2edcb..0000000
--- a/tests/pointer/1.0/default/lib/include/hidl-test/PointerHelper.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef ANDROID_HIDL_TEST_POINTER_HELPER_H
-#define ANDROID_HIDL_TEST_POINTER_HELPER_H
-
-#include <android/hardware/tests/pointer/1.0/IGraph.h>
-
-using ::android::hardware::tests::pointer::V1_0::IGraph;
-
-namespace android {
-
-void simpleGraph(IGraph::Graph& g);
-bool isSimpleGraph(const IGraph::Graph &g);
-void logSimpleGraph(const char *prefix, const IGraph::Graph& g);
-
-} // namespace android
-#endif // ANDROID_HIDL_TEST_POINTER_HELPER_H
diff --git a/tests/safeunion/1.0/Android.bp b/tests/safeunion/1.0/Android.bp
index 87edd53..2937832 100644
--- a/tests/safeunion/1.0/Android.bp
+++ b/tests/safeunion/1.0/Android.bp
@@ -13,4 +13,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/safeunion/1.0/default/Android.bp b/tests/safeunion/1.0/default/Android.bp
index fc2443e..759a49c 100644
--- a/tests/safeunion/1.0/default/Android.bp
+++ b/tests/safeunion/1.0/default/Android.bp
@@ -9,8 +9,6 @@
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/safeunion/cpp/1.0/Android.bp b/tests/safeunion/cpp/1.0/Android.bp
index 1111719..221643a 100644
--- a/tests/safeunion/cpp/1.0/Android.bp
+++ b/tests/safeunion/cpp/1.0/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/safeunion/cpp/1.0/default/Android.bp b/tests/safeunion/cpp/1.0/default/Android.bp
index 210a639..618f295 100644
--- a/tests/safeunion/cpp/1.0/default/Android.bp
+++ b/tests/safeunion/cpp/1.0/default/Android.bp
@@ -8,8 +8,6 @@
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/trie/1.0/Android.bp b/tests/trie/1.0/Android.bp
index 0795f66..3cb67c7 100644
--- a/tests/trie/1.0/Android.bp
+++ b/tests/trie/1.0/Android.bp
@@ -10,6 +10,5 @@
     interfaces: [
         "android.hidl.base@1.0",
     ],
-    gen_java: false,
+    gen_java: true,
 }
-
diff --git a/tests/trie/1.0/default/Android.bp b/tests/trie/1.0/default/Android.bp
index 948a8cb..4ca705c 100644
--- a/tests/trie/1.0/default/Android.bp
+++ b/tests/trie/1.0/default/Android.bp
@@ -9,8 +9,6 @@
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/tests/trie/1.0/types.hal b/tests/trie/1.0/types.hal
index c626909..889d3b2 100644
--- a/tests/trie/1.0/types.hal
+++ b/tests/trie/1.0/types.hal
@@ -29,16 +29,16 @@
 // Some forward reference tests.
 
 struct A {
-    ref<B> b;
+    vec<B> b;
 };
 
 struct B {
-    ref<A> a;
+    vec<A> a;
 };
 
-typedef ref<S> refS;
+typedef vec<S> vecS;
 struct S {
-    refS f;
+    vecS f;
 };
 
 enum E2 : E1 {
diff --git a/tetheroffload/config/1.0/Android.bp b/tetheroffload/config/1.0/Android.bp
index f20d77c..321224a 100644
--- a/tetheroffload/config/1.0/Android.bp
+++ b/tetheroffload/config/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tetheroffload/config/1.0/vts/functional/Android.bp b/tetheroffload/config/1.0/vts/functional/Android.bp
index 52b9810..7b472e3 100644
--- a/tetheroffload/config/1.0/vts/functional/Android.bp
+++ b/tetheroffload/config/1.0/vts/functional/Android.bp
@@ -17,5 +17,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalTetheroffloadConfigV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.tetheroffload.config@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/tetheroffload/config/1.0/vts/functional/VtsHalTetheroffloadConfigV1_0TargetTest.cpp b/tetheroffload/config/1.0/vts/functional/VtsHalTetheroffloadConfigV1_0TargetTest.cpp
index 34a95f2..02fe96f 100644
--- a/tetheroffload/config/1.0/vts/functional/VtsHalTetheroffloadConfigV1_0TargetTest.cpp
+++ b/tetheroffload/config/1.0/vts/functional/VtsHalTetheroffloadConfigV1_0TargetTest.cpp
@@ -16,11 +16,12 @@
 
 #define LOG_TAG "VtsOffloadConfigV1_0TargetTest"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 #include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
@@ -78,25 +79,10 @@
     return netlinkSocket(NETLINK_NETFILTER, groups);
 }
 
-// Test environment for OffloadConfig HIDL HAL.
-class OffloadConfigHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static OffloadConfigHidlEnvironment* Instance() {
-        static OffloadConfigHidlEnvironment* instance = new OffloadConfigHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IOffloadConfig>(); }
-   private:
-    OffloadConfigHidlEnvironment() {}
-};
-
-class OffloadConfigHidlTest : public testing::VtsHalHidlTargetTestBase {
+class OffloadConfigHidlTest : public testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        config = testing::VtsHalHidlTargetTestBase::getService<IOffloadConfig>(
-            OffloadConfigHidlEnvironment::Instance()->getServiceName<IOffloadConfig>());
+        config = IOffloadConfig::getService(GetParam());
         ASSERT_NE(nullptr, config.get()) << "Could not get HIDL instance";
     }
 
@@ -106,7 +92,7 @@
 };
 
 // Ensure handles can be set with correct socket options.
-TEST_F(OffloadConfigHidlTest, TestSetHandles) {
+TEST_P(OffloadConfigHidlTest, TestSetHandles) {
     // Try multiple times in a row to see if it provokes file descriptor leaks.
     for (int i = 0; i < 1024; i++) {
         unique_fd fd1(netlinkSocket(kFd1Groups));
@@ -136,7 +122,7 @@
 
 // Passing a handle without an associated file descriptor should return an error
 // (e.g. "Failed Input Checks"). Check that this occurs when both FDs are empty.
-TEST_F(OffloadConfigHidlTest, TestSetHandleNone) {
+TEST_P(OffloadConfigHidlTest, TestSetHandleNone) {
     native_handle_t* const nativeHandle1 = native_handle_create(0, 0);
     hidl_handle h1;
     h1.setTo(nativeHandle1, true);
@@ -150,7 +136,7 @@
 
 // Passing a handle without an associated file descriptor should return an error
 // (e.g. "Failed Input Checks"). Check that this occurs when FD2 is empty.
-TEST_F(OffloadConfigHidlTest, TestSetHandle1Only) {
+TEST_P(OffloadConfigHidlTest, TestSetHandle1Only) {
     unique_fd fd1(netlinkSocket(kFd1Groups));
     if (fd1.get() < 0) {
         ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
@@ -171,7 +157,7 @@
 
 // Passing a handle without an associated file descriptor should return an error
 // (e.g. "Failed Input Checks"). Check that this occurs when FD1 is empty.
-TEST_F(OffloadConfigHidlTest, TestSetHandle2OnlyNotOk) {
+TEST_P(OffloadConfigHidlTest, TestSetHandle2OnlyNotOk) {
     native_handle_t* const nativeHandle1 = native_handle_create(0, 0);
     hidl_handle h1;
     h1.setTo(nativeHandle1, true);
@@ -190,11 +176,7 @@
     ASSERT_TRUE(ret.isOk());
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(OffloadConfigHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    OffloadConfigHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGE("Test result with status=%d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, OffloadConfigHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IOffloadConfig::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/tetheroffload/control/1.0/Android.bp b/tetheroffload/control/1.0/Android.bp
index dc2487b..f894448 100644
--- a/tetheroffload/control/1.0/Android.bp
+++ b/tetheroffload/control/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/thermal/1.0/Android.bp b/thermal/1.0/Android.bp
index 8428977..de168d8 100644
--- a/thermal/1.0/Android.bp
+++ b/thermal/1.0/Android.bp
@@ -16,4 +16,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/thermal/1.0/default/Android.bp b/thermal/1.0/default/Android.bp
index 9d81474..194a9f8 100644
--- a/thermal/1.0/default/Android.bp
+++ b/thermal/1.0/default/Android.bp
@@ -27,7 +27,6 @@
         "libcutils",
         "libutils",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.thermal@1.0",
     ],
 }
@@ -48,7 +47,6 @@
         "libutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.thermal@1.0",
     ],
 }
diff --git a/thermal/1.0/default/android.hardware.thermal@1.0-service.rc b/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
index cf9bdee..ba3ce82 100644
--- a/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
+++ b/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.thermal-hal-1-0 /vendor/bin/hw/android.hardware.thermal@1.0-service
+    interface android.hardware.thermal@1.0::IThermal default
     class hal
     user system
     group system
diff --git a/thermal/1.0/vts/functional/Android.bp b/thermal/1.0/vts/functional/Android.bp
index 6bda558..d183bd8 100644
--- a/thermal/1.0/vts/functional/Android.bp
+++ b/thermal/1.0/vts/functional/Android.bp
@@ -19,6 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalThermalV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.thermal@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp b/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
index 6f059ef..aa1c0ce 100644
--- a/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
+++ b/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
@@ -21,11 +21,12 @@
 
 #define LOG_TAG "thermal_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/thermal/1.0/IThermal.h>
 #include <android/hardware/thermal/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <unistd.h>
 
 using ::android::hardware::hidl_string;
@@ -46,26 +47,11 @@
 #define MAX_DEVICE_TEMPERATURE 200
 #define MAX_FAN_SPEED 20000
 
-// Test environment for Thermal HIDL HAL.
-class ThermalHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static ThermalHidlEnvironment* Instance() {
-    static ThermalHidlEnvironment* instance = new ThermalHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<IThermal>(); }
- private:
-  ThermalHidlEnvironment() {}
-};
-
 // The main test class for THERMAL HIDL HAL.
-class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ThermalHidlTest : public testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-    thermal_ = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(
-        ThermalHidlEnvironment::Instance()->getServiceName<IThermal>());
+    thermal_ = IThermal::getService(GetParam());
     ASSERT_NE(thermal_, nullptr);
     baseSize_ = 0;
     names_.clear();
@@ -178,7 +164,7 @@
 };
 
 // Sanity test for Thermal::getTemperatures().
-TEST_F(ThermalHidlTest, TemperatureTest) {
+TEST_P(ThermalHidlTest, TemperatureTest) {
   hidl_vec<Temperature> passed;
   for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) {
     thermal_->getTemperatures(
@@ -193,7 +179,7 @@
 }
 
 // Sanity test for Thermal::getCpuUsages().
-TEST_F(ThermalHidlTest, CpuUsageTest) {
+TEST_P(ThermalHidlTest, CpuUsageTest) {
   hidl_vec<CpuUsage> passed;
   for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) {
     thermal_->getCpuUsages(
@@ -208,7 +194,7 @@
 }
 
 // Sanity test for Thermal::getCoolingDevices().
-TEST_F(ThermalHidlTest, CoolingDeviceTest) {
+TEST_P(ThermalHidlTest, CoolingDeviceTest) {
   hidl_vec<CoolingDevice> passed;
   for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) {
     thermal_->getCoolingDevices([&passed](
@@ -222,11 +208,7 @@
   }
 }
 
-int main(int argc, char** argv) {
-  ::testing::AddGlobalTestEnvironment(ThermalHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  ThermalHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, ThermalHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IThermal::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/thermal/1.1/Android.bp b/thermal/1.1/Android.bp
index 8c0f1f9..f38ed3b 100644
--- a/thermal/1.1/Android.bp
+++ b/thermal/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/thermal/1.1/vts/functional/Android.bp b/thermal/1.1/vts/functional/Android.bp
index 9a16c30..2c43d79 100644
--- a/thermal/1.1/vts/functional/Android.bp
+++ b/thermal/1.1/vts/functional/Android.bp
@@ -22,6 +22,5 @@
         "android.hardware.thermal@1.0",
         "android.hardware.thermal@1.1",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
-
diff --git a/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp b/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp
index 91c8b6e..bc7b2ee 100644
--- a/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp
+++ b/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp
@@ -17,10 +17,11 @@
 #include <android/hardware/thermal/1.1/IThermal.h>
 #include <android/hardware/thermal/1.1/IThermalCallback.h>
 #include <android/hardware/thermal/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 
 using ::android::hardware::thermal::V1_0::Temperature;
 using ::android::hardware::thermal::V1_0::TemperatureType;
@@ -63,26 +64,11 @@
     }
 };
 
-// Test environment for Thermal HIDL HAL.
-class ThermalHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static ThermalHidlEnvironment* Instance() {
-        static ThermalHidlEnvironment* instance = new ThermalHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IThermal>(); }
-   private:
-    ThermalHidlEnvironment() {}
-};
-
 // The main test class for THERMAL HIDL HAL 1.1.
-class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ThermalHidlTest : public testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        mThermal = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(
-            ThermalHidlEnvironment::Instance()->getServiceName<IThermal>());
+        mThermal = IThermal::getService(GetParam());
         ASSERT_NE(mThermal, nullptr);
         mThermalCallback = new(std::nothrow) ThermalCallback();
         ASSERT_NE(mThermalCallback, nullptr);
@@ -104,7 +90,7 @@
 // This just calls into and back from our local ThermalCallback impl.
 // Note: a real thermal throttling event from the Thermal HAL could be
 // inadvertently received here.
-TEST_F(ThermalHidlTest, NotifyThrottlingTest) {
+TEST_P(ThermalHidlTest, NotifyThrottlingTest) {
     auto ret = mThermalCallback->notifyThrottling(true, kThrottleTemp);
     ASSERT_TRUE(ret.isOk());
     auto res = mThermalCallback->WaitForCallback(kCallbackNameNotifyThrottling);
@@ -114,11 +100,7 @@
     EXPECT_EQ(kThrottleTemp, res.args->temperature);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(ThermalHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    ThermalHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    cout << "Test result = " << status << std::endl;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, ThermalHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IThermal::descriptor)),
+        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/thermal/2.0/Android.bp b/thermal/2.0/Android.bp
index af23ee3..1b76f37 100644
--- a/thermal/2.0/Android.bp
+++ b/thermal/2.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/thermal/2.0/default/Android.bp b/thermal/2.0/default/Android.bp
index dab0d33..7b72694 100644
--- a/thermal/2.0/default/Android.bp
+++ b/thermal/2.0/default/Android.bp
@@ -27,7 +27,6 @@
     shared_libs: [
         "libbase",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.thermal@2.0",
         "android.hardware.thermal@1.0",
diff --git a/thermal/2.0/default/android.hardware.thermal@2.0-service.rc b/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
index 046c771..4ff8bd6 100644
--- a/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
+++ b/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.thermal-hal-2-0-mock /vendor/bin/hw/android.hardware.thermal@2.0-service.mock
+    interface android.hardware.thermal@1.0::IThermal default
     interface android.hardware.thermal@2.0::IThermal default
     class hal
     user system
diff --git a/thermal/2.0/vts/functional/Android.bp b/thermal/2.0/vts/functional/Android.bp
index f4e95f8..0940576 100644
--- a/thermal/2.0/vts/functional/Android.bp
+++ b/thermal/2.0/vts/functional/Android.bp
@@ -22,5 +22,6 @@
         "android.hardware.thermal@1.0",
         "android.hardware.thermal@2.0",
     ],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp b/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
index d0f2e84..75536a6 100644
--- a/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
+++ b/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
@@ -18,9 +18,11 @@
 #include <android/hardware/thermal/2.0/IThermalChangedCallback.h>
 #include <android/hardware/thermal/2.0/types.h>
 
+#include <gtest/gtest.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_enum_range;
@@ -63,27 +65,11 @@
     }
 };
 
-// Test environment for Thermal HIDL HAL.
-class ThermalHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static ThermalHidlEnvironment* Instance() {
-        static ThermalHidlEnvironment* instance = new ThermalHidlEnvironment;
-        return instance;
-    }
-
-    void registerTestServices() override { registerTestService<IThermal>(); }
-
-   private:
-    ThermalHidlEnvironment() {}
-};
-
 // The main test class for THERMAL HIDL HAL 2.0.
-class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ThermalHidlTest : public testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        mThermal = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(
-            ThermalHidlEnvironment::Instance()->getServiceName<IThermal>());
+        mThermal = IThermal::getService(GetParam());
         ASSERT_NE(mThermal, nullptr);
         mThermalCallback = new (std::nothrow) ThermalCallback();
         ASSERT_NE(mThermalCallback, nullptr);
@@ -119,7 +105,7 @@
 // This just calls into and back from our local ThermalChangedCallback impl.
 // Note: a real thermal throttling event from the Thermal HAL could be
 // inadvertently received here.
-TEST_F(ThermalHidlTest, NotifyThrottlingTest) {
+TEST_P(ThermalHidlTest, NotifyThrottlingTest) {
     auto ret = mThermalCallback->notifyThrottling(kThrottleTemp);
     ASSERT_TRUE(ret.isOk());
     auto res = mThermalCallback->WaitForCallback(kCallbackNameNotifyThrottling);
@@ -129,7 +115,7 @@
 }
 
 // Test Thermal->registerThermalChangedCallback.
-TEST_F(ThermalHidlTest, RegisterThermalChangedCallbackTest) {
+TEST_P(ThermalHidlTest, RegisterThermalChangedCallbackTest) {
     // Expect to fail with same callback
     auto ret = mThermal->registerThermalChangedCallback(
             mThermalCallback, false, TemperatureType::SKIN,
@@ -159,7 +145,7 @@
 }
 
 // Test Thermal->unregisterThermalChangedCallback.
-TEST_F(ThermalHidlTest, UnregisterThermalChangedCallbackTest) {
+TEST_P(ThermalHidlTest, UnregisterThermalChangedCallbackTest) {
     sp<ThermalCallback> localThermalCallback = new (std::nothrow) ThermalCallback();
     // Expect to fail as the callback was not registered before
     auto ret = mThermal->unregisterThermalChangedCallback(
@@ -184,7 +170,7 @@
 }
 
 // Sanity test for Thermal::getCurrentTemperatures().
-TEST_F(ThermalHidlTest, TemperatureTest) {
+TEST_P(ThermalHidlTest, TemperatureTest) {
     mThermal->getCurrentTemperatures(false, TemperatureType::SKIN,
                                      [](ThermalStatus status, hidl_vec<Temperature> temperatures) {
                                          if (temperatures.size()) {
@@ -214,7 +200,7 @@
 }
 
 // Sanity test for Thermal::getTemperatureThresholds().
-TEST_F(ThermalHidlTest, TemperatureThresholdTest) {
+TEST_P(ThermalHidlTest, TemperatureThresholdTest) {
     mThermal->getTemperatureThresholds(
         false, TemperatureType::SKIN,
         [](ThermalStatus status, hidl_vec<TemperatureThreshold> temperatures) {
@@ -242,7 +228,7 @@
 }
 
 // Sanity test for Thermal::getCurrentCoolingDevices().
-TEST_F(ThermalHidlTest, CoolingDeviceTest) {
+TEST_P(ThermalHidlTest, CoolingDeviceTest) {
     mThermal->getCurrentCoolingDevices(
         false, CoolingType::CPU, [](ThermalStatus status, hidl_vec<CoolingDevice> cooling_devices) {
             if (cooling_devices.size()) {
@@ -271,11 +257,7 @@
     }
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(ThermalHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    ThermalHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    cout << "Test result = " << status << std::endl;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, ThermalHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IThermal::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/tv/cec/1.0/Android.bp b/tv/cec/1.0/Android.bp
index 7626dc0..d41a7e7 100644
--- a/tv/cec/1.0/Android.bp
+++ b/tv/cec/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tv/cec/1.0/default/Android.bp b/tv/cec/1.0/default/Android.bp
index 069f327..239a527 100644
--- a/tv/cec/1.0/default/Android.bp
+++ b/tv/cec/1.0/default/Android.bp
@@ -7,7 +7,6 @@
 
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libbase",
         "libutils",
@@ -34,8 +33,29 @@
         "libhardware_legacy",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.tv.cec@1.0",
     ],
 
 }
+
+cc_binary {
+    name: "android.hardware.tv.cec@1.0-service.mock",
+    vintf_fragments: ["android.hardware.tv.cec@1.0-service.mock.xml"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.tv.cec@1.0-service.mock.rc"],
+    srcs: [
+        "serviceMock.cpp",
+        "HdmiCecMock.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libbase",
+        "libutils",
+        "libhardware",
+        "libhidlbase",
+        "android.hardware.tv.cec@1.0",
+    ],
+}
diff --git a/tv/cec/1.0/default/HdmiCecMock.cpp b/tv/cec/1.0/default/HdmiCecMock.cpp
new file mode 100644
index 0000000..219be86
--- /dev/null
+++ b/tv/cec/1.0/default/HdmiCecMock.cpp
@@ -0,0 +1,318 @@
+/*
+ * 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 "android.hardware.tv.cec@1.0-mock"
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/hdmi_cec.h>
+#include "HdmiCecMock.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace V1_0 {
+namespace implementation {
+
+/*
+ * (*set_option)() passes flags controlling the way HDMI-CEC service works down
+ * to HAL implementation. Those flags will be used in case the feature needs
+ * update in HAL itself, firmware or microcontroller.
+ */
+void HdmiCecMock::cec_set_option(int flag, int value) {
+    // maintain options and set them accordingly
+    switch (flag) {
+        case HDMI_OPTION_WAKEUP:
+            mOptionWakeUp = value;
+            break;
+        case HDMI_OPTION_ENABLE_CEC:
+            mOptionEnableCec = value;
+            break;
+        case HDMI_OPTION_SYSTEM_CEC_CONTROL:
+            mOptionSystemCecControl = value;
+            break;
+        case HDMI_OPTION_SET_LANG:
+            mOptionLanguage = value;
+    }
+}
+
+// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
+Return<Result> HdmiCecMock::addLogicalAddress(CecLogicalAddress addr) {
+    // have a list to maintain logical addresses
+    int size = mLogicalAddresses.size();
+    mLogicalAddresses.resize(size + 1);
+    mLogicalAddresses[size + 1] = addr;
+    return Result::SUCCESS;
+}
+
+Return<void> HdmiCecMock::clearLogicalAddress() {
+    // remove logical address from the list
+    mLogicalAddresses = {};
+    return Void();
+}
+
+Return<void> HdmiCecMock::getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) {
+    // maintain a physical address and return it
+    // default 0xFFFF, update on hotplug event
+    _hidl_cb(Result::SUCCESS, mPhysicalAddress);
+    return Void();
+}
+
+Return<SendMessageResult> HdmiCecMock::sendMessage(const CecMessage& message) {
+    if (message.body.size() == 0) {
+        return SendMessageResult::NACK;
+    }
+    sendMessageToFifo(message);
+    return SendMessageResult::SUCCESS;
+}
+
+Return<void> HdmiCecMock::setCallback(const sp<IHdmiCecCallback>& callback) {
+    if (mCallback != nullptr) {
+        mCallback = nullptr;
+    }
+
+    if (callback != nullptr) {
+        mCallback = callback;
+        mCallback->linkToDeath(this, 0 /*cookie*/);
+
+        mInputFile = open(CEC_MSG_IN_FIFO, O_RDWR);
+        mOutputFile = open(CEC_MSG_OUT_FIFO, O_RDWR);
+        pthread_create(&mThreadId, NULL, __threadLoop, this);
+        pthread_setname_np(mThreadId, "hdmi_cec_loop");
+    }
+    return Void();
+}
+
+Return<int32_t> HdmiCecMock::getCecVersion() {
+    // maintain a cec version and return it
+    return mCecVersion;
+}
+
+Return<uint32_t> HdmiCecMock::getVendorId() {
+    return mCecVendorId;
+}
+
+Return<void> HdmiCecMock::getPortInfo(getPortInfo_cb _hidl_cb) {
+    // TODO ready port info from device specific config
+    _hidl_cb(mPortInfo);
+    return Void();
+}
+
+Return<void> HdmiCecMock::setOption(OptionKey key, bool value) {
+    cec_set_option(static_cast<int>(key), value ? 1 : 0);
+    return Void();
+}
+
+Return<void> HdmiCecMock::setLanguage(const hidl_string& language) {
+    if (language.size() != 3) {
+        LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size()
+                   << ".";
+        return Void();
+    }
+    // TODO validate if language is a valid language code
+    const char* languageStr = language.c_str();
+    int convertedLanguage = ((languageStr[0] & 0xFF) << 16) | ((languageStr[1] & 0xFF) << 8) |
+                            (languageStr[2] & 0xFF);
+    cec_set_option(HDMI_OPTION_SET_LANG, convertedLanguage);
+    return Void();
+}
+
+Return<void> HdmiCecMock::enableAudioReturnChannel(int32_t portId __unused, bool enable __unused) {
+    // Maintain ARC status
+    return Void();
+}
+
+Return<bool> HdmiCecMock::isConnected(int32_t portId) {
+    // maintain port connection status and update on hotplug event
+    if (portId < mTotalPorts && portId >= 0) {
+        return mPortConnectionStatus[portId];
+    }
+    return false;
+}
+
+void* HdmiCecMock::__threadLoop(void* user) {
+    HdmiCecMock* const self = static_cast<HdmiCecMock*>(user);
+    self->threadLoop();
+    return 0;
+}
+
+int HdmiCecMock::readMessageFromFifo(unsigned char* buf, int msgCount) {
+    if (msgCount <= 0 || !buf) {
+        return 0;
+    }
+
+    int ret = -1;
+    /* maybe blocked at driver */
+    ret = read(mInputFile, buf, msgCount);
+    if (ret < 0) {
+        ALOGE("[halimp] read :%s failed, ret:%d\n", CEC_MSG_IN_FIFO, ret);
+        return -1;
+    }
+
+    return ret;
+}
+
+int HdmiCecMock::sendMessageToFifo(const CecMessage& message) {
+    unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
+    int ret = -1;
+
+    memset(msgBuf, 0, sizeof(msgBuf));
+    msgBuf[0] = ((static_cast<uint8_t>(message.initiator) & 0xf) << 4) |
+                (static_cast<uint8_t>(message.destination) & 0xf);
+
+    size_t length = std::min(static_cast<size_t>(message.body.size()),
+                             static_cast<size_t>(MaxLength::MESSAGE_BODY));
+    for (size_t i = 0; i < length; ++i) {
+        msgBuf[i + 1] = static_cast<unsigned char>(message.body[i]);
+    }
+
+    // open the output pipe for writing outgoing cec message
+    mOutputFile = open(CEC_MSG_OUT_FIFO, O_WRONLY);
+    if (mOutputFile < 0) {
+        ALOGD("[halimp] file open failed for writing");
+        return -1;
+    }
+
+    // write message into the output pipe
+    ret = write(mOutputFile, msgBuf, length + 1);
+    close(mOutputFile);
+    if (ret < 0) {
+        ALOGE("[halimp] write :%s failed, ret:%d\n", CEC_MSG_OUT_FIFO, ret);
+        return -1;
+    }
+    return ret;
+}
+
+void HdmiCecMock::printCecMsgBuf(const char* msg_buf, int len) {
+    char buf[64] = {};
+    int i, size = 0;
+    memset(buf, 0, sizeof(buf));
+    for (i = 0; i < len; i++) {
+        size += sprintf(buf + size, " %02x", msg_buf[i]);
+    }
+    ALOGD("[halimp] %s, msg:%s", __FUNCTION__, buf);
+}
+
+void HdmiCecMock::handleHotplugMessage(unsigned char* msgBuf) {
+    HotplugEvent hotplugEvent{.connected = ((msgBuf[3]) & 0xf) > 0,
+                              .portId = static_cast<uint32_t>(msgBuf[0] & 0xf)};
+
+    if (hotplugEvent.portId >= mPortInfo.size()) {
+        ALOGD("[halimp] ignore hot plug message, id %x does not exist", hotplugEvent.portId);
+        return;
+    }
+
+    ALOGD("[halimp] hot plug port id %x, is connected %x", (msgBuf[0] & 0xf), (msgBuf[3] & 0xf));
+    if (mPortInfo[hotplugEvent.portId].type == HdmiPortType::OUTPUT) {
+        mPhysicalAddress =
+                ((hotplugEvent.connected == 0) ? 0xffff : ((msgBuf[1] << 8) | (msgBuf[2])));
+        mPortInfo[hotplugEvent.portId].physicalAddress = mPhysicalAddress;
+        ALOGD("[halimp] hot plug physical address %x", mPhysicalAddress);
+    }
+
+    // todo update connection status
+
+    if (mCallback != nullptr) {
+        mCallback->onHotplugEvent(hotplugEvent);
+    }
+}
+
+void HdmiCecMock::handleCecMessage(unsigned char* msgBuf, int megSize) {
+    CecMessage message;
+    size_t length = std::min(static_cast<size_t>(megSize - 1),
+                             static_cast<size_t>(MaxLength::MESSAGE_BODY));
+    message.body.resize(length);
+
+    for (size_t i = 0; i < length; ++i) {
+        message.body[i] = static_cast<uint8_t>(msgBuf[i + 1]);
+        ALOGD("[halimp] msg body %x", message.body[i]);
+    }
+
+    message.initiator = static_cast<CecLogicalAddress>((msgBuf[0] >> 4) & 0xf);
+    ALOGD("[halimp] msg init %x", message.initiator);
+    message.destination = static_cast<CecLogicalAddress>((msgBuf[0] >> 0) & 0xf);
+    ALOGD("[halimp] msg dest %x", message.destination);
+
+    // messageValidateAndHandle(&event);
+
+    if (mCallback != nullptr) {
+        mCallback->onCecMessage(message);
+    }
+}
+
+void HdmiCecMock::threadLoop() {
+    ALOGD("[halimp] threadLoop start.");
+    unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
+    int r = -1;
+
+    // open the input pipe
+    while (mInputFile < 0) {
+        usleep(1000 * 1000);
+        mInputFile = open(CEC_MSG_IN_FIFO, O_RDONLY);
+    }
+    ALOGD("[halimp] file open ok, fd = %d.", mInputFile);
+
+    while (mCecThreadRun) {
+        if (!mOptionSystemCecControl) {
+            usleep(1000 * 1000);
+            continue;
+        }
+
+        memset(msgBuf, 0, sizeof(msgBuf));
+        // try to get a message from dev.
+        // echo -n -e '\x04\x83' >> /dev/cec
+        r = readMessageFromFifo(msgBuf, CEC_MESSAGE_BODY_MAX_LENGTH);
+        if (r <= 1) {
+            // ignore received ping messages
+            continue;
+        }
+
+        printCecMsgBuf((const char*)msgBuf, r);
+
+        if (((msgBuf[0] >> 4) & 0xf) == 0xf) {
+            // the message is a hotplug event
+            handleHotplugMessage(msgBuf);
+            continue;
+        }
+
+        handleCecMessage(msgBuf, r);
+    }
+
+    ALOGD("[halimp] thread end.");
+    // mCecDevice.mExited = true;
+}
+
+HdmiCecMock::HdmiCecMock() {
+    ALOGE("[halimp] Opening a virtual HAL for testing and virtual machine.");
+    mCallback = nullptr;
+    mPortInfo.resize(mTotalPorts);
+    mPortConnectionStatus.resize(mTotalPorts);
+    mPortInfo[0] = {.type = HdmiPortType::OUTPUT,
+                    .portId = static_cast<uint32_t>(0),
+                    .cecSupported = true,
+                    .arcSupported = false,
+                    .physicalAddress = mPhysicalAddress};
+    mPortConnectionStatus[0] = false;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace cec
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/cec/1.0/default/HdmiCecMock.h b/tv/cec/1.0/default/HdmiCecMock.h
new file mode 100644
index 0000000..0a708fa
--- /dev/null
+++ b/tv/cec/1.0/default/HdmiCecMock.h
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H
+#define ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H
+
+#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
+#include <hardware/hardware.h>
+#include <hardware/hdmi_cec.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::tv::cec::V1_0::CecLogicalAddress;
+using ::android::hardware::tv::cec::V1_0::CecMessage;
+using ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
+using ::android::hardware::tv::cec::V1_0::IHdmiCec;
+using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback;
+using ::android::hardware::tv::cec::V1_0::MaxLength;
+using ::android::hardware::tv::cec::V1_0::OptionKey;
+using ::android::hardware::tv::cec::V1_0::Result;
+using ::android::hardware::tv::cec::V1_0::SendMessageResult;
+
+#define CEC_MSG_IN_FIFO "/dev/cec_in_pipe"
+#define CEC_MSG_OUT_FIFO "/dev/cec_out_pipe"
+
+struct HdmiCecMock : public IHdmiCec, public hidl_death_recipient {
+    HdmiCecMock();
+    // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
+    Return<Result> addLogicalAddress(CecLogicalAddress addr) override;
+    Return<void> clearLogicalAddress() override;
+    Return<void> getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) override;
+    Return<SendMessageResult> sendMessage(const CecMessage& message) override;
+    Return<void> setCallback(const sp<IHdmiCecCallback>& callback) override;
+    Return<int32_t> getCecVersion() override;
+    Return<uint32_t> getVendorId() override;
+    Return<void> getPortInfo(getPortInfo_cb _hidl_cb) override;
+    Return<void> setOption(OptionKey key, bool value) override;
+    Return<void> setLanguage(const hidl_string& language) override;
+    Return<void> enableAudioReturnChannel(int32_t portId, bool enable) override;
+    Return<bool> isConnected(int32_t portId) override;
+
+    virtual void serviceDied(uint64_t /*cookie*/,
+                             const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+        setCallback(nullptr);
+    }
+
+    void cec_set_option(int flag, int value);
+    void printCecMsgBuf(const char* msg_buf, int len);
+
+  private:
+    static void* __threadLoop(void* data);
+    void threadLoop();
+    int readMessageFromFifo(unsigned char* buf, int msgCount);
+    int sendMessageToFifo(const CecMessage& message);
+    void handleHotplugMessage(unsigned char* msgBuf);
+    void handleCecMessage(unsigned char* msgBuf, int length);
+
+  private:
+    sp<IHdmiCecCallback> mCallback;
+
+    // Variables for the virtual cec hal impl
+    uint16_t mPhysicalAddress = 0xFFFF;
+    vector<CecLogicalAddress> mLogicalAddresses;
+    int32_t mCecVersion = 0;
+    uint32_t mCecVendorId = 0;
+
+    // Port configuration
+    int mTotalPorts = 1;
+    hidl_vec<HdmiPortInfo> mPortInfo;
+    hidl_vec<bool> mPortConnectionStatus;
+
+    // CEC Option value
+    int mOptionWakeUp = 0;
+    int mOptionEnableCec = 0;
+    int mOptionSystemCecControl = 0;
+    int mOptionLanguage = 0;
+
+    // Testing variables
+    // Input file descriptor
+    int mInputFile;
+    // Output file descriptor
+    int mOutputFile;
+    bool mCecThreadRun = true;
+    pthread_t mThreadId = 0;
+};
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace cec
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H
diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.rc b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.rc
new file mode 100644
index 0000000..170b485
--- /dev/null
+++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.rc
@@ -0,0 +1,5 @@
+service vendor.cec-hal-1-0-mock /vendor/bin/hw/android.hardware.tv.cec@1.0-service.mock
+    interface android.hardware.tv.cec@1.0::IHdmiCec default
+    class hal
+    user system
+    group system
diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.xml b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.xml
new file mode 100644
index 0000000..5afa59d
--- /dev/null
+++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.tv.cec</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IHdmiCec</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
index 8595099..6d25229 100644
--- a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
+++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.cec-hal-1-0 /vendor/bin/hw/android.hardware.tv.cec@1.0-service
+    interface android.hardware.tv.cec@1.0::IHdmiCec default
     class hal
     user system
     group system
diff --git a/tv/cec/1.0/default/serviceMock.cpp b/tv/cec/1.0/default/serviceMock.cpp
new file mode 100644
index 0000000..c0af22f
--- /dev/null
+++ b/tv/cec/1.0/default/serviceMock.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 "android.hardware.tv.cec@1.0-service-shim"
+
+#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
+#include <hidl/LegacySupport.h>
+#include "HdmiCecMock.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::tv::cec::V1_0::IHdmiCec;
+using android::hardware::tv::cec::V1_0::implementation::HdmiCecMock;
+
+int main() {
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    android::sp<IHdmiCec> service = new HdmiCecMock();
+    android::status_t status;
+    status = service->registerAsService();
+    LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering mock cec service: %d",
+                        status);
+
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/tv/cec/2.0/Android.bp b/tv/cec/2.0/Android.bp
index 5a67fa5..61450ac 100644
--- a/tv/cec/2.0/Android.bp
+++ b/tv/cec/2.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tv/cec/2.0/default/Android.bp b/tv/cec/2.0/default/Android.bp
index 6e624e3..d3d5342 100644
--- a/tv/cec/2.0/default/Android.bp
+++ b/tv/cec/2.0/default/Android.bp
@@ -7,7 +7,6 @@
 
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libbase",
         "libutils",
@@ -35,7 +34,6 @@
         "libhardware_legacy",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.tv.cec@2.0",
     ],
 
diff --git a/tv/input/1.0/Android.bp b/tv/input/1.0/Android.bp
index a6c1959..1164430 100644
--- a/tv/input/1.0/Android.bp
+++ b/tv/input/1.0/Android.bp
@@ -15,7 +15,6 @@
         "android.hardware.audio.common@2.0",
         "android.hidl.base@1.0",
     ],
-    gen_java: false,
+    gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/tv/input/1.0/default/Android.bp b/tv/input/1.0/default/Android.bp
index 7c140a5..5f6b7e7 100644
--- a/tv/input/1.0/default/Android.bp
+++ b/tv/input/1.0/default/Android.bp
@@ -10,7 +10,6 @@
         "liblog",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.audio.common@2.0",
         "android.hardware.tv.input@1.0",
@@ -35,7 +34,6 @@
         "libhardware_legacy",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.audio.common@2.0",
         "android.hardware.tv.input@1.0",
     ],
diff --git a/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc b/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
index 972c654..6cb9a43 100644
--- a/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
+++ b/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.tv-input-1-0 /vendor/bin/hw/android.hardware.tv.input@1.0-service
+    interface android.hardware.tv.input@1.0::ITvInput default
     class hal
     user system
     group system
diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp
new file mode 100644
index 0000000..d78f3f2
--- /dev/null
+++ b/tv/tuner/1.0/Android.bp
@@ -0,0 +1,30 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.tv.tuner@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IDemux.hal",
+        "IDescrambler.hal",
+        "IDvr.hal",
+        "IDvrCallback.hal",
+        "IFilter.hal",
+        "IFilterCallback.hal",
+        "IFrontend.hal",
+        "IFrontendCallback.hal",
+        "ILnb.hal",
+        "ILnbCallback.hal",
+        "ITimeFilter.hal",
+        "ITuner.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal
new file mode 100644
index 0000000..16fc392
--- /dev/null
+++ b/tv/tuner/1.0/IDemux.hal
@@ -0,0 +1,162 @@
+/*
+ * 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.tv.tuner@1.0;
+
+import IDvr;
+import IDvrCallback;
+import IFilter;
+import IFilterCallback;
+import ITimeFilter;
+
+/**
+ * Demultiplexer(Demux) takes a single multiplexed input and splits it into
+ * one or more output.
+ */
+interface IDemux {
+    /**
+     * Set a frontend resource as data input of the demux
+     *
+     * It is used by the client to specify a hardware frontend as data source of
+     * this demux instance. A demux instance can have only one data source.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setFrontendDataSource(FrontendId frontendId) generates (Result result);
+
+    /**
+     * Open a new filter in the demux
+     *
+     * It is used by the client to open a filter in the demux.
+     *
+     * @param type the type of the filter to be added.
+     * @param bufferSize the buffer size of the filter to be opened. It's used
+     * to create a FMQ(Fast Message Queue) to hold data output from the filter.
+     * @param cb the callback for the filter to be used to send notifications
+     * back to the client.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return filter the filter instance of the newly added.
+     */
+    openFilter(DemuxFilterType type, uint32_t bufferSize, IFilterCallback cb)
+        generates (Result result, IFilter filter);
+
+    /**
+     * Open time filter of the demux
+     *
+     * It is used by the client to open time filter of the demux.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNAVAILABLE if time filter is not supported.
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return timeFilter the time filter instance of the newly added.
+     */
+    openTimeFilter() generates (Result result, ITimeFilter timeFilter);
+
+    /**
+     * Get hardware sync ID for audio and video.
+     *
+     * It is used by the client to get the hardware sync ID for audio and video.
+     *
+     * @param filter the filter instance.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if failed for a wrong filter ID.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return avSyncHwId the id of hardware A/V sync.
+     */
+    getAvSyncHwId(IFilter filter) generates (Result result, AvSyncHwId avSyncHwId);
+
+    /**
+     * Get current time stamp to use for A/V sync
+     *
+     * It is used by the client to get current time stamp for A/V sync. HW is
+     * supported to increment and maintain current time stamp.
+     *
+     * @param avSyncHwId the hardware id of A/V sync.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if failed for a wrong hardware ID of A/V sync.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return time the current time stamp of hardware A/V sync. The time stamp
+     * based on 90KHz has the same format as PTS (Presentation Time Stamp).
+     */
+    getAvSyncTime(AvSyncHwId avSyncHwId) generates (Result result, uint64_t time);
+
+    /**
+     * Close the Demux instance
+     *
+     * It is used by the client to release the demux instance. HAL clear
+     * underneath resource. client mustn't access the instance any more.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+
+    /**
+     * Open a DVR (Digital Video Record) instance in the demux
+     *
+     * It is used by the client to record and playback.
+     *
+     * @param type specify which kind of DVR to open.
+     * @param bufferSize the buffer size of the output to be added. It's used to
+     * create a FMQ(Fast Message Queue) to hold data from selected filters.
+     * @param cb the callback for the DVR to be used to send notifications
+     * back to the client.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         OUT_OF_MEMORY if failed for not enough memory.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return dvr a DVR instance.
+     */
+    openDvr(DvrType type, uint32_t bufferSize, IDvrCallback cb)
+        generates (Result result, IDvr dvr);
+
+    /**
+     * Connect Conditional Access Modules (CAM) through Common Interface (CI)
+     *
+     * It is used by the client to connect CI-CAM. The demux uses the output
+     * from the frontend as the input by default, and must change to use the
+     * output from CI-CAM as the input after this call take place.
+     *
+     * @param ciCamId specify CI-CAM Id to connect.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    connectCiCam(uint32_t ciCamId) generates (Result result);
+
+    /**
+     * Disconnect Conditional Access Modules (CAM)
+     *
+     * It is used by the client to disconnect CI-CAM. The demux will use the
+     * output from the frontend as the input after this call take place.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    disconnectCiCam() generates (Result result);
+};
diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal
new file mode 100644
index 0000000..7f98865
--- /dev/null
+++ b/tv/tuner/1.0/IDescrambler.hal
@@ -0,0 +1,99 @@
+/*
+ * 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.tv.tuner@1.0;
+
+import IFilter;
+
+/**
+ * Descrambler is used to descramble input data.
+ *
+ */
+interface IDescrambler {
+    /**
+     * Set a demux as source of the descrambler
+     *
+     * It is used by the client to specify a demux as source of this
+     * descrambler. A descrambler instance can have only one source, and
+     * this method can be only called once.
+     *
+     * @param demuxId the id of the demux to be used as descrambler's source.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setDemuxSource(DemuxId demuxId) generates (Result result);
+
+    /**
+     * Set a key token to link descrambler to a key slot
+     *
+     * It is used by the client to link a hardware key slot to a descrambler.
+     * A descrambler instance can have only one key slot to link, but a key
+     * slot can hold a few keys for different purposes.
+     *
+     * @param keyToken the token to be used to link the key slot.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setKeyToken(TunerKeyToken keyToken) generates (Result result);
+
+    /**
+     * Add packets' PID to the descrambler for descrambling
+     *
+     * It is used by the client to specify Package ID (PID) of packets which the
+     * descrambler start to descramble. Multiple PIDs can be added into one
+     * descrambler instance because descambling can happen simultaneously on
+     * packets from different PIDs.
+     *
+     * @param pid the PID of packets to start to be descrambled.
+     * @param filter an optional filter instance to identify upper stream.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    addPid(DemuxPid pid, IFilter optionalSourceFilter) generates (Result result);
+
+    /**
+     * Remove packets' PID from the descrambler
+     *
+     * It is used by the client to specify Package ID (PID) of packets which the
+     * descrambler stop to descramble.
+     *
+     * @param pid the PID of packets to stop to be descrambled.
+     * @param filter an optional filter instance to identify upper stream.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    removePid(DemuxPid pid, IFilter optionalSourceFilter) generates (Result result);
+
+    /**
+     * Release the descrambler instance
+     *
+     * It is used by the client to release the descrambler instance. HAL clear
+     * underneath resource. client mustn't access the instance any more.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/IDvr.hal b/tv/tuner/1.0/IDvr.hal
new file mode 100644
index 0000000..f57e4b6
--- /dev/null
+++ b/tv/tuner/1.0/IDvr.hal
@@ -0,0 +1,133 @@
+/*
+ * 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.tv.tuner@1.0;
+
+import IFilter;
+
+/**
+ * Digtal Video Record (DVR) interface provides record control on Demux's
+ * output buffer and playback control on Demux's input buffer.
+ */
+interface IDvr {
+    /**
+     * Get the descriptor of the DVR's FMQ
+     *
+     * It is used by the client to get the descriptor of the DVR's Fast
+     * Message Queue. The FMQ is used to transfer record or playback data
+     * between the client and the HAL.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return queue the descriptor of the DVR's FMQ
+     */
+    getQueueDesc() generates (Result result, fmq_sync<uint8_t> queue);
+
+    /**
+     * Configure the DVR.
+     *
+     * It is used by the client to configure the DVR interface.
+     *
+     * @param settings the settings of the DVR interface.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    configure(DvrSettings settings) generates (Result result);
+
+    /**
+     * Attach one filter to DVR interface for recording.
+     *
+     * It is used by the client to add the data filtered out from the filter
+     * to record.
+     *
+     * @param filter the instance of the attached filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    attachFilter(IFilter filter) generates (Result result);
+
+    /**
+     * Detach one filter from the DVR's recording.
+     *
+     * It is used by the client to remove the data of the filter from DVR's
+     * recording.
+     *
+     * @param filter the instance of the detached filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    detachFilter(IFilter filter) generates (Result result);
+
+    /**
+     * Start DVR.
+     *
+     * It is used by the client to ask the DVR to start consuming playback data
+     * or producing data for record.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    start() generates (Result result);
+
+    /**
+     * Stop DVR.
+     *
+     * It is used by the client to ask the DVR to stop consuming playback data
+     * or producing data for record.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    stop() generates (Result result);
+
+    /**
+     * Flush DVR data.
+     *
+     * It is used by the client to ask the DVR to flush the data which is
+     * not consumed by HAL for playback or the client for record yet.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    flush() generates (Result result);
+
+    /**
+     * close the DVR instance to release resource for DVR.
+     *
+     * It is used by the client to close the DVR instance, and HAL clears
+     * underneath resource for this DVR instance. Client mustn't access the
+     * instance any more and all methods should return a failure.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/IDvrCallback.hal b/tv/tuner/1.0/IDvrCallback.hal
new file mode 100644
index 0000000..337eddc
--- /dev/null
+++ b/tv/tuner/1.0/IDvrCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.tv.tuner@1.0;
+
+interface IDvrCallback {
+    /**
+     * Notify the client a new status of the demux's record.
+     *
+     * @param status a new status of the demux's record.
+     */
+    oneway onRecordStatus(RecordStatus status);
+
+    /**
+     * Notify the client a new status of the demux's playback.
+     *
+     * @param status a new status of the demux's playback.
+     */
+    oneway onPlaybackStatus(PlaybackStatus status);
+};
diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal
new file mode 100644
index 0000000..3ed09f6
--- /dev/null
+++ b/tv/tuner/1.0/IFilter.hal
@@ -0,0 +1,158 @@
+/*
+ * 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.tv.tuner@1.0;
+
+import IFilterCallback;
+
+/**
+ * The Filter is used to filter wanted data according to the filter's
+ * configuration.
+ */
+interface IFilter {
+    /**
+     * Get the descriptor of the filter's FMQ
+     *
+     * It is used by the client to get the descriptor of the filter's Fast
+     * Message Queue. The data in FMQ is filtered out from demux input or upper
+     * stream's filter. The data is origanized to data blocks which may have
+     * different length. The length's information of one or multiple data blocks
+     * is sent to client through DemuxFilterEvent. The data in each block
+     * follows the stardard specified by filter's type.
+     * E.X. one data block from the filter with Main_Type==TS and Sub_Type==PES
+     * is Packetized Elementary Stream from Transport Stream according to
+     * ISO/IEC 13818-1.
+     *
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNAVAILABLE if the filter doesn't have FMQ.
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return queue the descriptor of the filter's FMQ
+     */
+    getQueueDesc() generates (Result result, fmq_sync<uint8_t> queue);
+
+    /**
+     * Configure the filter.
+     *
+     * It is used by the client to configure the filter so that it can filter out
+     * intended data.
+     *
+     * @param settings the settings of the filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    configure(DemuxFilterSettings settings) generates (Result result);
+
+    /**
+     * Start the filter.
+     *
+     * It is used by the client to ask the filter to start filterring data.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    start() generates (Result result);
+
+    /**
+     * Stop the filter.
+     *
+     * It is used by the client to ask the filter to stop filterring data.
+     * It won't discard the data already filtered out by the filter. The filter
+     * will be stopped and removed automatically if the demux is closed.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    stop() generates (Result result);
+
+    /**
+     * Flush the filter.
+     *
+     * It is used by the client to ask the filter to flush the data which is
+     * already produced but not consumed yet.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    flush() generates (Result result);
+
+    /**
+     * Get the filter Id.
+     *
+     * It is used by the client to ask the hardware resource id for the filter.
+     *
+     * @param filterId the hardware resource Id for the filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    getId() generates (Result result, uint32_t filterId);
+
+    /**
+     * Release the handle reported by the HAL for AV memory.
+     *
+     * It is used by the client to notify the HAL that the AV handle won't be
+     * used any more in client side, so that the HAL can mark the memory
+     * presented by file descripor in the handle as released.
+     *
+     * @param avMemory A handle associated to the memory for audio or video.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if failed for wrong parameter.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    releaseAvHandle(handle avMemory) generates (Result result);
+
+    /**
+     * Set the filter's data source.
+     *
+     * A filter uses demux as data source by default. If the data was packetized
+     * by multiple protocols, multiple filters may need to work together to
+     * extract all protocols' header. Then a filter's data source can be output
+     * from another filter.
+     *
+     * @param filter the filter instance which provides data input. Switch to
+     * use demux as data source if the filter instance is NULL.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setDataSource(IFilter filter) generates (Result result);
+
+    /**
+     * Release the Filter instance
+     *
+     * It is used by the client to release the Filter instance. HAL clear
+     * underneath resource. client mustn't access the instance any more.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/IFilterCallback.hal b/tv/tuner/1.0/IFilterCallback.hal
new file mode 100644
index 0000000..a0ff62e
--- /dev/null
+++ b/tv/tuner/1.0/IFilterCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.tv.tuner@1.0;
+
+interface IFilterCallback {
+    /**
+     * Notify the client that a new filter event happened.
+     *
+     * @param filterEvent a filter event.
+     */
+    oneway onFilterEvent(DemuxFilterEvent filterEvent);
+
+    /**
+     * Notify the client a new status of a filter.
+     *
+     * @param status a new status of the filter.
+     */
+    oneway onFilterStatus(DemuxFilterStatus status);
+};
diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
new file mode 100644
index 0000000..ceda2b3
--- /dev/null
+++ b/tv/tuner/1.0/IFrontend.hal
@@ -0,0 +1,161 @@
+/*
+ * 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.tv.tuner@1.0;
+
+import IFrontendCallback;
+import ILnb;
+
+/**
+ * A Tuner Frontend is used to tune to a frequency and lock signal. It provide
+ * live data feed to Tuner Demux interface.
+ */
+interface IFrontend {
+    /**
+     * Set the callback
+     *
+     * It is used by the client to receive events from the Frontend.
+     * Only one callback for one Frontend instance is supported. The callback
+     * will be replaced if it's set again.
+     *
+     * @param callback Callback object to pass Frontend events to the system.
+     *        The previously registered callback must be replaced with this one.
+     *        It can be null.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if callback can't be set at current stage,
+     *         UNKNOWN_ERROR if callback setting failed for other reasons.
+     */
+    setCallback(IFrontendCallback callback) generates (Result result);
+
+    /**
+     * Tuning Frontend
+     *
+     * It is used by the client to lock a frequency by providing signal
+     * delivery information. If previous tuning isn't completed, this call must
+     * stop previous tuning, and start a new tuning. Tune is a async call.
+     * LOCKED or NO_SIGNAL eventi is sent back to caller through callback.
+     *
+     * @param settings Signal delivery information which frontend can use to
+     * search and lock the signal.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if tuning can't be applied at current stage,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     */
+    tune(FrontendSettings settings) generates (Result result);
+
+    /**
+     * Stop the tuning
+     *
+     * It is used by the client to stop a previous tuning.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successfully stop tuning.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    stopTune() generates (Result result);
+
+    /**
+     * Release the Frontend instance
+     *
+     * It is used by the client to release the frontend instance. HAL clear
+     * underneath resource. client mustn't access the instance any more.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+
+    /**
+     * Scan the frontend to use the settings given.
+     *
+     * This uses the frontend to start a scan from signal delivery information.
+     * If previous scan isn't completed, this call MUST stop previous scan,
+     * and start a new scan.
+     * Scan is an async call, with FrontendScanMessage sent via callback.
+     *
+     * @param settings Signal delivery information which the frontend uses to
+     * scan the signal.
+     * @param type the type which the frontend uses to scan the signal.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if tuning can't be applied at current stage,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     */
+    scan(FrontendSettings settings, FrontendScanType type) generates (Result result);
+
+    /**
+     * Stops a previous scanning.
+     *
+     * If the method completes successfully, the frontend stop previous
+     * scanning.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successfully stop tuning.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    stopScan() generates (Result result);
+
+    /**
+     * Gets the statuses of the frontend.
+     *
+     * This retrieve the statuses of the frontend for given status types.
+     *
+     * @param statusTypes an array of status type which the caller request.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if tuning can't be applied at current stage,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     * @return statuses an array of statuses which response the caller's
+     *         request.
+     */
+    getStatus(vec<FrontendStatusType> statusTypes)
+        generates (Result result, vec<FrontendStatus> statuses);
+
+    /**
+     * Sets Low-Noise Block downconverter (LNB) for satellite frontend.
+     *
+     * This assigns a hardware LNB resource to the satellite frontend. It can be
+     * called multiple times to update LNB assignment. The LNB resource must be
+     * released when the frontend is closed.
+     *
+     * @param lnbId the Id of assigned LNB resource.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if the frontend can't be set with a LNB, such as
+     *         cable frontend.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setLnb(LnbId lnbId) generates (Result result);
+
+    /**
+     * Enble or Disable Low Noise Amplifier (LNA).
+     *
+     * @param bEnable true if activate LNA module; false if deactivate LNA
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if the frontend doesn't support LNA.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setLna(bool bEnable) generates (Result result);
+};
diff --git a/tv/tuner/1.0/IFrontendCallback.hal b/tv/tuner/1.0/IFrontendCallback.hal
new file mode 100644
index 0000000..88b96c4
--- /dev/null
+++ b/tv/tuner/1.0/IFrontendCallback.hal
@@ -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.
+ */
+
+package android.hardware.tv.tuner@1.0;
+
+interface IFrontendCallback {
+    /**
+     * Notify the client that a new event happened on the frontend.
+     *
+     * @param frontendEventType the event type.
+     */
+    oneway onEvent(FrontendEventType frontendEventType);
+
+    /**
+     * The callback function that must be called by HAL implementation to notify
+     * the client of scan messages.
+     *
+     * @param type the type of scan message.
+     * @param message the scan message sent by HAL to the client.
+     */
+    oneway onScanMessage(FrontendScanMessageType type, FrontendScanMessage message);
+};
diff --git a/tv/tuner/1.0/ILnb.hal b/tv/tuner/1.0/ILnb.hal
new file mode 100644
index 0000000..5070519
--- /dev/null
+++ b/tv/tuner/1.0/ILnb.hal
@@ -0,0 +1,106 @@
+/*
+ * 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.tv.tuner@1.0;
+
+import ILnbCallback;
+
+/**
+ * A Tuner LNB (low-noise block downconverter) is used by satellite frontend
+ * to receive the microwave signal from the satellite, amplify it, and
+ * downconvert the frequency to a lower frequency.
+ */
+interface ILnb {
+    /**
+     * Set the lnb callback.
+     *
+     * ILnbCallback is used by the client to receive events from the Lnb.
+     * Only one callback per ILnb instance is supported. The callback
+     * will be replaced if it's set again.
+     *
+     * @param callback Callback object to pass Lnb events to the system.
+     *        The previously registered callback must be replaced with this one.
+     *        It can be null.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if callback can't be set at current stage,
+     *         UNKNOWN_ERROR if callback setting failed for other reasons.
+     */
+    setCallback(ILnbCallback callback) generates (Result result);
+
+    /**
+     * Set the lnb's power voltage.
+     *
+     * @param voltage the power's voltage the Lnb to use.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if the selected voltage isn't allowed,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setVoltage(LnbVoltage voltage) generates (Result result);
+
+    /**
+     * Set the lnb's tone mode.
+     *
+     * @param tone the tone mode the Lnb to use.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if the selected tone mode isn't allowed,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setTone(LnbTone tone) generates (Result result);
+
+    /**
+     * Select the lnb's position.
+     *
+     * @param position the position the Lnb to use.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if the selected position isn't allowed,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setSatellitePosition(LnbPosition position) generates (Result result);
+
+    /**
+     *  Sends DiSEqC (Digital Satellite Equipment Control) message.
+     *
+     * Client sends DiSeqc message to DiSEqc to LNB. The response message from
+     * the device comes back to the client through frontend's callback
+     * onDiseqcMessage.
+     *
+     * @param diseqcMessage a byte array of data for DiSEqC message which is
+     *        specified by EUTELSAT Bus Functional Specification Version 4.2.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if the frontend can't send DiSEqc Message, such as
+     *         cable frontend.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    sendDiseqcMessage(vec<uint8_t> diseqcMessage) generates (Result result);
+
+    /**
+     * Releases the LNB instance
+     *
+     * Associated resources are released.  close may be called more than once.
+     * Calls to any other method after this will return an error
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/ILnbCallback.hal b/tv/tuner/1.0/ILnbCallback.hal
new file mode 100644
index 0000000..68e9c35
--- /dev/null
+++ b/tv/tuner/1.0/ILnbCallback.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.tv.tuner@1.0;
+
+interface ILnbCallback {
+    /**
+     * Notify the client that a new event happened on the Lnb.
+     *
+     * @param LnbEventType the event type.
+     */
+    oneway onEvent(LnbEventType lnbEventType);
+
+    /**
+     * The callback function that must be called by HAL implementation to notify
+     * the client of new DiSEqC message.
+     *
+     * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite
+     * Equipment Control) message which is specified by EUTELSAT Bus Functional
+     * Specification Version 4.2.
+     */
+    oneway onDiseqcMessage(vec<uint8_t> diseqcMessage);
+};
diff --git a/tv/tuner/1.0/ITimeFilter.hal b/tv/tuner/1.0/ITimeFilter.hal
new file mode 100644
index 0000000..ce285db
--- /dev/null
+++ b/tv/tuner/1.0/ITimeFilter.hal
@@ -0,0 +1,88 @@
+/*
+ * 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.tv.tuner@1.0;
+
+/**
+ * Timer Filter is used by Demux to filter data based on time stamp.
+ */
+interface ITimeFilter {
+    /**
+     * Set time stamp for time based filter.
+     *
+     * It is used by the client to set initial time stamp and enable time
+     * filtering. The time will be incremented locally. The demux discards
+     * the content which time stamp is older than the time in the time filter.
+     *
+     * @param timeStamp initial time stamp for the time filter. It based on
+     * 90KHz has the same format as PTS (Presentation Time Stamp).
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setTimeStamp(uint64_t timeStamp) generates (Result result);
+
+    /**
+     * Clear the time stamp in the time filter.
+     *
+     * It is used by the client to clear the time value of the time filter,
+     * then disable time filter.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    clearTimeStamp() generates (Result result);
+
+    /**
+     * Get the current time in the time filter.
+     *
+     * It is used by the client to inquiry current time in the time filter.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return timeStamp current time stamp in the time filter.
+     */
+    getTimeStamp() generates (Result result, uint64_t timeStamp);
+
+    /**
+     * Get the time from the beginning of current data source.
+     *
+     * It is used by the client to inquiry the time stamp from the beginning
+     * of current data source.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return timeStamp time stamp from the beginning of current data source.
+     */
+    getSourceTime() generates (Result result, uint64_t timeStamp);
+
+    /**
+     * Close the Time Filter instance
+     *
+     * It is used by the client to release the demux instance. HAL clear
+     * underneath resource. client mustn't access the instance any more.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal
new file mode 100644
index 0000000..2712c13
--- /dev/null
+++ b/tv/tuner/1.0/ITuner.hal
@@ -0,0 +1,126 @@
+/*
+ * 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.tv.tuner@1.0;
+
+import IDemux;
+import IDescrambler;
+import IFrontend;
+import ILnb;
+
+/**
+ * Top level interface to manage Frontend, Demux and Decrambler hardware
+ * resouces which are needed for Android TV.
+ */
+interface ITuner {
+    /**
+     * Get Frontend IDs
+     *
+     * It is used by the client to get all available frontends' IDs.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     * @return frontendIds an array of FrontendId for the available frontends.
+     */
+    getFrontendIds() generates (Result result, vec<FrontendId> frontendIds);
+
+    /**
+     * Create a new instance of Frontend given a frontendId.
+     *
+     * It is used by the client to create a frontend instance.
+     *
+     * @param frontendId the id of the frontend to be opened.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNAVAILABLE if no resource.
+     *         UNKNOWN_ERROR if creation failed for other reasons.
+     * @return frontend the newly created frontend interface.
+     */
+    openFrontendById(FrontendId frontendId) generates (Result result, IFrontend frontend);
+
+    /**
+     * Create a new instance of Demux.
+     *
+     * It is used by the client to create a Demux instance.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if creation failed for other reasons.
+     * @return demuxId newly created demux id.
+     * @return demux the newly created demux interface.
+     */
+    openDemux() generates (Result result, DemuxId demuxId, IDemux demux);
+
+    /**
+     * Retrieve the Demux's Capabilities.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if the inquiry failed for other reasons.
+     * @return caps the Demux's Capabilities.
+     */
+    getDemuxCaps() generates (Result result, DemuxCapabilities caps);
+
+    /**
+     * Create a new instance of Descrambler.
+     *
+     * It is used by the client to create a Descrambler instance.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if creation failed for other reasons.
+     * @return descrambler the newly created descrambler interface.
+     */
+    openDescrambler() generates (Result result, IDescrambler descrambler);
+
+    /**
+     * Retrieve the frontend's information.
+     *
+     * @param frontendId the id of the frontend to be inquiried.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if the inquiry failed for other reasons.
+     * @return info the frontend's information.
+     */
+    getFrontendInfo(FrontendId frontendId) generates (Result result, FrontendInfo info);
+
+    /**
+     * Get low-noise block downconverter (LNB) IDs.
+     *
+     * It is used by the client to get all available LNBs' IDs.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     * @return frontendIds an array of LnbId for the available LNBs.
+     */
+    getLnbIds() generates (Result result, vec<LnbId> lnbIds);
+
+    /**
+     * Create a new instance of Lnb given a lnbId.
+     *
+     * It is used by the client to create a Lnb instance for satellite Frontend.
+     *
+     * @param lnbId the id of the LNB to be opened.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNAVAILABLE if no resource.
+     *         UNKNOWN_ERROR if creation failed for other reasons.
+     * @return lnb the newly created Lnb interface.
+     */
+    openLnbById(LnbId lnbId) generates (Result result, ILnb lnb);
+};
diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp
new file mode 100644
index 0000000..989e25c
--- /dev/null
+++ b/tv/tuner/1.0/default/Android.bp
@@ -0,0 +1,50 @@
+cc_defaults {
+    name: "tuner_service_defaults",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "Filter.cpp",
+        "Frontend.cpp",
+        "Descrambler.cpp",
+        "Demux.cpp",
+        "Dvr.cpp",
+        "TimeFilter.cpp",
+        "Tuner.cpp",
+        "Lnb.cpp",
+        "service.cpp",
+    ],
+
+    compile_multilib: "first",
+
+    shared_libs: [
+        "android.hardware.tv.tuner@1.0",
+        "android.hidl.memory@1.0",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "libhidlmemory",
+        "liblog",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+    header_libs: [
+        "media_plugin_headers",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.tv.tuner@1.0-service",
+    vintf_fragments: ["android.hardware.tv.tuner@1.0-service.xml"],
+    defaults: ["tuner_service_defaults"],
+    init_rc: ["android.hardware.tv.tuner@1.0-service.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.tv.tuner@1.0-service-lazy",
+    vintf_fragments: ["android.hardware.tv.tuner@1.0-service-lazy.xml"],
+    overrides: ["android.hardware.tv.tuner@1.0-service"],
+    defaults: ["tuner_service_defaults"],
+    init_rc: ["android.hardware.tv.tuner@1.0-service-lazy.rc"],
+    cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
new file mode 100644
index 0000000..71a26ab
--- /dev/null
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -0,0 +1,283 @@
+/*
+ * 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 "android.hardware.tv.tuner@1.0-Demux"
+
+#include "Demux.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+
+Demux::Demux(uint32_t demuxId, sp<Tuner> tuner) {
+    mDemuxId = demuxId;
+    mTunerService = tuner;
+}
+
+Demux::~Demux() {}
+
+Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (mTunerService == nullptr) {
+        return Result::NOT_INITIALIZED;
+    }
+
+    mFrontend = mTunerService->getFrontendById(frontendId);
+
+    if (mFrontend == nullptr) {
+        return Result::INVALID_STATE;
+    }
+
+    mFrontendSourceFile = mFrontend->getSourceFile();
+
+    mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
+    return startBroadcastInputLoop();
+}
+
+Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
+                               const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint32_t filterId;
+
+    if (!mUnusedFilterIds.empty()) {
+        filterId = *mUnusedFilterIds.begin();
+
+        mUnusedFilterIds.erase(filterId);
+    } else {
+        filterId = ++mLastUsedFilterId;
+    }
+
+    mUsedFilterIds.insert(filterId);
+
+    if (cb == nullptr) {
+        ALOGW("callback can't be null");
+        _hidl_cb(Result::INVALID_ARGUMENT, new Filter());
+        return Void();
+    }
+
+    sp<Filter> filter = new Filter(type, filterId, bufferSize, cb, this);
+
+    if (!filter->createFilterMQ()) {
+        _hidl_cb(Result::UNKNOWN_ERROR, filter);
+        return Void();
+    }
+
+    mFilters[filterId] = filter;
+
+    _hidl_cb(Result::SUCCESS, filter);
+    return Void();
+}
+
+Return<void> Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    sp<TimeFilter> timeFilter = new TimeFilter(this);
+
+    _hidl_cb(Result::SUCCESS, timeFilter);
+    return Void();
+}
+
+Return<void> Demux::getAvSyncHwId(const sp<IFilter>& /* filter */, getAvSyncHwId_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    AvSyncHwId avSyncHwId = 0;
+
+    _hidl_cb(Result::SUCCESS, avSyncHwId);
+    return Void();
+}
+
+Return<void> Demux::getAvSyncTime(AvSyncHwId /* avSyncHwId */, getAvSyncTime_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t avSyncTime = 0;
+
+    _hidl_cb(Result::SUCCESS, avSyncTime);
+    return Void();
+}
+
+Return<Result> Demux::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    mUnusedFilterIds.clear();
+    mUsedFilterIds.clear();
+    mLastUsedFilterId = -1;
+
+    return Result::SUCCESS;
+}
+
+Return<void> Demux::openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
+                            openDvr_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (cb == nullptr) {
+        ALOGW("DVR callback can't be null");
+        _hidl_cb(Result::INVALID_ARGUMENT, new Dvr());
+        return Void();
+    }
+
+    sp<Dvr> dvr = new Dvr(type, bufferSize, cb, this);
+
+    if (!dvr->createDvrMQ()) {
+        _hidl_cb(Result::UNKNOWN_ERROR, dvr);
+        return Void();
+    }
+
+    _hidl_cb(Result::SUCCESS, dvr);
+    return Void();
+}
+
+Return<Result> Demux::connectCiCam(uint32_t ciCamId) {
+    ALOGV("%s", __FUNCTION__);
+
+    mCiCamId = ciCamId;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Demux::disconnectCiCam() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Result Demux::removeFilter(uint32_t filterId) {
+    ALOGV("%s", __FUNCTION__);
+
+    // resetFilterRecords(filterId);
+    mUsedFilterIds.erase(filterId);
+    mUnusedFilterIds.insert(filterId);
+    mFilters.erase(filterId);
+
+    return Result::SUCCESS;
+}
+
+void Demux::startTsFilter(vector<uint8_t> data) {
+    set<uint32_t>::iterator it;
+    for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
+        uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
+        if (DEBUG_FILTER) {
+            ALOGW("start ts filter pid: %d", pid);
+        }
+        if (pid == mFilters[*it]->getTpid()) {
+            mFilters[*it]->updateFilterOutput(data);
+        }
+    }
+}
+
+bool Demux::startFilterDispatcher() {
+    set<uint32_t>::iterator it;
+
+    // Handle the output data per filter type
+    for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
+        if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+Result Demux::startFilterHandler(uint32_t filterId) {
+    return mFilters[filterId]->startFilterHandler();
+}
+
+void Demux::updateFilterOutput(uint16_t filterId, vector<uint8_t> data) {
+    mFilters[filterId]->updateFilterOutput(data);
+}
+
+uint16_t Demux::getFilterTpid(uint32_t filterId) {
+    return mFilters[filterId]->getTpid();
+}
+
+Result Demux::startBroadcastInputLoop() {
+    pthread_create(&mBroadcastInputThread, NULL, __threadLoopBroadcast, this);
+    pthread_setname_np(mBroadcastInputThread, "broadcast_input_thread");
+
+    return Result::SUCCESS;
+}
+
+void* Demux::__threadLoopBroadcast(void* user) {
+    Demux* const self = static_cast<Demux*>(user);
+    self->broadcastInputThreadLoop();
+    return 0;
+}
+
+void Demux::broadcastInputThreadLoop() {
+    std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
+    mBroadcastInputThreadRunning = true;
+    mKeepFetchingDataFromFrontend = true;
+
+    // open the stream and get its length
+    std::ifstream inputData(mFrontendSourceFile, std::ifstream::binary);
+    // TODO take the packet size from the frontend setting
+    int packetSize = 188;
+    int writePacketAmount = 6;
+    char* buffer = new char[packetSize];
+    ALOGW("[Demux] broadcast input thread loop start %s", mFrontendSourceFile.c_str());
+    if (!inputData.is_open()) {
+        mBroadcastInputThreadRunning = false;
+        ALOGW("[Demux] Error %s", strerror(errno));
+    }
+
+    while (mBroadcastInputThreadRunning) {
+        // move the stream pointer for packet size * 6 every read until the end
+        while (mKeepFetchingDataFromFrontend) {
+            for (int i = 0; i < writePacketAmount; i++) {
+                inputData.read(buffer, packetSize);
+                if (!inputData) {
+                    mKeepFetchingDataFromFrontend = false;
+                    mBroadcastInputThreadRunning = false;
+                    break;
+                }
+                // filter and dispatch filter output
+                vector<uint8_t> byteBuffer;
+                byteBuffer.resize(packetSize);
+                for (int index = 0; index < byteBuffer.size(); index++) {
+                    byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
+                }
+                startTsFilter(byteBuffer);
+            }
+            startFilterDispatcher();
+            usleep(100);
+        }
+    }
+
+    ALOGW("[Demux] Broadcast Input thread end.");
+    delete[] buffer;
+    inputData.close();
+}
+
+void Demux::stopBroadcastInput() {
+    ALOGD("[Demux] stop frontend on demux");
+    mKeepFetchingDataFromFrontend = false;
+    mBroadcastInputThreadRunning = false;
+    std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
new file mode 100644
index 0000000..037429d
--- /dev/null
+++ b/tv/tuner/1.0/default/Demux.h
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_
+
+#include <android/hardware/tv/tuner/1.0/IDemux.h>
+#include <fmq/MessageQueue.h>
+#include <math.h>
+#include <set>
+#include "Dvr.h"
+#include "Filter.h"
+#include "Frontend.h"
+#include "TimeFilter.h"
+#include "Tuner.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
+using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Dvr;
+class Filter;
+class Frontend;
+class TimeFilter;
+class Tuner;
+
+class Demux : public IDemux {
+  public:
+    Demux(uint32_t demuxId, sp<Tuner> tuner);
+
+    ~Demux();
+
+    virtual Return<Result> setFrontendDataSource(uint32_t frontendId) override;
+
+    virtual Return<void> openFilter(const DemuxFilterType& type, uint32_t bufferSize,
+                                    const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) override;
+
+    virtual Return<void> openTimeFilter(openTimeFilter_cb _hidl_cb) override;
+
+    virtual Return<void> getAvSyncHwId(const sp<IFilter>& filter,
+                                       getAvSyncHwId_cb _hidl_cb) override;
+
+    virtual Return<void> getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) override;
+
+    virtual Return<Result> close() override;
+
+    virtual Return<void> openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
+                                 openDvr_cb _hidl_cb) override;
+
+    virtual Return<Result> connectCiCam(uint32_t ciCamId) override;
+
+    virtual Return<Result> disconnectCiCam() override;
+
+    // Functions interacts with Tuner Service
+    void stopBroadcastInput();
+    Result removeFilter(uint32_t filterId);
+    Result startFilterHandler(uint32_t filterId);
+    void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
+    uint16_t getFilterTpid(uint32_t filterId);
+
+  private:
+    // Tuner service
+    sp<Tuner> mTunerService;
+
+    // Frontend source
+    sp<Frontend> mFrontend;
+    string mFrontendSourceFile;
+
+    // A struct that passes the arguments to a newly created filter thread
+    struct ThreadArgs {
+        Demux* user;
+        uint32_t filterId;
+    };
+
+    Result startBroadcastInputLoop();
+    static void* __threadLoopBroadcast(void* user);
+    void broadcastInputThreadLoop();
+
+    /**
+     * To create a FilterMQ with the the next available Filter ID.
+     * Creating Event Flag at the same time.
+     * Add the successfully created/saved FilterMQ into the local list.
+     *
+     * Return false is any of the above processes fails.
+     */
+    void deleteEventFlag();
+    bool readDataFromMQ();
+    /**
+     * A dispatcher to read and dispatch input data to all the started filters.
+     * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     */
+    bool startFilterDispatcher();
+    void startTsFilter(vector<uint8_t> data);
+
+    uint32_t mDemuxId;
+    uint32_t mCiCamId;
+    /**
+     * Record the last used filter id. Initial value is -1.
+     * Filter Id starts with 0.
+     */
+    uint32_t mLastUsedFilterId = -1;
+    /**
+     * Record all the used filter Ids.
+     * Any removed filter id should be removed from this set.
+     */
+    set<uint32_t> mUsedFilterIds;
+    /**
+     * Record all the unused filter Ids within mLastUsedFilterId.
+     * Removed filter Id should be added into this set.
+     * When this set is not empty, ids here should be allocated first
+     * and added into usedFilterIds.
+     */
+    set<uint32_t> mUnusedFilterIds;
+    /**
+     * A list of created FilterMQ ptrs.
+     * The array number is the filter ID.
+     */
+    std::map<uint32_t, sp<Filter>> mFilters;
+
+    // Thread handlers
+    pthread_t mBroadcastInputThread;
+    /**
+     * If a specific filter's writing loop is still running
+     */
+    bool mBroadcastInputThreadRunning;
+    bool mKeepFetchingDataFromFrontend;
+    /**
+     * Lock to protect writes to the FMQs
+     */
+    std::mutex mWriteLock;
+    /**
+     * Lock to protect writes to the input status
+     */
+    std::mutex mBroadcastInputThreadLock;
+
+    // temp handle single PES filter
+    // TODO handle mulptiple Pes filters
+    int mPesSizeLeft = 0;
+    vector<uint8_t> mPesOutput;
+
+    const bool DEBUG_FILTER = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_
diff --git a/tv/tuner/1.0/default/Descrambler.cpp b/tv/tuner/1.0/default/Descrambler.cpp
new file mode 100644
index 0000000..e3f5b22
--- /dev/null
+++ b/tv/tuner/1.0/default/Descrambler.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "android.hardware.tv.tuner@1.0-Descrambler"
+
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <utils/Log.h>
+
+#include "Descrambler.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Descrambler::Descrambler() {}
+
+Descrambler::~Descrambler() {}
+
+Return<Result> Descrambler::setDemuxSource(uint32_t demuxId) {
+    ALOGV("%s", __FUNCTION__);
+    if (mDemuxSet) {
+        ALOGW("[   WARN   ] Descrambler has already been set with a demux id %d", mSourceDemuxId);
+        return Result::INVALID_STATE;
+    }
+    mDemuxSet = true;
+    mSourceDemuxId = demuxId;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::setKeyToken(const hidl_vec<uint8_t>& /* keyToken */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::addPid(const DemuxPid& /* pid */,
+                                   const sp<IFilter>& /* optionalSourceFilter */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::removePid(const DemuxPid& /* pid */,
+                                      const sp<IFilter>& /* optionalSourceFilter */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::close() {
+    ALOGV("%s", __FUNCTION__);
+    mDemuxSet = false;
+
+    return Result::SUCCESS;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.0/default/Descrambler.h b/tv/tuner/1.0/default/Descrambler.h
new file mode 100644
index 0000000..c889820
--- /dev/null
+++ b/tv/tuner/1.0/default/Descrambler.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_DESCRAMBLER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_DESCRAMBLER_H_
+
+#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_0::IDescrambler;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+class Descrambler : public IDescrambler {
+  public:
+    Descrambler();
+
+    virtual Return<Result> setDemuxSource(uint32_t demuxId) override;
+
+    virtual Return<Result> setKeyToken(const hidl_vec<uint8_t>& keyToken) override;
+
+    virtual Return<Result> addPid(const DemuxPid& pid,
+                                  const sp<IFilter>& optionalSourceFilter) override;
+
+    virtual Return<Result> removePid(const DemuxPid& pid,
+                                     const sp<IFilter>& optionalSourceFilter) override;
+
+    virtual Return<Result> close() override;
+
+  private:
+    virtual ~Descrambler();
+    uint32_t mSourceDemuxId;
+    bool mDemuxSet = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_DESCRAMBLER_H_
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
new file mode 100644
index 0000000..eb38f90
--- /dev/null
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -0,0 +1,280 @@
+/*
+ * 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 "android.hardware.tv.tuner@1.0-Dvr"
+
+#include "Dvr.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+
+Dvr::Dvr() {}
+
+Dvr::Dvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb, sp<Demux> demux) {
+    mType = type;
+    mBufferSize = bufferSize;
+    mCallback = cb;
+    mDemux = demux;
+}
+
+Dvr::~Dvr() {}
+
+Return<void> Dvr::getQueueDesc(getQueueDesc_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    _hidl_cb(Result::SUCCESS, *mDvrMQ->getDesc());
+    return Void();
+}
+
+Return<Result> Dvr::configure(const DvrSettings& settings) {
+    ALOGV("%s", __FUNCTION__);
+
+    mDvrSettings = settings;
+    mDvrConfigured = true;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::attachFilter(const sp<IFilter>& filter) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint32_t filterId;
+    Result status;
+
+    filter->getId([&](Result result, uint32_t id) {
+        filterId = id;
+        status = result;
+    });
+
+    if (status != Result::SUCCESS) {
+        return status;
+    }
+
+    mFilters[filterId] = filter;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::detachFilter(const sp<IFilter>& filter) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint32_t filterId;
+    Result status;
+
+    filter->getId([&](Result result, uint32_t id) {
+        filterId = id;
+        status = result;
+    });
+
+    if (status != Result::SUCCESS) {
+        return status;
+    }
+
+    std::map<uint32_t, sp<IFilter>>::iterator it;
+
+    it = mFilters.find(filterId);
+    if (it != mFilters.end()) {
+        mFilters.erase(filterId);
+    }
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::start() {
+    ALOGV("%s", __FUNCTION__);
+
+    if (!mCallback) {
+        return Result::NOT_INITIALIZED;
+    }
+
+    if (!mDvrConfigured) {
+        return Result::INVALID_STATE;
+    }
+
+    if (mType == DvrType::PLAYBACK) {
+        pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
+        pthread_setname_np(mDvrThread, "playback_waiting_loop");
+    } else if (mType == DvrType::RECORD) {
+        /*pthread_create(&mInputThread, NULL, __threadLoopInput, this);
+        pthread_setname_np(mInputThread, "playback_waiting_loop");*/
+    }
+
+    // TODO start another thread to send filter status callback to the framework
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::stop() {
+    ALOGV("%s", __FUNCTION__);
+
+    mDvrThreadRunning = false;
+
+    std::lock_guard<std::mutex> lock(mDvrThreadLock);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::flush() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+bool Dvr::createDvrMQ() {
+    ALOGV("%s", __FUNCTION__);
+
+    // Create a synchronized FMQ that supports blocking read/write
+    std::unique_ptr<DvrMQ> tmpDvrMQ =
+            std::unique_ptr<DvrMQ>(new (std::nothrow) DvrMQ(mBufferSize, true));
+    if (!tmpDvrMQ->isValid()) {
+        ALOGW("Failed to create FMQ of DVR");
+        return false;
+    }
+
+    mDvrMQ = std::move(tmpDvrMQ);
+
+    if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
+        return false;
+    }
+
+    return true;
+}
+
+void* Dvr::__threadLoopPlayback(void* user) {
+    Dvr* const self = static_cast<Dvr*>(user);
+    self->playbackThreadLoop();
+    return 0;
+}
+
+void Dvr::playbackThreadLoop() {
+    ALOGD("[Dvr] playback threadLoop start.");
+    std::lock_guard<std::mutex> lock(mDvrThreadLock);
+    mDvrThreadRunning = true;
+
+    while (mDvrThreadRunning) {
+        uint32_t efState = 0;
+        status_t status =
+                mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
+                                    &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
+        if (status != OK) {
+            ALOGD("[Dvr] wait for data ready on the playback FMQ");
+            continue;
+        }
+        // Our current implementation filter the data and write it into the filter FMQ immediately
+        // after the DATA_READY from the VTS/framework
+        if (!readPlaybackFMQ() || !startFilterDispatcher()) {
+            ALOGD("[Dvr] playback data failed to be filtered. Ending thread");
+            break;
+        }
+
+        maySendPlaybackStatusCallback();
+    }
+
+    mDvrThreadRunning = false;
+    ALOGD("[Dvr] playback thread ended.");
+}
+
+void Dvr::maySendPlaybackStatusCallback() {
+    std::lock_guard<std::mutex> lock(mPlaybackStatusLock);
+    int availableToRead = mDvrMQ->availableToRead();
+    int availableToWrite = mDvrMQ->availableToWrite();
+
+    PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
+                                                         mDvrSettings.playback().highThreshold,
+                                                         mDvrSettings.playback().lowThreshold);
+    if (mPlaybackStatus != newStatus) {
+        mCallback->onPlaybackStatus(newStatus);
+        mPlaybackStatus = newStatus;
+    }
+}
+
+PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                              uint32_t highThreshold, uint32_t lowThreshold) {
+    if (availableToWrite == 0) {
+        return PlaybackStatus::SPACE_FULL;
+    } else if (availableToRead > highThreshold) {
+        return PlaybackStatus::SPACE_ALMOST_FULL;
+    } else if (availableToRead < lowThreshold) {
+        return PlaybackStatus::SPACE_ALMOST_EMPTY;
+    } else if (availableToRead == 0) {
+        return PlaybackStatus::SPACE_EMPTY;
+    }
+    return mPlaybackStatus;
+}
+
+bool Dvr::readPlaybackFMQ() {
+    // Read playback data from the input FMQ
+    int size = mDvrMQ->availableToRead();
+    int playbackPacketSize = mDvrSettings.playback().packetSize;
+    vector<uint8_t> dataOutputBuffer;
+    dataOutputBuffer.resize(playbackPacketSize);
+
+    // Dispatch the packet to the PID matching filter output buffer
+    for (int i = 0; i < size / playbackPacketSize; i++) {
+        if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
+            return false;
+        }
+        startTpidFilter(dataOutputBuffer);
+    }
+
+    return true;
+}
+
+void Dvr::startTpidFilter(vector<uint8_t> data) {
+    std::map<uint32_t, sp<IFilter>>::iterator it;
+    for (it = mFilters.begin(); it != mFilters.end(); it++) {
+        uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
+        if (DEBUG_DVR) {
+            ALOGW("[Dvr] start ts filter pid: %d", pid);
+        }
+        if (pid == mDemux->getFilterTpid(it->first)) {
+            mDemux->updateFilterOutput(it->first, data);
+        }
+    }
+}
+
+bool Dvr::startFilterDispatcher() {
+    std::map<uint32_t, sp<IFilter>>::iterator it;
+
+    // Handle the output data per filter type
+    for (it = mFilters.begin(); it != mFilters.end(); it++) {
+        if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
new file mode 100644
index 0000000..fbb778c
--- /dev/null
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_
+
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <fmq/MessageQueue.h>
+#include <math.h>
+#include <set>
+#include "Demux.h"
+#include "Frontend.h"
+#include "Tuner.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Demux;
+class Filter;
+class Frontend;
+class Tuner;
+
+class Dvr : public IDvr {
+  public:
+    Dvr();
+
+    Dvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb, sp<Demux> demux);
+
+    ~Dvr();
+
+    virtual Return<void> getQueueDesc(getQueueDesc_cb _hidl_cb) override;
+
+    virtual Return<Result> configure(const DvrSettings& settings) override;
+
+    virtual Return<Result> attachFilter(const sp<IFilter>& filter) override;
+
+    virtual Return<Result> detachFilter(const sp<IFilter>& filter) override;
+
+    virtual Return<Result> start() override;
+
+    virtual Return<Result> stop() override;
+
+    virtual Return<Result> flush() override;
+
+    virtual Return<Result> close() override;
+
+    /**
+     * To create a DvrMQ and its Event Flag.
+     *
+     * Return false is any of the above processes fails.
+     */
+    bool createDvrMQ();
+
+  private:
+    // Demux service
+    sp<Demux> mDemux;
+
+    DvrType mType;
+    uint32_t mBufferSize;
+    sp<IDvrCallback> mCallback;
+    std::map<uint32_t, sp<IFilter>> mFilters;
+
+    void deleteEventFlag();
+    bool readDataFromMQ();
+    void maySendPlaybackStatusCallback();
+    void maySendRecordStatusCallback();
+    PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                             uint32_t highThreshold, uint32_t lowThreshold);
+    /**
+     * A dispatcher to read and dispatch input data to all the started filters.
+     * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     */
+    bool readPlaybackFMQ();
+    void startTpidFilter(vector<uint8_t> data);
+    bool startFilterDispatcher();
+    static void* __threadLoopPlayback(void* user);
+    static void* __threadLoopBroadcast(void* user);
+    void playbackThreadLoop();
+    void broadcastInputThreadLoop();
+
+    unique_ptr<DvrMQ> mDvrMQ;
+    EventFlag* mDvrEventFlag;
+    /**
+     * Demux callbacks used on filter events or IO buffer status
+     */
+    bool mDvrConfigured = false;
+    DvrSettings mDvrSettings;
+
+    // Thread handlers
+    pthread_t mDvrThread;
+    pthread_t mBroadcastInputThread;
+
+    // FMQ status local records
+    PlaybackStatus mPlaybackStatus;
+    /**
+     * If a specific filter's writing loop is still running
+     */
+    bool mDvrThreadRunning;
+    bool mBroadcastInputThreadRunning;
+    bool mKeepFetchingDataFromFrontend;
+    /**
+     * Lock to protect writes to the FMQs
+     */
+    std::mutex mWriteLock;
+    /**
+     * Lock to protect writes to the input status
+     */
+    std::mutex mPlaybackStatusLock;
+    std::mutex mBroadcastInputThreadLock;
+    std::mutex mDvrThreadLock;
+
+    const bool DEBUG_DVR = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
new file mode 100644
index 0000000..befd1e6
--- /dev/null
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -0,0 +1,470 @@
+/*
+ * 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 "android.hardware.tv.tuner@1.0-Filter"
+
+#include "Filter.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+
+Filter::Filter() {}
+
+Filter::Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize,
+               const sp<IFilterCallback>& cb, sp<Demux> demux) {
+    mType = type;
+    mFilterId = filterId;
+    mBufferSize = bufferSize;
+    mCallback = cb;
+    mDemux = demux;
+}
+
+Filter::~Filter() {}
+
+Return<void> Filter::getId(getId_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    _hidl_cb(Result::SUCCESS, mFilterId);
+    return Void();
+}
+
+Return<Result> Filter::setDataSource(const sp<IFilter>& filter) {
+    ALOGV("%s", __FUNCTION__);
+
+    mDataSource = filter;
+    mIsDataSourceDemux = false;
+
+    return Result::SUCCESS;
+}
+
+Return<void> Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    _hidl_cb(Result::SUCCESS, *mFilterMQ->getDesc());
+    return Void();
+}
+
+Return<Result> Filter::configure(const DemuxFilterSettings& settings) {
+    ALOGV("%s", __FUNCTION__);
+
+    mFilterSettings = settings;
+    switch (mType.mainType) {
+        case DemuxFilterMainType::TS:
+            mTpid = settings.ts().tpid;
+            break;
+        case DemuxFilterMainType::MMTP:
+            /*mmtpSettings*/
+            break;
+        case DemuxFilterMainType::IP:
+            /*ipSettings*/
+            break;
+        case DemuxFilterMainType::TLV:
+            /*tlvSettings*/
+            break;
+        case DemuxFilterMainType::ALP:
+            /*alpSettings*/
+            break;
+        default:
+            break;
+    }
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::start() {
+    ALOGV("%s", __FUNCTION__);
+
+    return startFilterLoop();
+}
+
+Return<Result> Filter::stop() {
+    ALOGV("%s", __FUNCTION__);
+
+    mFilterThreadRunning = false;
+
+    std::lock_guard<std::mutex> lock(mFilterThreadLock);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::flush() {
+    ALOGV("%s", __FUNCTION__);
+
+    // temp implementation to flush the FMQ
+    int size = mFilterMQ->availableToRead();
+    char* buffer = new char[size];
+    mFilterMQ->read((unsigned char*)&buffer[0], size);
+    delete[] buffer;
+    mFilterStatus = DemuxFilterStatus::DATA_READY;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    return mDemux->removeFilter(mFilterId);
+}
+
+bool Filter::createFilterMQ() {
+    ALOGV("%s", __FUNCTION__);
+
+    // Create a synchronized FMQ that supports blocking read/write
+    std::unique_ptr<FilterMQ> tmpFilterMQ =
+            std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(mBufferSize, true));
+    if (!tmpFilterMQ->isValid()) {
+        ALOGW("Failed to create FMQ of filter with id: %d", mFilterId);
+        return false;
+    }
+
+    mFilterMQ = std::move(tmpFilterMQ);
+
+    if (EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterEventFlag) != OK) {
+        return false;
+    }
+
+    return true;
+}
+
+Result Filter::startFilterLoop() {
+    pthread_create(&mFilterThread, NULL, __threadLoopFilter, this);
+    pthread_setname_np(mFilterThread, "filter_waiting_loop");
+
+    return Result::SUCCESS;
+}
+
+void* Filter::__threadLoopFilter(void* user) {
+    Filter* const self = static_cast<Filter*>(user);
+    self->filterThreadLoop();
+    return 0;
+}
+
+void Filter::filterThreadLoop() {
+    ALOGD("[Filter] filter %d threadLoop start.", mFilterId);
+    std::lock_guard<std::mutex> lock(mFilterThreadLock);
+    mFilterThreadRunning = true;
+
+    // For the first time of filter output, implementation needs to send the filter
+    // Event Callback without waiting for the DATA_CONSUMED to init the process.
+    while (mFilterThreadRunning) {
+        if (mFilterEvent.events.size() == 0) {
+            ALOGD("[Filter] wait for filter data output.");
+            usleep(1000 * 1000);
+            continue;
+        }
+        // After successfully write, send a callback and wait for the read to be done
+        mCallback->onFilterEvent(mFilterEvent);
+        mFilterEvent.events.resize(0);
+        mFilterStatus = DemuxFilterStatus::DATA_READY;
+        mCallback->onFilterStatus(mFilterStatus);
+        break;
+    }
+
+    while (mFilterThreadRunning) {
+        uint32_t efState = 0;
+        // We do not wait for the last round of written data to be read to finish the thread
+        // because the VTS can verify the reading itself.
+        for (int i = 0; i < SECTION_WRITE_COUNT; i++) {
+            while (mFilterThreadRunning) {
+                status_t status = mFilterEventFlag->wait(
+                        static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
+                        WAIT_TIMEOUT, true /* retry on spurious wake */);
+                if (status != OK) {
+                    ALOGD("[Filter] wait for data consumed");
+                    continue;
+                }
+                break;
+            }
+
+            if (mCallback == nullptr) {
+                ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId);
+                break;
+            }
+
+            maySendFilterStatusCallback();
+
+            while (mFilterThreadRunning) {
+                std::lock_guard<std::mutex> lock(mFilterEventLock);
+                if (mFilterEvent.events.size() == 0) {
+                    continue;
+                }
+                // After successfully write, send a callback and wait for the read to be done
+                mCallback->onFilterEvent(mFilterEvent);
+                mFilterEvent.events.resize(0);
+                break;
+            }
+            // We do not wait for the last read to be done
+            // VTS can verify the read result itself.
+            if (i == SECTION_WRITE_COUNT - 1) {
+                ALOGD("[Filter] filter %d writing done. Ending thread", mFilterId);
+                break;
+            }
+        }
+        mFilterThreadRunning = false;
+    }
+
+    ALOGD("[Filter] filter thread ended.");
+}
+
+void Filter::maySendFilterStatusCallback() {
+    std::lock_guard<std::mutex> lock(mFilterStatusLock);
+    int availableToRead = mFilterMQ->availableToRead();
+    int availableToWrite = mFilterMQ->availableToWrite();
+    int fmqSize = mFilterMQ->getQuantumCount();
+
+    DemuxFilterStatus newStatus = checkFilterStatusChange(
+            availableToWrite, availableToRead, ceil(fmqSize * 0.75), ceil(fmqSize * 0.25));
+    if (mFilterStatus != newStatus) {
+        mCallback->onFilterStatus(newStatus);
+        mFilterStatus = newStatus;
+    }
+}
+
+DemuxFilterStatus Filter::checkFilterStatusChange(uint32_t availableToWrite,
+                                                  uint32_t availableToRead, uint32_t highThreshold,
+                                                  uint32_t lowThreshold) {
+    if (availableToWrite == 0) {
+        return DemuxFilterStatus::OVERFLOW;
+    } else if (availableToRead > highThreshold) {
+        return DemuxFilterStatus::HIGH_WATER;
+    } else if (availableToRead < lowThreshold) {
+        return DemuxFilterStatus::LOW_WATER;
+    }
+    return mFilterStatus;
+}
+
+uint16_t Filter::getTpid() {
+    return mTpid;
+}
+
+void Filter::updateFilterOutput(vector<uint8_t> data) {
+    std::lock_guard<std::mutex> lock(mFilterOutputLock);
+    ALOGD("[Filter] handler output updated");
+    mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
+}
+
+Result Filter::startFilterHandler() {
+    std::lock_guard<std::mutex> lock(mFilterOutputLock);
+    switch (mType.mainType) {
+        case DemuxFilterMainType::TS:
+            switch (mType.subType.tsFilterType()) {
+                case DemuxTsFilterType::UNDEFINED:
+                    break;
+                case DemuxTsFilterType::SECTION:
+                    startSectionFilterHandler();
+                    break;
+                case DemuxTsFilterType::PES:
+                    startPesFilterHandler();
+                    break;
+                case DemuxTsFilterType::TS:
+                    startTsFilterHandler();
+                    break;
+                case DemuxTsFilterType::AUDIO:
+                case DemuxTsFilterType::VIDEO:
+                    startMediaFilterHandler();
+                    break;
+                case DemuxTsFilterType::PCR:
+                    startPcrFilterHandler();
+                    break;
+                case DemuxTsFilterType::RECORD:
+                    startRecordFilterHandler();
+                    break;
+                case DemuxTsFilterType::TEMI:
+                    startTemiFilterHandler();
+                    break;
+            }
+            break;
+        case DemuxFilterMainType::MMTP:
+            /*mmtpSettings*/
+            break;
+        case DemuxFilterMainType::IP:
+            /*ipSettings*/
+            break;
+        case DemuxFilterMainType::TLV:
+            /*tlvSettings*/
+            break;
+        case DemuxFilterMainType::ALP:
+            /*alpSettings*/
+            break;
+        default:
+            break;
+    }
+    return Result::SUCCESS;
+}
+
+Result Filter::startSectionFilterHandler() {
+    if (mFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
+    if (!writeSectionsAndCreateEvent(mFilterOutput)) {
+        ALOGD("[Filter] filter %d fails to write into FMQ. Ending thread", mFilterId);
+        return Result::UNKNOWN_ERROR;
+    }
+
+    mFilterOutput.clear();
+
+    return Result::SUCCESS;
+}
+
+Result Filter::startPesFilterHandler() {
+    std::lock_guard<std::mutex> lock(mFilterEventLock);
+    if (mFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
+
+    for (int i = 0; i < mFilterOutput.size(); i += 188) {
+        if (mPesSizeLeft == 0) {
+            uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
+                              mFilterOutput[i + 6];
+            ALOGD("[Filter] prefix %d", prefix);
+            if (prefix == 0x000001) {
+                // TODO handle mulptiple Pes filters
+                mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
+                mPesSizeLeft += 6;
+                ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+            } else {
+                continue;
+            }
+        }
+
+        int endPoint = min(184, mPesSizeLeft);
+        // append data and check size
+        vector<uint8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
+        vector<uint8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
+        mPesOutput.insert(mPesOutput.end(), first, last);
+        // size does not match then continue
+        mPesSizeLeft -= endPoint;
+        ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+        if (mPesSizeLeft > 0) {
+            continue;
+        }
+        // size match then create event
+        if (!writeDataToFilterMQ(mPesOutput)) {
+            ALOGD("[Filter] pes data write failed");
+            mFilterOutput.clear();
+            return Result::INVALID_STATE;
+        }
+        maySendFilterStatusCallback();
+        DemuxFilterPesEvent pesEvent;
+        pesEvent = {
+                // temp dump meta data
+                .streamId = mPesOutput[3],
+                .dataLength = static_cast<uint16_t>(mPesOutput.size()),
+        };
+        ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+
+        int size = mFilterEvent.events.size();
+        mFilterEvent.events.resize(size + 1);
+        mFilterEvent.events[size].pes(pesEvent);
+        mPesOutput.clear();
+    }
+
+    mFilterOutput.clear();
+
+    return Result::SUCCESS;
+}
+
+Result Filter::startTsFilterHandler() {
+    // TODO handle starting TS filter
+    return Result::SUCCESS;
+}
+
+Result Filter::startMediaFilterHandler() {
+    DemuxFilterMediaEvent mediaEvent;
+    mediaEvent = {
+            // temp dump meta data
+            .pts = 0,
+            .dataLength = 530,
+            .avMemory = nullptr,
+            .isSecureMemory = false,
+    };
+    mFilterEvent.events.resize(1);
+    mFilterEvent.events[0].media(mediaEvent);
+
+    mFilterOutput.clear();
+    // TODO handle write FQM for media stream
+    return Result::SUCCESS;
+}
+
+Result Filter::startRecordFilterHandler() {
+    DemuxFilterTsRecordEvent tsRecordEvent;
+    tsRecordEvent.pid.tPid(0);
+    tsRecordEvent.indexMask.tsIndexMask(0x01);
+    mFilterEvent.events.resize(1);
+    mFilterEvent.events[0].tsRecord(tsRecordEvent);
+
+    mFilterOutput.clear();
+    return Result::SUCCESS;
+}
+
+Result Filter::startPcrFilterHandler() {
+    // TODO handle starting PCR filter
+    return Result::SUCCESS;
+}
+
+Result Filter::startTemiFilterHandler() {
+    // TODO handle starting TEMI filter
+    return Result::SUCCESS;
+}
+
+bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) {
+    // TODO check how many sections has been read
+    ALOGD("[Filter] section hander");
+    std::lock_guard<std::mutex> lock(mFilterEventLock);
+    if (!writeDataToFilterMQ(data)) {
+        return false;
+    }
+    int size = mFilterEvent.events.size();
+    mFilterEvent.events.resize(size + 1);
+    DemuxFilterSectionEvent secEvent;
+    secEvent = {
+            // temp dump meta data
+            .tableId = 0,
+            .version = 1,
+            .sectionNum = 1,
+            .dataLength = static_cast<uint16_t>(data.size()),
+    };
+    mFilterEvent.events[size].section(secEvent);
+    return true;
+}
+
+bool Filter::writeDataToFilterMQ(const std::vector<uint8_t>& data) {
+    std::lock_guard<std::mutex> lock(mWriteLock);
+    if (mFilterMQ->write(data.data(), data.size())) {
+        return true;
+    }
+    return false;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
new file mode 100644
index 0000000..fbd965a
--- /dev/null
+++ b/tv/tuner/1.0/default/Filter.h
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_
+
+#include <android/hardware/tv/tuner/1.0/IFilter.h>
+#include <fmq/MessageQueue.h>
+#include <math.h>
+#include <set>
+#include "Demux.h"
+#include "Frontend.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Demux;
+
+class Filter : public IFilter {
+  public:
+    Filter();
+
+    Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize,
+           const sp<IFilterCallback>& cb, sp<Demux> demux);
+
+    ~Filter();
+
+    virtual Return<void> getId(getId_cb _hidl_cb) override;
+
+    virtual Return<Result> setDataSource(const sp<IFilter>& filter) override;
+
+    virtual Return<void> getQueueDesc(getQueueDesc_cb _hidl_cb) override;
+
+    virtual Return<Result> configure(const DemuxFilterSettings& settings) override;
+
+    virtual Return<Result> start() override;
+
+    virtual Return<Result> stop() override;
+
+    virtual Return<Result> flush() override;
+
+    virtual Return<Result> releaseAvHandle(const hidl_handle& avMemory) override;
+
+    virtual Return<Result> close() override;
+
+    /**
+     * To create a FilterMQ and its Event Flag.
+     *
+     * Return false is any of the above processes fails.
+     */
+    bool createFilterMQ();
+    uint16_t getTpid();
+    void updateFilterOutput(vector<uint8_t> data);
+    Result startFilterHandler();
+
+  private:
+    // Tuner service
+    sp<Demux> mDemux;
+    /**
+     * Filter callbacks used on filter events or FMQ status
+     */
+    sp<IFilterCallback> mCallback;
+
+    uint32_t mFilterId;
+    uint32_t mBufferSize;
+    DemuxFilterType mType;
+    DemuxFilterSettings mFilterSettings;
+
+    uint16_t mTpid;
+    sp<IFilter> mDataSource;
+    bool mIsDataSourceDemux = true;
+    vector<uint8_t> mFilterOutput;
+    unique_ptr<FilterMQ> mFilterMQ;
+    EventFlag* mFilterEventFlag;
+    DemuxFilterEvent mFilterEvent;
+
+    // Thread handlers
+    pthread_t mFilterThread;
+
+    // FMQ status local records
+    DemuxFilterStatus mFilterStatus;
+    /**
+     * If a specific filter's writing loop is still running
+     */
+    bool mFilterThreadRunning;
+    bool mKeepFetchingDataFromFrontend;
+
+    /**
+     * How many times a filter should write
+     * TODO make this dynamic/random/can take as a parameter
+     */
+    const uint16_t SECTION_WRITE_COUNT = 10;
+
+    /**
+     * Filter handlers to handle the data filtering.
+     * They are also responsible to write the filtered output into the filter FMQ
+     * and update the filterEvent bound with the same filterId.
+     */
+    Result startSectionFilterHandler();
+    Result startPesFilterHandler();
+    Result startTsFilterHandler();
+    Result startMediaFilterHandler();
+    Result startRecordFilterHandler();
+    Result startPcrFilterHandler();
+    Result startTemiFilterHandler();
+    Result startFilterLoop();
+
+    void deleteEventFlag();
+    bool writeDataToFilterMQ(const std::vector<uint8_t>& data);
+    bool readDataFromMQ();
+    bool writeSectionsAndCreateEvent(vector<uint8_t> data);
+    void maySendFilterStatusCallback();
+    DemuxFilterStatus checkFilterStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                              uint32_t highThreshold, uint32_t lowThreshold);
+    /**
+     * A dispatcher to read and dispatch input data to all the started filters.
+     * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     */
+    void startTsFilter(vector<uint8_t> data);
+    bool startFilterDispatcher();
+    static void* __threadLoopFilter(void* user);
+    void filterThreadLoop();
+
+    /**
+     * Lock to protect writes to the FMQs
+     */
+    std::mutex mWriteLock;
+    /**
+     * Lock to protect writes to the filter event
+     */
+    // TODO make each filter separate event lock
+    std::mutex mFilterEventLock;
+    /**
+     * Lock to protect writes to the input status
+     */
+    std::mutex mFilterStatusLock;
+    std::mutex mFilterThreadLock;
+    std::mutex mFilterOutputLock;
+
+    // temp handle single PES filter
+    // TODO handle mulptiple Pes filters
+    int mPesSizeLeft = 0;
+    vector<uint8_t> mPesOutput;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
new file mode 100644
index 0000000..1e07edd
--- /dev/null
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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 "android.hardware.tv.tuner@1.0-Frontend"
+
+#include "Frontend.h"
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Frontend::Frontend(FrontendType type, FrontendId id, sp<Tuner> tuner) {
+    mType = type;
+    mId = id;
+    mTunerService = tuner;
+    // Init callback to nullptr
+    mCallback = nullptr;
+}
+
+Frontend::~Frontend() {}
+
+Return<Result> Frontend::close() {
+    ALOGV("%s", __FUNCTION__);
+    // Reset callback
+    mCallback = nullptr;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::setCallback(const sp<IFrontendCallback>& callback) {
+    ALOGV("%s", __FUNCTION__);
+    if (callback == nullptr) {
+        ALOGW("[   WARN   ] Set Frontend callback with nullptr");
+        return Result::INVALID_ARGUMENT;
+    }
+
+    mCallback = callback;
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::tune(const FrontendSettings& /* settings */) {
+    ALOGV("%s", __FUNCTION__);
+    if (mCallback == nullptr) {
+        ALOGW("[   WARN   ] Frontend callback is not set when tune");
+        return Result::INVALID_STATE;
+    }
+
+    // TODO dynamically allocate file to the source file
+    mSourceStreamFile = FRONTEND_STREAM_FILE;
+
+    mCallback->onEvent(FrontendEventType::LOCKED);
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::stopTune() {
+    ALOGV("%s", __FUNCTION__);
+
+    mTunerService->frontendStopTune(mId);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::scan(const FrontendSettings& /* settings */, FrontendScanType /* type */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::stopScan() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& /* statusTypes */,
+                                 getStatus_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<FrontendStatus> statuses;
+    _hidl_cb(Result::SUCCESS, statuses);
+
+    return Void();
+}
+
+Return<Result> Frontend::setLna(bool /* bEnable */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::setLnb(uint32_t /* lnb */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+FrontendType Frontend::getFrontendType() {
+    return mType;
+}
+
+FrontendId Frontend::getFrontendId() {
+    return mId;
+}
+
+string Frontend::getSourceFile() {
+    return mSourceStreamFile;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h
new file mode 100644
index 0000000..eab43a3
--- /dev/null
+++ b/tv/tuner/1.0/default/Frontend.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_
+
+#include <android/hardware/tv/tuner/1.0/IFrontend.h>
+#include <fstream>
+#include <iostream>
+#include "Tuner.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::FrontendType;
+using ::android::hardware::tv::tuner::V1_0::IFrontend;
+using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+class Tuner;
+
+class Frontend : public IFrontend {
+  public:
+    Frontend(FrontendType type, FrontendId id, sp<Tuner> tuner);
+
+    virtual Return<Result> close() override;
+
+    virtual Return<Result> setCallback(const sp<IFrontendCallback>& callback) override;
+
+    virtual Return<Result> tune(const FrontendSettings& settings) override;
+
+    virtual Return<Result> stopTune() override;
+
+    virtual Return<Result> scan(const FrontendSettings& settings, FrontendScanType type) override;
+
+    virtual Return<Result> stopScan() override;
+
+    virtual Return<void> getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
+                                   getStatus_cb _hidl_cb) override;
+
+    virtual Return<Result> setLna(bool bEnable) override;
+
+    virtual Return<Result> setLnb(uint32_t lnb) override;
+
+    FrontendType getFrontendType();
+
+    FrontendId getFrontendId();
+
+    string getSourceFile();
+
+  private:
+    virtual ~Frontend();
+    sp<IFrontendCallback> mCallback;
+    sp<Tuner> mTunerService;
+    FrontendType mType = FrontendType::UNDEFINED;
+    FrontendId mId = 0;
+
+    const string FRONTEND_STREAM_FILE = "/vendor/etc/dumpTs3.ts";
+    string mSourceStreamFile;
+    std::ifstream mFrontendData;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_
diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp
new file mode 100644
index 0000000..51931d6
--- /dev/null
+++ b/tv/tuner/1.0/default/Lnb.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.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.0-Lnb"
+
+#include "Lnb.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Lnb::Lnb() {}
+
+Lnb::~Lnb() {}
+
+Return<Result> Lnb::setCallback(const sp<ILnbCallback>& /* callback */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setVoltage(LnbVoltage /* voltage */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setTone(LnbTone /* tone */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setSatellitePosition(LnbPosition /* position */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::sendDiseqcMessage(const hidl_vec<uint8_t>& /* diseqcMessage */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h
new file mode 100644
index 0000000..f285cb9
--- /dev/null
+++ b/tv/tuner/1.0/default/Lnb.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_
+
+#include <android/hardware/tv/tuner/1.0/ILnb.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_0::ILnbCallback;
+using ::android::hardware::tv::tuner::V1_0::LnbPosition;
+using ::android::hardware::tv::tuner::V1_0::LnbTone;
+using ::android::hardware::tv::tuner::V1_0::LnbVoltage;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+class Lnb : public ILnb {
+  public:
+    Lnb();
+
+    virtual Return<Result> setCallback(const sp<ILnbCallback>& callback) override;
+
+    virtual Return<Result> setVoltage(LnbVoltage voltage) override;
+
+    virtual Return<Result> setTone(LnbTone tone) override;
+
+    virtual Return<Result> setSatellitePosition(LnbPosition position) override;
+
+    virtual Return<Result> sendDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override;
+
+    virtual Return<Result> close() override;
+
+  private:
+    virtual ~Lnb();
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/OWNERS b/tv/tuner/1.0/default/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.0/default/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/1.0/default/TimeFilter.cpp b/tv/tuner/1.0/default/TimeFilter.cpp
new file mode 100644
index 0000000..0b1fd1c
--- /dev/null
+++ b/tv/tuner/1.0/default/TimeFilter.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "android.hardware.tv.tuner@1.0-TimeFilter"
+
+#include "TimeFilter.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+TimeFilter::TimeFilter() {}
+
+TimeFilter::TimeFilter(sp<Demux> demux) {
+    mDemux = demux;
+}
+
+TimeFilter::~TimeFilter() {}
+
+Return<Result> TimeFilter::setTimeStamp(uint64_t /* timeStamp */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> TimeFilter::clearTimeStamp() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<void> TimeFilter::getTimeStamp(getTimeStamp_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t timeStamp = 0;
+
+    _hidl_cb(Result::SUCCESS, timeStamp);
+    return Void();
+}
+
+Return<void> TimeFilter::getSourceTime(getSourceTime_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t time = 0;
+
+    _hidl_cb(Result::SUCCESS, time);
+    return Void();
+}
+
+Return<Result> TimeFilter::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/TimeFilter.h b/tv/tuner/1.0/default/TimeFilter.h
new file mode 100644
index 0000000..7131df8
--- /dev/null
+++ b/tv/tuner/1.0/default/TimeFilter.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_
+
+#include <android/hardware/tv/tuner/1.0/ITimeFilter.h>
+#include "Demux.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Demux;
+
+class TimeFilter : public ITimeFilter {
+  public:
+    TimeFilter();
+
+    TimeFilter(sp<Demux> demux);
+
+    ~TimeFilter();
+
+    virtual Return<Result> setTimeStamp(uint64_t timeStamp) override;
+
+    virtual Return<Result> clearTimeStamp() override;
+
+    virtual Return<void> getTimeStamp(getTimeStamp_cb _hidl_cb) override;
+
+    virtual Return<void> getSourceTime(getSourceTime_cb _hidl_cb) override;
+
+    virtual Return<Result> close() override;
+
+  private:
+    sp<Demux> mDemux;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
new file mode 100644
index 0000000..f86b28d
--- /dev/null
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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 "android.hardware.tv.tuner@1.0-Tuner"
+
+#include "Tuner.h"
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <utils/Log.h>
+#include "Demux.h"
+#include "Descrambler.h"
+#include "Frontend.h"
+#include "Lnb.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_0::DemuxId;
+
+Tuner::Tuner() {
+    // Static Frontends array to maintain local frontends information
+    // Array index matches their FrontendId in the default impl
+    mFrontendSize = 8;
+    mFrontends.resize(mFrontendSize);
+    mFrontends[0] = new Frontend(FrontendType::DVBT, 0, this);
+    mFrontends[1] = new Frontend(FrontendType::ATSC, 1, this);
+    mFrontends[2] = new Frontend(FrontendType::DVBC, 2, this);
+    mFrontends[3] = new Frontend(FrontendType::DVBS, 3, this);
+    mFrontends[4] = new Frontend(FrontendType::DVBT, 4, this);
+    mFrontends[5] = new Frontend(FrontendType::ISDBT, 5, this);
+    mFrontends[6] = new Frontend(FrontendType::ANALOG, 6, this);
+    mFrontends[7] = new Frontend(FrontendType::ATSC, 7, this);
+}
+
+Tuner::~Tuner() {}
+
+Return<void> Tuner::getFrontendIds(getFrontendIds_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<FrontendId> frontendIds;
+    frontendIds.resize(mFrontendSize);
+    for (int i = 0; i < mFrontendSize; i++) {
+        frontendIds[i] = mFrontends[i]->getFrontendId();
+    }
+
+    _hidl_cb(Result::SUCCESS, frontendIds);
+    return Void();
+}
+
+Return<void> Tuner::openFrontendById(uint32_t frontendId, openFrontendById_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (frontendId >= mFrontendSize || frontendId < 0) {
+        ALOGW("[   WARN   ] Frontend with id %d isn't available", frontendId);
+        _hidl_cb(Result::UNAVAILABLE, nullptr);
+        return Void();
+    }
+
+    _hidl_cb(Result::SUCCESS, mFrontends[frontendId]);
+    return Void();
+}
+
+Return<void> Tuner::openDemux(openDemux_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    DemuxId demuxId = mLastUsedId + 1;
+    mLastUsedId += 1;
+    sp<Demux> demux = new Demux(demuxId, this);
+    mDemuxes[demuxId] = demux;
+
+    _hidl_cb(Result::SUCCESS, demuxId, demux);
+    return Void();
+}
+
+Return<void> Tuner::getDemuxCaps(getDemuxCaps_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    DemuxCapabilities caps;
+
+    _hidl_cb(Result::SUCCESS, caps);
+    return Void();
+}
+
+Return<void> Tuner::openDescrambler(openDescrambler_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    sp<IDescrambler> descrambler = new Descrambler();
+
+    _hidl_cb(Result::SUCCESS, descrambler);
+    return Void();
+}
+
+Return<void> Tuner::getFrontendInfo(FrontendId /* frontendId */, getFrontendInfo_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    FrontendInfo info;
+
+    _hidl_cb(Result::SUCCESS, info);
+    return Void();
+}
+
+Return<void> Tuner::getLnbIds(getLnbIds_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<LnbId> lnbIds;
+
+    _hidl_cb(Result::SUCCESS, lnbIds);
+    return Void();
+}
+
+Return<void> Tuner::openLnbById(LnbId /* lnbId */, openLnbById_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    sp<ILnb> lnb = new Lnb();
+
+    _hidl_cb(Result::SUCCESS, lnb);
+    return Void();
+}
+
+sp<Frontend> Tuner::getFrontendById(uint32_t frontendId) {
+    ALOGV("%s", __FUNCTION__);
+
+    return mFrontends[frontendId];
+}
+
+void Tuner::setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId) {
+    mFrontendToDemux[frontendId] = demuxId;
+}
+
+void Tuner::frontendStopTune(uint32_t frontendId) {
+    map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
+    uint32_t demuxId;
+    if (it != mFrontendToDemux.end()) {
+        demuxId = it->second;
+        mDemuxes[demuxId]->stopBroadcastInput();
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
new file mode 100644
index 0000000..96da257
--- /dev/null
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_
+
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <map>
+#include "Demux.h"
+#include "Frontend.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+class Frontend;
+class Demux;
+
+class Tuner : public ITuner {
+  public:
+    Tuner();
+    virtual Return<void> getFrontendIds(getFrontendIds_cb _hidl_cb) override;
+
+    virtual Return<void> openFrontendById(uint32_t frontendId,
+                                          openFrontendById_cb _hidl_cb) override;
+
+    virtual Return<void> openDemux(openDemux_cb _hidl_cb) override;
+
+    virtual Return<void> getDemuxCaps(getDemuxCaps_cb _hidl_cb) override;
+
+    virtual Return<void> openDescrambler(openDescrambler_cb _hidl_cb) override;
+
+    virtual Return<void> getFrontendInfo(FrontendId frontendId,
+                                         getFrontendInfo_cb _hidl_cb) override;
+
+    virtual Return<void> getLnbIds(getLnbIds_cb _hidl_cb) override;
+
+    virtual Return<void> openLnbById(LnbId lnbId, openLnbById_cb _hidl_cb) override;
+
+    sp<Frontend> getFrontendById(uint32_t frontendId);
+
+    void setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId);
+
+    void frontendStopTune(uint32_t frontendId);
+
+  private:
+    virtual ~Tuner();
+    // Static mFrontends array to maintain local frontends information
+    vector<sp<Frontend>> mFrontends;
+    std::map<uint32_t, uint32_t> mFrontendToDemux;
+    std::map<uint32_t, sp<Demux>> mDemuxes;
+    // To maintain how many Frontends we have
+    int mFrontendSize;
+    // The last used demux id. Initial value is -1.
+    // First used id will be 0.
+    int mLastUsedId = -1;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_
diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc
new file mode 100644
index 0000000..ad72fae
--- /dev/null
+++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc
@@ -0,0 +1,9 @@
+service vendor.tuner-hal-1-0 /vendor/bin/hw/android.hardware.tv.tuner@1.0-service-lazy
+    interface android.hardware.tv.tuner@1.0::ITuner default
+    oneshot
+    disabled
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.xml b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.xml
new file mode 100644
index 0000000..4bcfe10
--- /dev/null
+++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.tv.tuner</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ITuner</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc
new file mode 100644
index 0000000..6d59ed7
--- /dev/null
+++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc
@@ -0,0 +1,6 @@
+service vendor.tuner-hal-1-0 /vendor/bin/hw/android.hardware.tv.tuner@1.0-service
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.xml b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.xml
new file mode 100644
index 0000000..4bcfe10
--- /dev/null
+++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.tv.tuner</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ITuner</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/service.cpp b/tv/tuner/1.0/default/service.cpp
new file mode 100644
index 0000000..581d269
--- /dev/null
+++ b/tv/tuner/1.0/default/service.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 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_NDEBUG 0
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.tv.tuner@1.0-service-lazy"
+#else
+#define LOG_TAG "android.hardware.tv.tuner@1.0-service"
+#endif
+
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+#include "Tuner.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::implementation::Tuner;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main() {
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    android::sp<ITuner> service = new Tuner();
+    android::status_t status;
+    if (kLazyService) {
+        auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
+        status = serviceRegistrar->registerService(service);
+    } else {
+        status = service->registerAsService();
+    }
+    LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering tuner service: %d", status);
+
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
new file mode 100644
index 0000000..ef33952
--- /dev/null
+++ b/tv/tuner/1.0/types.hal
@@ -0,0 +1,2763 @@
+/*
+ * 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.tv.tuner@1.0;
+
+import android.hidl.safe_union@1.0;
+import android.hidl.safe_union@1.0::Monostate;
+
+@export
+enum Result : int32_t {
+    SUCCESS,
+    UNAVAILABLE,
+    NOT_INITIALIZED,
+    INVALID_STATE,
+    INVALID_ARGUMENT,
+    OUT_OF_MEMORY,
+    UNKNOWN_ERROR,
+};
+
+/**
+ * Frontend ID.
+ */
+typedef uint32_t FrontendId;
+
+/**
+ *  Frontend Types.
+ */
+@export
+enum FrontendType : uint32_t {
+    UNDEFINED = 0,
+    ANALOG,
+    /**
+     * Advanced Television Systems Committee (ATSC) Standard A/72.
+     */
+    ATSC,
+    /**
+     * Advanced Television Systems Committee (ATSC 3.0) Standard A/300.
+     */
+    ATSC3,
+    /**
+     * Digital Video Broadcasting - Cable
+     * DVB Cable Frontend Standard ETSI EN 300 468 V1.15.1.
+     */
+    DVBC,
+    /**
+     * Digital Video Broadcasting - Satellite
+     * DVB Satellite Frontend Standard ETSI EN 300 468 V1.15.1 and
+     * ETSI EN 302 307-2 V1.1.1.
+     */
+    DVBS,
+    /**
+     * Digital Video Broadcasting - Terrestrial
+     * DVB Terresttrial Frontend Standard ETSI EN 300 468 V1.15.1 and
+     * ETSI EN 302 755 V1.4.1.
+     */
+    DVBT,
+    /**
+     * Integrated Services Digital Broadcasting-Satellite (ISDB-S)
+     * ARIB STD-B20 is technical document of ISDB-S.
+     */
+    ISDBS,
+    /**
+     * Integrated Services Digital Broadcasting-Satellite (ISDB-S)
+     * ARIB STD-B44 is technical document of ISDB-S3.
+     */
+    ISDBS3,
+    /**
+     * Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD)
+     * ABNT NBR 15603 is technical document of ISDB-T.
+     */
+    ISDBT,
+};
+
+/**
+ *  Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1
+ *  and ETSI EN 302 307-2 V1.1.1.
+ */
+@export
+enum FrontendInnerFec : uint64_t {
+    /**
+     * Not defined
+     */
+    FEC_UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set FEC automatically
+     */
+    AUTO = 1 << 0,
+    /**
+     * 1/2 conv. code rate
+     */
+    FEC_1_2 = 1 << 1,
+    /**
+     * 1/3 conv. code rate
+     */
+    FEC_1_3 = 1 << 2,
+    /**
+     * 1/4 conv. code rate
+     */
+    FEC_1_4 = 1 << 3,
+    /**
+     * 1/5 conv. code rate
+     */
+    FEC_1_5 = 1 << 4,
+    /**
+     * 2/3 conv. code rate
+     */
+    FEC_2_3 = 1 << 5,
+    /**
+     * 2/5 conv. code rate
+     */
+    FEC_2_5 = 1 << 6,
+    /**
+     * 2/9 conv. code rate
+     */
+    FEC_2_9 = 1 << 7,
+    /**
+     * 3/4 conv. code rate
+     */
+    FEC_3_4 = 1 << 8,
+    /**
+     * 3/5 conv. code rate
+     */
+    FEC_3_5 = 1 << 9,
+    /**
+     * 4/5 conv. code rate
+     */
+    FEC_4_5 = 1 << 10,
+    /**
+     * 4/15 conv. code rate
+     */
+    FEC_4_15 = 1 << 11,
+    /**
+     * 5/6 conv. code rate
+     */
+    FEC_5_6 = 1 << 12,
+    /**
+     * 5/9 conv. code rate
+     */
+    FEC_5_9 = 1 << 13,
+    /**
+     * 6/7 conv. code rate
+     */
+    FEC_6_7 = 1 << 14,
+    /**
+     * 7/8 conv. code rate
+     */
+    FEC_7_8 = 1 << 15,
+    /**
+     * 7/9 conv. code rate
+     */
+    FEC_7_9 = 1 << 16,
+    /**
+     * 7/15 conv. code rate
+     */
+    FEC_7_15 = 1 << 17,
+    /**
+     * 8/9 conv. code rate
+     */
+    FEC_8_9 = 1 << 18,
+    /**
+     * 8/15 conv. code rate
+     */
+    FEC_8_15 = 1 << 19,
+    /**
+     * 9/10 conv. code rate
+     */
+    FEC_9_10 = 1 << 20,
+    /**
+     * 9/20 conv. code rate
+     */
+    FEC_9_20 = 1 << 21,
+    /**
+     * 11/15 conv. code rate
+     */
+    FEC_11_15 = 1 << 22,
+    /**
+     * 11/20 conv. code rate
+     */
+    FEC_11_20 = 1 << 23,
+    /**
+     * 11/45 conv. code rate
+     */
+    FEC_11_45 = 1 << 24,
+    /**
+     * 13/18 conv. code rate
+     */
+    FEC_13_18 = 1 << 25,
+    /**
+     * 13/45 conv. code rate
+     */
+    FEC_13_45 = 1 << 26,
+    /**
+     * 14/45 conv. code rate
+     */
+    FEC_14_45 = 1 << 27,
+    /**
+     * 23/36 conv. code rate
+     */
+    FEC_23_36 = 1 << 28,
+    /**
+     * 25/36 conv. code rate
+     */
+    FEC_25_36 = 1 << 29,
+    /**
+     * 26/45 conv. code rate
+     */
+    FEC_26_45 = 1 << 30,
+    /**
+     * 28/45 conv. code rate
+     */
+    FEC_28_45 = 1 << 31,
+    /**
+     * 29/45 conv. code rate
+     */
+    FEC_29_45 = 1 << 32,
+    /**
+     * 31/45 conv. code rate
+     */
+    FEC_31_45 = 1 << 33,
+    /**
+     * 32/45 conv. code rate
+     */
+    FEC_32_45 = 1 << 34,
+    /**
+     * 77/90 conv. code rate
+     */
+    FEC_77_90 = 1 << 35,
+};
+
+/**
+ *  Modulation Type for ATSC.
+ */
+@export
+enum FrontendAtscModulation : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set modulation automatically
+     */
+    AUTO = 1 << 0,
+    MOD_8VSB = 1 << 2,
+    MOD_16VSB = 1 << 3,
+};
+
+/**
+ *  Signal Setting for ATSC Frontend.
+ */
+struct FrontendAtscSettings {
+    /**
+     * Signal frequency in Hertz
+     */
+    uint32_t frequency;
+
+    FrontendAtscModulation modulation;
+};
+
+/**
+ *  Capabilities for ATSC Frontend.
+ */
+struct FrontendAtscCapabilities {
+    /**
+     * Modulation capability
+     */
+    bitfield<FrontendAtscModulation> modulationCap;
+};
+
+/**
+ *  Modulation Type for ATSC3.
+ */
+@export
+enum FrontendAtsc3Modulation : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set modulation automatically
+     */
+    AUTO = 1 << 0,
+    MOD_QPSK = 1 << 1,
+    MOD_16QAM = 1 << 2,
+    MOD_64QAM = 1 << 3,
+    MOD_256QAM = 1 << 4,
+    MOD_1024QAM = 1 << 5,
+    MOD_4096QAM = 1 << 6,
+};
+
+/**
+ *  Bandwidth for ATSC3.
+ */
+@export
+enum FrontendAtsc3Bandwidth : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set bandwidth automatically
+     */
+    AUTO = 1 << 0,
+    BANDWIDTH_6MHZ = 1 << 1,
+    BANDWIDTH_7MHZ = 1 << 2,
+    BANDWIDTH_8MHZ = 1 << 3,
+};
+
+/**
+ *  Time Interleave Mode for ATSC3.
+ */
+@export
+enum FrontendAtsc3TimeInterleaveMode : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set TimeInterleaveMode automatically
+     */
+    AUTO = 1 << 0,
+    CTI = 1 << 1,
+    HTI = 1 << 2,
+};
+
+/**
+ *  Code Rate for ATSC3.
+ */
+@export
+enum FrontendAtsc3CodeRate : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Coderate automatically
+     */
+    AUTO = 1 << 0,
+    CODERATE_2_15 = 1 << 1,
+    CODERATE_3_15 = 1 << 2,
+    CODERATE_4_15 = 1 << 3,
+    CODERATE_5_15 = 1 << 4,
+    CODERATE_6_15 = 1 << 5,
+    CODERATE_7_15 = 1 << 6,
+    CODERATE_8_15 = 1 << 7,
+    CODERATE_9_15 = 1 << 8,
+    CODERATE_10_15 = 1 << 9,
+    CODERATE_11_15 = 1 << 10,
+    CODERATE_12_15 = 1 << 11,
+    CODERATE_13_15 = 1 << 12,
+};
+
+/**
+ *  Forward Error Correction (FEC) for ATSC3.
+ */
+@export
+enum FrontendAtsc3Fec : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set FEC automatically
+     */
+    AUTO = 1 << 0,
+    BCH_LDPC_16K = 1 << 1,
+    BCH_LDPC_64K = 1 << 2,
+    CRC_LDPC_16K = 1 << 3,
+    CRC_LDPC_64K = 1 << 4,
+    LDPC_16K = 1 << 5,
+    LDPC_64K = 1 << 6,
+};
+
+/**
+ *  Demodulator Output Format for an ATSC3 Frontend.
+ */
+@export
+enum FrontendAtsc3DemodOutputFormat : uint8_t {
+    /**
+     * Dummy. Scan uses this.
+     */
+    UNDEFINED = 0,
+    /**
+     * ALP format. Typically used in US region.
+     */
+    ATSC3_LINKLAYER_PACKET = 1 << 0,
+    /**
+     * BaseBand packet format. Typically used in Korea region.
+     */
+    BASEBAND_PACKET = 1 << 1,
+};
+
+/**
+ *  PLP basis Signal Settings for an ATSC3 Frontend.
+ */
+struct FrontendAtsc3PlpSettings {
+    uint8_t plpId;
+
+    FrontendAtsc3Modulation modulation;
+
+    FrontendAtsc3TimeInterleaveMode interleaveMode;
+
+    FrontendAtsc3CodeRate codeRate;
+
+    FrontendAtsc3Fec fec;
+};
+
+/**
+ *  Signal Settings for an ATSC3 Frontend.
+ */
+struct FrontendAtsc3Settings {
+    /**
+     * Signal frequency in Hertz
+     */
+    uint32_t frequency;
+
+    /**
+     * Bandwidth of tuning band.
+     */
+    FrontendAtsc3Bandwidth bandwidth;
+
+    FrontendAtsc3DemodOutputFormat demodOutputFormat;
+
+    vec<FrontendAtsc3PlpSettings> plpSettings;
+};
+
+/**
+ *  Capabilities for ATSC3 Frontend.
+ */
+struct FrontendAtsc3Capabilities {
+    /**
+     * Bandwidth capability
+     */
+    bitfield<FrontendAtsc3Bandwidth> bandwidthCap;
+
+    /**
+     * Modulation capability
+     */
+    bitfield<FrontendAtsc3Modulation> modulationCap;
+
+    /**
+     * TimeInterleaveMode capability
+     */
+    bitfield<FrontendAtsc3TimeInterleaveMode> timeInterleaveModeCap;
+
+    /**
+     * CodeRate capability
+     */
+    bitfield<FrontendAtsc3CodeRate> codeRateCap;
+
+    /**
+     * FEC capability
+     */
+    bitfield<FrontendAtsc3Fec> fecCap;
+
+    /**
+     * Demodulator Output Format capability
+     */
+    bitfield<FrontendAtsc3DemodOutputFormat> demodOutputFormatCap;
+};
+
+/**
+ *  Modulation Type for DVBS.
+ */
+@export
+enum FrontendDvbsModulation : int32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Modulation automatically
+     */
+    AUTO = 1 << 0,
+    MOD_QPSK = 1 << 1,
+    MOD_8PSK = 1 << 2,
+    MOD_16QAM = 1 << 3,
+    MOD_16PSK = 1 << 4,
+    MOD_32PSK = 1 << 5,
+    MOD_ACM = 1 << 6,
+    MOD_8APSK = 1 << 7,
+    MOD_16APSK = 1 << 8,
+    MOD_32APSK = 1 << 9,
+    MOD_64APSK = 1 << 10,
+    MOD_128APSK = 1 << 11,
+    MOD_256APSK = 1 << 12,
+    /**
+     * Reserved for Proprietary modulation
+     */
+    MOD_RESERVED = 1 << 13,
+};
+
+/**
+ *  Roll Off value for DVBS.
+ */
+@export
+enum FrontendDvbsRolloff : uint32_t {
+    UNDEFINED,
+    ROLLOFF_0_35,
+    ROLLOFF_0_25,
+    ROLLOFF_0_20,
+    ROLLOFF_0_15,
+    ROLLOFF_0_10,
+    ROLLOFF_0_5,
+};
+
+/**
+ *  Pilot mode for DVBS.
+ */
+@export
+enum FrontendDvbsPilot : uint32_t {
+    UNDEFINED,
+    ON,
+    OFF,
+    AUTO,
+};
+
+/**
+ *  Code Rate for DVBS.
+ */
+struct FrontendDvbsCodeRate {
+    FrontendInnerFec fec;
+
+    bool isLinear;
+
+    /**
+     * true if enable short frame
+     */
+    bool isShortFrames;
+
+    /**
+     * bits number in 1000 symbol. 0 if use the default.
+     */
+    uint32_t bitsPer1000Symbol;
+};
+
+/**
+ *  Sub standards in DVBS.
+ */
+@export
+enum FrontendDvbsStandard : uint8_t {
+    AUTO = 1 << 0,
+    S = 1 << 1,
+    S2 = 1 << 2,
+    S2X = 1 << 3,
+};
+
+/**
+ *  Signal Settings for an DVBS Frontend.
+ */
+struct FrontendDvbsSettings {
+    /**
+     * Signal frequency in Hertz
+     */
+    uint32_t frequency;
+
+    FrontendDvbsModulation modulation;
+
+    FrontendDvbsCodeRate coderate;
+
+    /**
+     * Symbols per second
+     */
+    uint32_t symbolRate;
+
+    FrontendDvbsRolloff rolloff;
+
+    FrontendDvbsPilot pilot;
+
+    uint32_t inputStreamId;
+
+    FrontendDvbsStandard standard;
+};
+
+/**
+ *  Capabilities for DVBS Frontend.
+ */
+struct FrontendDvbsCapabilities {
+    bitfield<FrontendDvbsModulation> modulationCap;
+
+    bitfield<FrontendInnerFec> innerfecCap;
+
+    bitfield<FrontendDvbsStandard> standard;
+};
+
+/**
+ *  Modulation Type for DVBC.
+ */
+@export
+enum FrontendDvbcModulation : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Modulation automatically
+     */
+    AUTO = 1 << 0,
+    MOD_16QAM = 1 << 1,
+    MOD_32QAM = 1 << 2,
+    MOD_64QAM = 1 << 3,
+    MOD_128QAM = 1 << 4,
+    MOD_256QAM = 1 << 5,
+};
+
+/**
+ *  Outer Forward Error Correction (FEC) Type for DVBC.
+ */
+@export
+enum FrontendDvbcOuterFec : uint32_t {
+    UNDEFINED = 0,
+    OUTER_FEC_NONE,
+    OUTER_FEC_RS,
+};
+
+/**
+ *   Annex Type for DVBC.
+ */
+@export
+enum FrontendDvbcAnnex : uint8_t {
+    UNDEFINED = 0,
+    A = 1 << 0,
+    B = 1 << 1,
+    C = 1 << 2,
+};
+
+/**
+ *   Spectral Inversion Type for DVBC.
+ */
+@export
+enum FrontendDvbcSpectralInversion : uint32_t {
+    UNDEFINED,
+    NORMAL,
+    INVERTED,
+};
+
+/**
+ *  Signal Settings for an DVBC Frontend.
+ */
+struct FrontendDvbcSettings {
+    /**
+     * Signal frequency in Hertz
+     */
+    uint32_t frequency;
+
+    FrontendDvbcModulation modulation;
+
+    FrontendInnerFec fec;
+
+    /**
+     * Symbols per second
+     */
+    uint32_t symbolRate;
+
+    FrontendDvbcOuterFec outerFec;
+
+    FrontendDvbcAnnex annex;
+
+    FrontendDvbcSpectralInversion spectralInversion;
+};
+
+/**
+ *  Capabilities for DVBC Frontend.
+ */
+struct FrontendDvbcCapabilities {
+    bitfield<FrontendDvbcModulation> modulationCap;
+
+    bitfield<FrontendInnerFec> fecCap;
+
+    bitfield<FrontendDvbcAnnex> annexCap;
+};
+
+/**
+ *  Bandwidth Type for DVBT.
+ */
+@export
+enum FrontendDvbtBandwidth : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Bandwidth automatically
+     */
+    AUTO = 1 << 0,
+    BANDWIDTH_8MHZ = 1 << 1,
+    BANDWIDTH_7MHZ = 1 << 2,
+    BANDWIDTH_6MHZ = 1 << 3,
+    BANDWIDTH_5MHZ = 1 << 4,
+    BANDWIDTH_1_7MHZ = 1 << 5,
+    BANDWIDTH_10MHZ = 1 << 6,
+};
+
+/**
+ *  Constellation Type for DVBT.
+ */
+@export
+enum FrontendDvbtConstellation : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Constellation automatically
+     */
+    AUTO = 1 << 0,
+    CONSTELLATION_QPSK = 1 << 1,
+    CONSTELLATION_16QAM = 1 << 2,
+    CONSTELLATION_64QAM = 1 << 3,
+    CONSTELLATION_256QAM = 1 << 4,
+};
+
+/**
+ *  Hierarchy Type for DVBT.
+ */
+@export
+enum FrontendDvbtHierarchy : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Hierarchy automatically
+     */
+    AUTO = 1 << 0,
+    HIERARCHY_NON_NATIVE = 1 << 1,
+    HIERARCHY_1_NATIVE = 1 << 2,
+    HIERARCHY_2_NATIVE = 1 << 3,
+    HIERARCHY_4_NATIVE = 1 << 4,
+    HIERARCHY_NON_INDEPTH = 1 << 5,
+    HIERARCHY_1_INDEPTH = 1 << 6,
+    HIERARCHY_2_INDEPTH = 1 << 7,
+    HIERARCHY_4_INDEPTH = 1 << 8,
+};
+
+/**
+ *  Hierarchy Type for DVBT.
+ */
+@export
+enum FrontendDvbtCoderate : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Hierarchy automatically
+     */
+    AUTO = 1 << 0,
+    CODERATE_1_2 = 1 << 1,
+    CODERATE_2_3 = 1 << 2,
+    CODERATE_3_4 = 1 << 3,
+    CODERATE_5_6 = 1 << 4,
+    CODERATE_7_8 = 1 << 5,
+    CODERATE_3_5 = 1 << 6,
+    CODERATE_4_5 = 1 << 7,
+    CODERATE_6_7 = 1 << 8,
+    CODERATE_8_9 = 1 << 9,
+};
+
+/**
+ *  Guard Interval Type for DVBT.
+ */
+@export
+enum FrontendDvbtGuardInterval : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Guard Interval automatically
+     */
+    AUTO = 1 << 0,
+    INTERVAL_1_32 = 1 << 1,
+    INTERVAL_1_16 = 1 << 2,
+    INTERVAL_1_8 = 1 << 3,
+    INTERVAL_1_4 = 1 << 4,
+    INTERVAL_1_128 = 1 << 5,
+    INTERVAL_19_128 = 1 << 6,
+    INTERVAL_19_256 = 1 << 7,
+};
+
+/**
+ *  Transmission Mode for DVBT.
+ */
+@export
+enum FrontendDvbtTransmissionMode : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Transmission Mode automatically
+     */
+    AUTO = 1 << 0,
+    MODE_2K = 1 << 1,
+    MODE_8K = 1 << 2,
+    MODE_4K = 1 << 3,
+    MODE_1K = 1 << 4,
+    MODE_16K = 1 << 5,
+    MODE_32K = 1 << 6,
+};
+
+/**
+ *   Physical Layer Pipe (PLP) Mode for DVBT.
+ */
+enum FrontendDvbtPlpMode : uint32_t {
+    UNDEFINED,
+    AUTO,
+    MANUAL,
+};
+
+/**
+ *  Sub standards in DVBT.
+ */
+@export
+enum FrontendDvbtStandard : uint8_t {
+    AUTO = 1 << 0,
+    T = 1 << 1,
+    T2 = 1 << 2,
+};
+
+/**
+ *  Signal Settings for DVBT Frontend.
+ */
+struct FrontendDvbtSettings {
+    /**
+     * Signal frequency in Hertz
+     */
+    uint32_t frequency;
+
+    FrontendDvbtTransmissionMode transmissionMode;
+
+    FrontendDvbtBandwidth bandwidth;
+
+    FrontendDvbtConstellation constellation;
+
+    FrontendDvbtHierarchy hierarchy;
+
+    /**
+     * Code Rate for High Priority level
+     */
+    FrontendDvbtCoderate hpCoderate;
+
+    /**
+     * Code Rate for Low Priority level
+     */
+    FrontendDvbtCoderate lpCoderate;
+
+    FrontendDvbtGuardInterval guardInterval;
+
+    bool isHighPriority;
+
+    FrontendDvbtStandard standard;
+
+    bool isMiso;
+
+    FrontendDvbtPlpMode plpMode;
+
+    /**
+     * Physical Layer Pipe (PLP) Id
+     */
+    uint8_t plpId;
+
+    /**
+     * Group Id for Physical Layer Pipe (PLP)
+     */
+    uint8_t plpGroupId;
+};
+
+/**
+ *  Capabilities for DVBT Frontend.
+ */
+struct FrontendDvbtCapabilities {
+    bitfield<FrontendDvbtTransmissionMode> transmissionModeCap;
+
+    bitfield<FrontendDvbtBandwidth> bandwidthCap;
+
+    bitfield<FrontendDvbtConstellation> constellationCap;
+
+    bitfield<FrontendDvbtCoderate> coderateCap;
+
+    bitfield<FrontendDvbtHierarchy> hierarchyCap;
+
+    bitfield<FrontendDvbtGuardInterval> guardIntervalCap;
+
+    bool isT2Supported;
+
+    bool isMisoSupported;
+};
+
+/**
+ *  Roll Off Type for ISDBS.
+ */
+@export
+enum FrontendIsdbsRolloff : uint32_t {
+    UNDEFINED,
+    ROLLOFF_0_35,
+};
+
+/**
+ *  Modulaltion Type for ISDBS.
+ */
+@export
+enum FrontendIsdbsModulation : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Modulation automatically
+     */
+    AUTO = 1 << 0,
+    MOD_BPSK = 1 << 1,
+    MOD_QPSK = 1 << 2,
+    MOD_TC8PSK = 1 << 3,
+};
+
+/**
+ *  Code Rate Type for ISDBS.
+ */
+@export
+enum FrontendIsdbsCoderate : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Code Rate automatically
+     */
+    AUTO = 1 << 0,
+    CODERATE_1_2 = 1 << 1,
+    CODERATE_2_3 = 1 << 2,
+    CODERATE_3_4 = 1 << 3,
+    CODERATE_5_6 = 1 << 4,
+    CODERATE_7_8 = 1 << 5,
+};
+
+/**
+ *  Stream Id Type for ISDBS.
+ */
+@export
+enum FrontendIsdbsStreamIdType : uint32_t {
+    STREAM_ID,
+    RELATIVE_STREAM_NUMBER,
+};
+
+/**
+ *  Signal Settings for ISDBS Frontend.
+ */
+struct FrontendIsdbsSettings {
+    /**
+     * Signal frequency in Hertz
+     */
+    uint32_t frequency;
+
+    uint16_t streamId;
+
+    FrontendIsdbsStreamIdType streamIdType;
+
+    FrontendIsdbsModulation modulation;
+
+    FrontendIsdbsCoderate coderate;
+
+    /**
+     * Symbols per second
+     */
+    uint32_t symbolRate;
+
+    FrontendIsdbsRolloff rolloff;
+};
+
+/**
+ *  Capabilities for ISDBS Frontend.
+ */
+struct FrontendIsdbsCapabilities {
+    bitfield<FrontendIsdbsModulation> modulationCap;
+
+    bitfield<FrontendIsdbsCoderate> coderateCap;
+};
+
+/**
+ *  Roll of Type for ISDBS3.
+ */
+@export
+enum FrontendIsdbs3Rolloff : uint32_t {
+    UNDEFINED,
+    ROLLOFF_0_03,
+};
+
+/**
+ *  Modulaltion Type for ISDBS3.
+ */
+@export
+enum FrontendIsdbs3Modulation : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Modulation automatically
+     */
+    AUTO = 1 << 5,
+    MOD_BPSK = 1 << 1,
+    MOD_QPSK = 1 << 2,
+    MOD_8PSK = 1 << 3,
+    MOD_16APSK = 1 << 4,
+    MOD_32APSK = 1 << 5,
+};
+
+/**
+ *  Code Rate Type for ISDBS3.
+ */
+@export
+enum FrontendIsdbs3Coderate : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Code Rate automatically
+     */
+    AUTO = 1 << 0,
+    CODERATE_1_3 = 1 << 1,
+    CODERATE_2_5 = 1 << 2,
+    CODERATE_1_2 = 1 << 3,
+    CODERATE_3_5 = 1 << 4,
+    CODERATE_2_3 = 1 << 5,
+    CODERATE_3_4 = 1 << 6,
+    CODERATE_7_9 = 1 << 7,
+    CODERATE_4_5 = 1 << 8,
+    CODERATE_5_6 = 1 << 9,
+    CODERATE_7_8 = 1 << 10,
+    CODERATE_9_10 = 1 << 11,
+};
+
+/**
+ *  Signal Settings for ISDBS3 Frontend.
+ */
+struct FrontendIsdbs3Settings {
+    /**
+     * Signal frequency in Hertz
+     */
+    uint32_t frequency;
+
+    uint16_t streamId;
+
+    FrontendIsdbsStreamIdType streamIdType;
+
+    FrontendIsdbs3Modulation modulation;
+
+    FrontendIsdbs3Coderate coderate;
+
+    /**
+     * Symbols per second
+     */
+    uint32_t symbolRate;
+
+    FrontendIsdbs3Rolloff rolloff;
+};
+
+/**
+ *  Capabilities for ISDBS3 Frontend.
+ */
+struct FrontendIsdbs3Capabilities {
+    bitfield<FrontendIsdbs3Modulation> modulationCap;
+
+    bitfield<FrontendIsdbs3Coderate> coderateCap;
+};
+
+/**
+ *   Mode for ISDBT.
+ */
+@export
+enum FrontendIsdbtMode : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Mode automatically
+     */
+    AUTO = 1 << 0,
+    MODE_1 = 1 << 1,
+    MODE_2 = 1 << 2,
+    MODE_3 = 1 << 3,
+};
+
+/**
+ *   Bandwidth for ISDBT.
+ */
+@export
+enum FrontendIsdbtBandwidth : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Bandwidth automatically
+     */
+    AUTO = 1 << 0,
+    BANDWIDTH_8MHZ = 1 << 1,
+    BANDWIDTH_7MHZ = 1 << 2,
+    BANDWIDTH_6MHZ = 1 << 3,
+};
+
+/**
+ *   Modulation for ISDBT.
+ */
+@export
+enum FrontendIsdbtModulation : uint32_t {
+    UNDEFINED = 0,
+    /**
+     * hardware is able to detect and set Modulation automatically
+     */
+    AUTO = 1 << 0,
+    MOD_DQPSK = 1 << 1,
+    MOD_QPSK = 1 << 2,
+    MOD_16QAM = 1 << 3,
+    MOD_64QAM = 1 << 4,
+};
+
+typedef FrontendDvbtCoderate FrontendIsdbtCoderate;
+
+typedef FrontendDvbtGuardInterval FrontendIsdbtGuardInterval;
+
+/**
+ *  Signal Settings for ISDBT Frontend.
+ */
+struct FrontendIsdbtSettings {
+    /**
+     * Signal frequency in Hertz
+     */
+    uint32_t frequency;
+
+    FrontendIsdbtModulation modulation;
+
+    FrontendIsdbtBandwidth bandwidth;
+
+    FrontendIsdbtMode mode;
+
+    FrontendIsdbtCoderate coderate;
+
+    FrontendIsdbtGuardInterval guardInterval;
+
+    uint32_t serviceAreaId;
+};
+
+/**
+ *  Capabilities for ISDBT Frontend.
+ */
+struct FrontendIsdbtCapabilities {
+    bitfield<FrontendIsdbtMode> modeCap;
+
+    bitfield<FrontendIsdbtBandwidth> bandwidthCap;
+
+    bitfield<FrontendIsdbtModulation> constellationCap;
+
+    bitfield<FrontendIsdbtCoderate> coderateCap;
+
+    bitfield<FrontendIsdbtGuardInterval> guardIntervalCap;
+};
+
+/**
+ *   Signal Type for Analog Frontend.
+ */
+@export
+enum FrontendAnalogType : uint32_t {
+    UNDEFINED = 0,
+    PAL = 1 << 0,
+    SECAM = 1 << 1,
+    NTSC = 1 << 2,
+};
+
+/**
+ *   Standard Interchange Format (SIF) for Analog Frontend.
+ */
+@export
+enum FrontendAnalogSifStandard : uint32_t {
+    UNDEFINED = 0,
+    BG = 1 << 0,
+    BG_A2 = 1 << 1,
+    BG_NICAM = 1 << 2,
+    I = 1 << 3,
+    DK = 1 << 4,
+    DK1 = 1 << 5,
+    DK2 = 1 << 6,
+    DK3 = 1 << 7,
+    DK_NICAM = 1 << 8,
+    L = 1 << 9,
+    M = 1 << 10,
+    M_BTSC = 1 << 11,
+    M_A2 = 1 << 12,
+    M_EIA_J = 1 << 13,
+    I_NICAM = 1 << 14,
+    L_NICAM = 1 << 15,
+    L_PRIME = 1 << 16,
+};
+
+/**
+ *  Signal Settings for Analog Frontend.
+ */
+struct FrontendAnalogSettings {
+    /**
+     * Signal frequency in Hertz
+     */
+    uint32_t frequency;
+
+    FrontendAnalogType type;
+
+    FrontendAnalogSifStandard sifStandard;
+};
+
+/**
+ *  Capabilities for Analog Frontend.
+ */
+struct FrontendAnalogCapabilities {
+    bitfield<FrontendAnalogType> typeCap;
+
+    bitfield<FrontendAnalogSifStandard> sifStandardCap;
+};
+
+/**
+ *  Signal Settings for Frontend.
+ */
+safe_union FrontendSettings {
+    FrontendAnalogSettings analog;
+
+    FrontendAtscSettings atsc;
+
+    FrontendAtsc3Settings atsc3;
+
+    FrontendDvbsSettings dvbs;
+
+    FrontendDvbcSettings dvbc;
+
+    FrontendDvbtSettings dvbt;
+
+    FrontendIsdbsSettings isdbs;
+
+    FrontendIsdbs3Settings isdbs3;
+
+    FrontendIsdbtSettings isdbt;
+};
+
+/**
+ *  Scan type for Frontend.
+ */
+enum FrontendScanType : uint32_t {
+    SCAN_UNDEFINED = 0,
+    SCAN_AUTO = 1 << 0,
+    SCAN_BLIND = 1 << 1,
+};
+
+/**
+ *  Scan Message Type for Frontend.
+ */
+enum FrontendScanMessageType : uint32_t {
+    /**
+     * Scan locked the signal.
+     */
+    LOCKED,
+    /**
+     * Scan stopped.
+     */
+    END,
+    /**
+     * Scan progress report.
+     */
+    PROGRESS_PERCENT,
+    /**
+     * Locked frequency report.
+     */
+    FREQUENCY,
+    /**
+     * Locked symbol rate.
+     */
+    SYMBOL_RATE,
+    /**
+     * Locked Plp Ids for DVBT2 frontend.
+     */
+    PLP_IDS,
+    /**
+     * Locked group Ids for DVBT2 frontend.
+     */
+    GROUP_IDS,
+    /**
+     * Stream Ids.
+     */
+    INPUT_STREAM_IDS,
+    /**
+     * Locked signal standard.
+     */
+    STANDARD,
+    /**
+     * PLP status in a tuned frequency band for ATSC3 frontend.
+     */
+    ATSC3_PLP_INFO,
+};
+
+/**
+ *  ATSC3.0 PLP information for scan
+ */
+struct FrontendScanAtsc3PlpInfo {
+    uint8_t plpId;
+
+    bool bLlsFlag;
+};
+
+/**
+ *  Scan Message for Frontend.
+ */
+safe_union FrontendScanMessage {
+    bool isLocked;
+
+    bool isEnd;
+
+    /**
+     * scan progress percent (0..100)
+     */
+    uint8_t progressPercent;
+
+    /**
+     * Signal frequency in Hertz
+     */
+    uint32_t frequency;
+
+    /**
+     * Symbols per second
+     */
+    uint32_t symbolRate;
+
+    vec<uint8_t> plpIds;
+
+    vec<uint8_t> groupIds;
+
+    vec<uint16_t> inputStreamIds;
+
+    safe_union standard {
+        FrontendDvbsStandard sStd;
+
+        FrontendDvbtStandard tStd;
+    } std;
+
+    /**
+     * A list of PLP status in a tuned frequency band for ATSC3 frontend.
+     */
+    vec<FrontendScanAtsc3PlpInfo> atsc3PlpInfos;
+};
+
+/**
+ * Frontend Event Type.
+ */
+@export
+enum FrontendEventType : uint32_t {
+    /**
+     * If frontend locked the signal which is specified by tune method, HAL sends
+     * Locked event.
+     */
+    LOCKED,
+    /**
+     * If frontend can't locked the signal which is specified by tune method,
+     * HAL sends NO_SIGNAL event.
+     */
+    NO_SIGNAL,
+    /**
+     * If frontend detect that the locked signal get lost, HAL sends LOST_LOCK
+     * event.
+     */
+    LOST_LOCK,
+};
+
+/**
+ * Frontend Status Type.
+ */
+@export
+enum FrontendStatusType : uint32_t {
+    /**
+     * Lock status for Demod.
+     */
+    DEMOD_LOCK,
+    /**
+     * Signal to Noise Ratio.
+     */
+    SNR,
+    /**
+     * Bit Error Ratio.
+     */
+    BER,
+    /**
+     * Packages Error Ratio.
+     */
+    PER,
+    /**
+     * Bit Error Ratio before FEC.
+     */
+    PRE_BER,
+    /**
+     * Signal Quality (0..100). Good data over total data in percent can be
+     * used as a way to present Signal Quality.
+     */
+    SIGNAL_QUALITY,
+    /**
+     * Signal Strength.
+     */
+    SIGNAL_STRENGTH,
+    /**
+     * Symbol Rate.
+     */
+    SYMBOL_RATE,
+    /**
+     * Forward Error Correction Type.
+     */
+    FEC,
+    /**
+     * Modulation Type.
+     */
+    MODULATION,
+    /**
+     * Spectral Inversion Type.
+     */
+    SPECTRAL,
+    /**
+     * LNB Voltage.
+     */
+    LNB_VOLTAGE,
+    /**
+     * Physical Layer Pipe ID.
+     */
+    PLP_ID,
+    /**
+     * Status for Emergency Warning Broadcasting System.
+     */
+    EWBS,
+    /**
+     * Automatic Gain Control.
+     */
+    AGC,
+    /**
+     * Low Noise Amplifier.
+     */
+    LNA,
+    /**
+     * Error status by layer.
+     */
+    LAYER_ERROR,
+    /**
+     * CN value by VBER.
+     */
+    VBER_CN,
+    /**
+     * CN value by LBER.
+     */
+    LBER_CN,
+    /**
+     * CN value by XER.
+     */
+    XER_CN,
+    /**
+     * Moduration Error Ratio.
+     */
+    MER,
+    /**
+     * Difference between tuning frequency and actual locked frequency.
+     */
+    FREQ_OFFSET,
+    /**
+     * Hierarchy for DVBT.
+     */
+    HIERARCHY,
+    /**
+     * Lock status for RF.
+     */
+    RF_LOCK,
+    /**
+     * PLP information in a frequency band for ATSC3.0 frontend.
+     */
+    ATSC3_PLP_INFO,
+};
+
+/**
+ * Status for each tuning PLPs
+ */
+struct FrontendStatusAtsc3PlpInfo {
+    /**
+     * PLP Id value.
+     */
+    uint8_t plpId;
+
+    /**
+     * Demod Lock/Unlock status of this particular PLP.
+     */
+    bool isLocked;
+
+    /**
+     * Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation.
+     */
+    uint32_t uec;
+};
+
+/**
+ * Modulation Type for Frontend's status.
+ */
+safe_union FrontendModulationStatus {
+    FrontendDvbcModulation dvbc;
+
+    FrontendDvbsModulation dvbs;
+
+    FrontendIsdbsModulation isdbs;
+
+    FrontendIsdbs3Modulation isdbs3;
+
+    FrontendIsdbtModulation isdbt;
+};
+
+/**
+ *  The status for Frontend.
+ */
+safe_union FrontendStatus {
+    /**
+     * Lock status for Demod in True/False.
+     */
+    bool isDemodLocked;
+
+    /**
+     * SNR value measured by 0.001 dB.
+     */
+    int32_t snr;
+
+    /**
+     * The number of error bit per 1 billion bits.
+     */
+    uint32_t ber;
+
+    /**
+     * The number of error package per 1 billion packages.
+     */
+    uint32_t per;
+
+    /**
+     * The number of error bit per 1 billion bits before FEC.
+     */
+    uint32_t preBer;
+
+    /**
+     * Signal Quality in percent.
+     */
+    uint32_t signalQuality;
+
+    /**
+     * Signal Strength measured by 0.001 dBm.
+     */
+    int32_t signalStrength;
+
+    /**
+     * Symbols per second
+     */
+    uint32_t symbolRate;
+
+    FrontendInnerFec innerFec;
+
+    FrontendModulationStatus modulation;
+
+    FrontendDvbcSpectralInversion inversion;
+
+    LnbVoltage lnbVoltage;
+
+    uint8_t plpId;
+
+    bool isEWBS;
+
+    /**
+     * AGC value is normalized from 0 to 255.
+     */
+    uint8_t agc;
+
+    bool isLnaOn;
+
+    vec<bool> isLayerError;
+
+    /**
+     * CN value by VBER measured by 0.001 dB
+     */
+    int32_t vberCn;
+
+    /**
+     * CN value by LBER measured by 0.001 dB
+     */
+    int32_t lberCn;
+
+    /**
+     * CN value by XER measured by 0.001 dB
+     */
+    int32_t xerCn;
+
+    /**
+     * MER value measured by 0.001 dB
+     */
+    int32_t mer;
+
+    /**
+     * Frequency difference in Hertz.
+     */
+    int32_t freqOffset;
+
+    FrontendDvbtHierarchy hierarchy;
+
+    bool isRfLocked;
+
+    /**
+     * A list of PLP status for tuned PLPs for ATSC3 frontend.
+     */
+    vec<FrontendStatusAtsc3PlpInfo> plpInfo;
+};
+
+/**
+ *  Information for the Frontend.
+ */
+struct FrontendInfo {
+    FrontendType type;
+
+    /**
+     * Frequency in Hertz
+     */
+    uint32_t minFrequency;
+
+    /**
+     * Frequency in Hertz
+     */
+    uint32_t maxFrequency;
+
+    /**
+     * Minimum symbols per second
+     */
+    uint32_t minSymbolRate;
+
+    /**
+     * Maximum symbols per second
+     */
+    uint32_t maxSymbolRate;
+
+    /**
+     * Range in Hertz
+     */
+    uint32_t acquireRange;
+
+    /**
+     * Frontends are assigned with the same exclusiveGroupId if they can't
+     * function at same time. For instance, they share same hardware module.
+     */
+    uint32_t exclusiveGroupId;
+
+    /**
+     * A list of supported status types which client can inquiry
+     */
+    vec<FrontendStatusType> statusCaps;
+
+    safe_union FrontendCapabilities {
+        FrontendAnalogCapabilities analogCaps;
+
+        FrontendAtscCapabilities atscCaps;
+
+        FrontendAtsc3Capabilities atsc3Caps;
+
+        FrontendDvbsCapabilities dvbsCaps;
+
+        FrontendDvbcCapabilities dvbcCaps;
+
+        FrontendDvbtCapabilities dvbtCaps;
+
+        FrontendIsdbsCapabilities isdbsCaps;
+
+        FrontendIsdbs3Capabilities isdbs3Caps;
+
+        FrontendIsdbtCapabilities isdbtCaps;
+    } frontendCaps;
+};
+
+/*
+ * Low-Noise Block downconverter (LNB) ID is used to associate with a hardware
+ * LNB module.
+ */
+typedef uint32_t LnbId;
+
+/**
+ *  Power Voltage Type for LNB.
+ */
+@export
+enum LnbVoltage : uint32_t {
+    NONE,
+    VOLTAGE_5V,
+    VOLTAGE_11V,
+    VOLTAGE_12V,
+    VOLTAGE_13V,
+    VOLTAGE_14V,
+    VOLTAGE_15V,
+    VOLTAGE_18V,
+    VOLTAGE_19V,
+};
+
+/**
+ *  Tone Type for LNB.
+ */
+@export
+enum LnbTone : int32_t {
+    NONE,
+    CONTINUOUS,
+};
+
+/**
+ *  The Position of LNB.
+ */
+@export
+enum LnbPosition : int32_t {
+    UNDEFINED,
+    POSITION_A,
+    POSITION_B,
+};
+
+/**
+ * Lnb Event Type.
+ */
+@export
+enum LnbEventType : uint32_t {
+    DISEQC_RX_OVERFLOW,
+    /**
+     * If LNB detect that outgoing Diseqc message isn't delivered on time.
+     */
+    DISEQC_RX_TIMEOUT,
+    /**
+     * If LNB detect that the incoming Diseqc message has parity error.
+     */
+    DISEQC_RX_PARITY_ERROR,
+    /**
+     * If LNB detect that the LNB is overload.
+     */
+    LNB_OVERLOAD,
+};
+
+/* Demux ID is used to associate with a hardware demux resource. */
+typedef uint32_t DemuxId;
+
+/**
+ * Filter Main Type specifies the protocol that the filter use to extract data
+ * from input stream.
+ */
+@export
+enum DemuxFilterMainType : uint32_t {
+    /**
+     * Transport Stream according to ISO/IEC 13818-1.
+     */
+    TS = 1 << 0,
+    /**
+     * MPEG Media Transport Protocol according to ISO/IEC 23008-1.
+     */
+    MMTP = 1 << 1,
+    /**
+     * Internet Protocol.
+     */
+    IP = 1 << 2,
+    /**
+     * Type Length Value according to ITU-R BT.1869.
+     */
+    TLV = 1 << 3,
+    /**
+     * ATSC Link-Layer Protocol according to A/330 ATSC3.0.
+     */
+    ALP = 1 << 4,
+};
+
+/**
+ * TS Filter Type according to ISO/IEC 13818-1
+ */
+@export
+enum DemuxTsFilterType : uint32_t {
+    UNDEFINED,
+    /**
+     * A filter to filter Section data out from input stream, and queue the
+     * data to the filter's FMQ (Fast Message Queue).
+     */
+    SECTION,
+    /**
+     * A filter to filter Packetized Elementary Stream data out from input
+     * stream, and queue the data to the filter's FMQ.
+     */
+    PES,
+    /**
+     * A filter to filter a Transport Stream out from input stream, and queue
+     * the data to the filter's FMQ.
+     */
+    TS,
+    /**
+     * A filter to filter Audio data out from input stream, and send Audio's
+     * Metadata to client through onFilterEvent.
+     */
+    AUDIO,
+    /**
+     * A filter to filter Video data out from input stream, and send Video's
+     * Metadata to client through onFilterEvent.
+     */
+    VIDEO,
+    /**
+     * A filter to set PCR (Program Clock Reference) channel from input stream.
+     */
+    PCR,
+    /**
+     * A filter to filter data out from input stream, and queue the data to the
+     * buffer of the record.
+     */
+    RECORD,
+    /**
+     * A filter to filter out Timed External Media Information (TEMI) according
+     * to ISO/IEC 13818-1:2013/ DAM 6 from input stream, and send TEMI event to
+     * client through onFilterEvent.
+     */
+    TEMI,
+};
+
+/**
+ * MMTP Filter Type according to ISO/IEC 23008-1
+ */
+@export
+enum DemuxMmtpFilterType : uint32_t {
+    UNDEFINED,
+    /**
+     * A filter to filter signaling data out from input stream, and queue the
+     * data to the filter's FMQ (Fast Message Queue).
+     */
+    SECTION,
+    /**
+     * A filter to filter MFU (Media fragment unit) out from input stream, and
+     * queue the data to the filter's FMQ.
+     */
+    PES,
+    /**
+     * A filter to filter a MMTP stream out from input stream, and queue the
+     * data to the filter's FMQ.
+     */
+    MMTP,
+    /**
+     * A filter to filter Audio data out from input stream, and send Audio's
+     * Metadata to client through onFilterEvent.
+     */
+    AUDIO,
+    /**
+     * A filter to filter Video data out from input stream, and send Video's
+     * Metadata to client through onFilterEvent.
+     */
+    VIDEO,
+    /**
+     * A filter to filter data out from input stream, and queue the data to the
+     * buffer of the record.
+     */
+    RECORD,
+    /**
+     * A filter to filter application data out from input stream, and queue the
+     * data to the filter's FMQ.
+     */
+    DOWNLOAD,
+};
+
+/**
+ * IP Filter Type.
+ */
+@export
+enum DemuxIpFilterType : uint32_t {
+    UNDEFINED,
+    /**
+     * A filter to filter section data out from input stream, and queue the
+     * data to the filter's FMQ (Fast Message Queue).
+     */
+    SECTION,
+    /**
+     * A filter to set NTP (Network Time Procotol) channel from input stream.
+     */
+    NTP,
+    /**
+     * A filter to strip out IP message header and queue the data to the
+     * filter's FMQ.
+     */
+    IP_PAYLOAD,
+    /**
+     * A filter to filter a IP stream out from input stream. The output can be
+     * either upper stream of another filter or queued to the filter's FMQ.
+     */
+    IP,
+    /**
+     * A filter to strip out IP message header and be a data source of another
+     * filter.
+     */
+    PAYLOAD_THROUGH,
+};
+
+/**
+ * TLV Filter Type according to ITU-R BT.1869.
+ */
+@export
+enum DemuxTlvFilterType : uint32_t {
+    UNDEFINED,
+    /**
+     * A filter to filter signaling data out from input stream, and queue the
+     * data to the filter's FMQ (Fast Message Queue).
+     */
+    SECTION,
+    /**
+     * A filter to filter a TLV stream out from input stream. The output can be
+     * either upper stream of another filter or queued to the filter's FMQ.
+     */
+    TLV,
+    /**
+     * A filter to strip out TLV message header and be a data source of another
+     * filter.
+     */
+    PAYLOAD_THROUGH,
+};
+
+/**
+ * ALP Filter Type according to A/330 ATSC3.0.
+ */
+@export
+enum DemuxAlpFilterType : uint32_t {
+    UNDEFINED,
+    /**
+     * A filter to filter signaling data out from input stream, and queue the
+     * data to the filter's FMQ (Fast Message Queue).
+     */
+    SECTION,
+    /**
+     * A filter to set PTP (Precision Time Protocol) channel from input stream.
+     */
+    PTP,
+    /**
+     * A filter to strip out ALP message header and be a data source of another
+     * filter.
+     */
+    PAYLOAD_THROUGH,
+};
+
+/**
+ * Demux Filter Type.
+ */
+struct DemuxFilterType {
+    DemuxFilterMainType mainType;
+
+    safe_union DemuxFilterSubType {
+        DemuxTsFilterType tsFilterType;
+
+        DemuxMmtpFilterType mmtpFilterType;
+
+        DemuxIpFilterType ipFilterType;
+
+        DemuxTlvFilterType tlvFilterType;
+
+        DemuxAlpFilterType alpFilterType;
+    } subType;
+};
+
+/* Packet ID is used to specify packets in transport stream. */
+typedef uint16_t DemuxTpid;
+
+/* Packet ID is used to specify packets in MMTP */
+typedef uint16_t DemuxMmtpPid;
+
+/**
+ * Demux Packet ID.
+ */
+safe_union DemuxPid {
+    DemuxTpid tPid;
+
+    DemuxMmtpPid mmtpPid;
+};
+
+@export
+enum Constant : uint16_t {
+    /**
+     * An invalid packet ID in transport stream according to ISO/IEC 13818-1.
+     */
+    INVALID_TS_PID = 0xFFFF,
+    /**
+     * An invalid Stream ID.
+     */
+    INVALID_STREAM_ID = 0xFFFF,
+};
+
+/**
+ * A status of data in the filter's buffer.
+ */
+@export
+enum DemuxFilterStatus : uint8_t {
+    /**
+     * The data in the filter buffer is ready to be read.
+     */
+    DATA_READY = 1 << 0,
+    /**
+     * The available data amount in the filter buffer is at low level which is
+     * set to 25 percent by default.
+     */
+    LOW_WATER = 1 << 1,
+    /**
+     * The available data amount in the filter buffer is at high level which is
+     * set to 75 percent by default.
+     */
+    HIGH_WATER = 1 << 2,
+    /**
+     * The data in the filter buffer is full and newly filtered data is being
+     * discarded.
+     */
+    OVERFLOW = 1 << 3,
+};
+
+/**
+ * Indexes can be tagged through TS (Transport Stream) header.
+ */
+@export
+enum DemuxTsIndex : uint32_t {
+    FIRST_PACKET = 1 << 0,
+    PAYLOAD_UNIT_START_INDICATOR = 1 << 1,
+    CHANGE_TO_NOT_SCRAMBLED = 1 << 2,
+    CHANGE_TO_EVEN_SCRAMBLED = 1 << 3,
+    CHANGE_TO_ODD_SCRAMBLED = 1 << 4,
+    DISCONTINUITY_INDICATOR = 1 << 5,
+    RANDOM_ACCESS_INDICATOR = 1 << 6,
+    PRIORITY_INDICATOR = 1 << 7,
+    PCR_FLAG = 1 << 8,
+    OPCR_FLAG = 1 << 9,
+    SPLICING_POINT_FLAG = 1 << 10,
+    PRIVATE_DATA = 1 << 11,
+    ADAPTATION_EXTENSION_FLAG = 1 << 12,
+};
+
+/**
+ * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
+ * according to ISO/IEC 13818-1.
+ */
+@export
+enum DemuxScIndex : uint32_t {
+    /**
+     * Start Code is for a new I Frame
+     */
+    I_FRAME = 1 << 0,
+    /**
+     * Start Code is for a new P Frame
+     */
+    P_FRAME = 1 << 1,
+    /**
+     * Start Code is for a new B Frame
+     */
+    B_FRAME = 1 << 2,
+    /**
+     * Start Code is for a new Sequence
+     */
+    SEQUENCE = 1 << 3,
+};
+
+/**
+ * Indexes can be tagged by NAL unit group in HEVC
+ * according to ISO/IEC 23008-2.
+ */
+@export
+enum DemuxScHevcIndex : uint32_t {
+    SPS = 1 << 0,
+    AUD = 1 << 1,
+    SLICE_CE_BLA_W_LP = 1 << 2,
+    SLICE_BLA_W_RADL = 1 << 3,
+    SLICE_BLA_N_LP = 1 << 4,
+    SLICE_IDR_W_RADL = 1 << 5,
+    SLICE_IDR_N_LP = 1 << 6,
+    SLICE_TRAIL_CRA = 1 << 7,
+};
+
+/**
+ * Index type to be used in the filter for record
+ */
+@export
+enum DemuxRecordIndexType : uint32_t {
+    /**
+     * Don't use index
+     */
+    NONE,
+    /**
+     * Use TS index
+     */
+    TS,
+    /**
+     * Use Start Code index
+     */
+    SC,
+    /**
+     * Use Start Code index for HEVC
+     */
+    SC_HEVC,
+};
+
+/**
+ *  Filter Settings for Record data.
+ */
+struct DemuxFilterRecordSettings {
+    DemuxRecordIndexType indexType;
+
+    safe_union IndexMask {
+        bitfield<DemuxTsIndex> tsIndexMask;
+
+        bitfield<DemuxScIndex> scIndexMask;
+
+        bitfield<DemuxScHevcIndex> scHevcIndexMask;
+    } indexMask;
+};
+
+/**
+ *  Bits Settings for Section Filter.
+ */
+struct DemuxFilterSectionBits {
+    /**
+     * The bytes are configured for Section Filter
+     */
+    vec<uint8_t> filter;
+
+    /**
+     * Active bits in the configured bytes to be used for filtering
+     */
+    vec<uint8_t> mask;
+
+    /**
+     * Do positive match at the bit position of the configured bytes when the
+     * bit at same position of the mode is 0.
+     * Do negative match at the bit position of the configured bytes when the
+     * bit at same position of the mode is 1.
+     */
+    vec<uint8_t> mode;
+};
+
+/**
+ *  Filter Settings for Section data according to ISO/IEC 13818-1.
+ */
+struct DemuxFilterSectionSettings {
+    safe_union Condition {
+        DemuxFilterSectionBits sectionBits;
+
+        struct TableInfo {
+            /**
+             * Table ID for Section Filter
+             */
+            uint16_t tableId;
+
+            /**
+             * Version number for Section Filter
+             */
+            uint16_t version;
+        } tableInfo;
+    } condition;
+
+    /**
+     * true if the filter checks CRC and discards data with wrong CRC
+     */
+    bool isCheckCrc;
+
+    /**
+     * true if the filter repeats the data with the same version
+     */
+    bool isRepeat;
+
+    /**
+     * true if the filter send onFilterStatus instead of onFilterEvent.
+     */
+    bool isRaw;
+};
+
+typedef uint16_t DemuxStreamId;
+
+/**
+ *  Filter Settings for a PES Data.
+ */
+struct DemuxFilterPesDataSettings {
+    DemuxStreamId streamId;
+
+    /**
+     * true if the filter send onFilterStatus instead of onFilterEvent.
+     */
+    bool isRaw;
+};
+
+/**
+ *  Filter Settings for a Video and Audio.
+ */
+struct DemuxFilterAvSettings {
+    /**
+     * true if the filter output goes to decoder directly in pass through mode.
+     */
+    bool isPassthrough;
+};
+
+/**
+ *  Filter Settings for a Download.
+ */
+struct DemuxFilterDownloadSettings {
+    uint32_t downloadId;
+};
+
+/**
+ *  IP Settings for a IP filter.
+ */
+struct DemuxIpAddress {
+    safe_union SrcIpAddress {
+        uint8_t[4] v4;
+
+        uint8_t[16] v6;
+    } srcIpAddress;
+
+    safe_union DstIpAddress {
+        uint8_t[4] v4;
+
+        uint8_t[16] v6;
+    } dstIpAddress;
+
+    uint16_t srcPort;
+
+    uint16_t dstPort;
+};
+
+/**
+ *  Filter Settings for a TS filter.
+ */
+struct DemuxTsFilterSettings {
+    DemuxTpid tpid;
+
+    safe_union FilterSettings {
+        /**
+         * Not additional parameters. it's used by PCR, TS, TEMI subtype
+         * filters.
+         */
+        Monostate noinit;
+
+        DemuxFilterSectionSettings section;
+
+        DemuxFilterAvSettings av;
+
+        DemuxFilterPesDataSettings pesData;
+
+        DemuxFilterRecordSettings record;
+    } filterSettings;
+};
+
+/**
+ *  Filter Settings for a MMTP filter.
+ */
+struct DemuxMmtpFilterSettings {
+    DemuxMmtpPid mmtpPid;
+
+    safe_union FilterSettings {
+        /**
+         * Not additional parameters. it's used by MMTP subtype filters.
+         */
+        Monostate noinit;
+
+        DemuxFilterSectionSettings section;
+
+        DemuxFilterAvSettings av;
+
+        DemuxFilterPesDataSettings pesData;
+
+        DemuxFilterRecordSettings record;
+
+        DemuxFilterDownloadSettings download;
+    } filterSettings;
+};
+
+/**
+ *  Filter Settings for a IP filter.
+ */
+struct DemuxIpFilterSettings {
+    DemuxIpAddress ipAddr;
+
+    safe_union FilterSettings {
+        /**
+         * Not additional parameters. it's used by NTP, IP_PAYLOAD,
+         * PAYLOAD_THROUGH subtype filters.
+         */
+        Monostate noinit;
+
+        DemuxFilterSectionSettings section;
+
+        DemuxFilterPesDataSettings pesData;
+
+        /**
+         * true if the data from IP subtype go to next filter directly
+         */
+        bool bPassthrough;
+    } filterSettings;
+};
+
+/**
+ *  Filter Settings for a TLV filter.
+ */
+struct DemuxTlvFilterSettings {
+    uint8_t packetType;
+
+    /**
+     * true if the filtered data is commpressed ip packet
+     */
+    bool bIsCompressedIpPacket;
+
+    safe_union FilterSettings {
+        /**
+         * Not additional parameters. it's used by PAYLOAD_THROUGH subtype
+         * filters.
+         */
+        Monostate noinit;
+
+        DemuxFilterSectionSettings section;
+
+        /**
+         * true if the data from TLV subtype go to next filter directly
+         */
+        bool bPassthrough;
+    } filterSettings;
+};
+
+/**
+ * ALP Length Type
+ */
+@export
+enum DemuxAlpLengthType : uint8_t {
+    UNDEFINED = 0,
+    /**
+     * Length does NOT include additional header. Used in US region.
+     */
+    WITHOUT_ADDITIONAL_HEADER,
+    /**
+     * Length includes additional header. Used in Korea region.
+     */
+    WITH_ADDITIONAL_HEADER,
+};
+
+/**
+ *  Filter Settings for a ALP filter.
+ */
+struct DemuxAlpFilterSettings {
+    /**
+     * 0: IpV4, 2:Compressed Ip, 4:Signaling.
+     */
+    uint8_t packetType;
+
+    DemuxAlpLengthType lengthType;
+
+    safe_union FilterSettings {
+        /**
+         * Not additional parameters. it's used by PTP, PAYLOAD_THROUGH subtype
+         * filters.
+         */
+        Monostate noinit;
+
+        DemuxFilterSectionSettings section;
+    } filterSettings;
+};
+
+/**
+ *  Filter Settings.
+ */
+safe_union DemuxFilterSettings {
+    DemuxTsFilterSettings ts;
+
+    DemuxMmtpFilterSettings mmtp;
+
+    DemuxIpFilterSettings ip;
+
+    DemuxTlvFilterSettings tlv;
+
+    DemuxAlpFilterSettings alp;
+};
+
+/**
+ * The bits of EventFlag in FMQ (Fast message queue) are used by client to
+ * notify HAL the status change.
+ */
+@export
+enum DemuxQueueNotifyBits : uint32_t {
+    /**
+     * client writes data and notify HAL the data is ready.
+     */
+    DATA_READY = 1 << 0,
+    /**
+     * client reads data and notify HAL the data is consumed.
+     */
+    DATA_CONSUMED = 1 << 1,
+};
+
+/**
+ *  Filter Event for Section Filter.
+ */
+struct DemuxFilterSectionEvent {
+    /**
+     * Table ID of filtered data
+     */
+    uint16_t tableId;
+
+    /**
+     * Version number of filtered data
+     */
+    uint16_t version;
+
+    /**
+     * Section number of filtered data
+     */
+    uint16_t sectionNum;
+
+    /**
+     * Data size in bytes of filtered data
+     */
+    uint16_t dataLength;
+};
+
+/**
+ *  Extra Meta Data from AD (Audio Descriptor) according to
+ *  ETSI TS 101 154 V2.1.1.
+ */
+struct AudioExtraMetaData {
+    uint8_t adFade;
+
+    uint8_t adPan;
+
+    uint8_t versionTextTag;
+
+    uint8_t adGainCenter;
+
+    uint8_t adGainFront;
+
+    uint8_t adGainSurround;
+};
+
+/**
+ *  Filter Event for Audio or Video Filter.
+ */
+struct DemuxFilterMediaEvent {
+    DemuxStreamId streamId;
+
+    /**
+     * true if PTS is present in PES header.
+     */
+    bool isPtsPresent;
+
+    /**
+     * Presentation Time Stamp for audio or video frame. It based on 90KHz has
+     * the same format as PTS (Presentation Time Stamp).
+     */
+    uint64_t pts;
+
+    /**
+     * Data size in bytes of audio or video frame
+     */
+    uint32_t dataLength;
+
+    /**
+     * A handle associated to the memory where audio or video data stays.
+     */
+    handle avMemory;
+
+    /**
+     * True if the avMemory is in secure area, and isn't mappable.
+     */
+    bool isSecureMemory;
+
+    /**
+     * MPU sequence number of filtered data (only for MMTP)
+     */
+    uint32_t mpuSequenceNumber;
+
+    bool isPesPrivateData;
+
+    safe_union ExtraMetaData {
+        /**
+         * Not additional parameters. it's used for video.
+         */
+        Monostate noinit;
+
+        AudioExtraMetaData audio;
+    } extraMetaData;
+};
+
+/**
+ *  Filter Event for PES data.
+ */
+struct DemuxFilterPesEvent {
+    DemuxStreamId streamId;
+
+    /**
+     * Data size in bytes of PES data
+     */
+    uint16_t dataLength;
+
+    /**
+     * MPU sequence number of filtered data (only for MMTP)
+     */
+    uint32_t mpuSequenceNumber;
+};
+
+/**
+ *  Filter Event for TS Record data.
+ */
+struct DemuxFilterTsRecordEvent {
+    DemuxPid pid;
+
+    /**
+     * Indexes of record output
+     */
+    safe_union IndexMask {
+        bitfield<DemuxTsIndex> tsIndexMask;
+
+        bitfield<DemuxScIndex> scIndexMask;
+
+        bitfield<DemuxScHevcIndex> scHevcIndexMask;
+    } indexMask;
+
+    /**
+     * Byte number from beginning of the filter's output
+     */
+    uint64_t byteNumber;
+};
+
+/**
+ *  Filter Event for Timed External Media Information (TEMI) data.
+ */
+struct DemuxFilterTemiEvent {
+    /**
+     * Presentation Time Stamp for audio or video frame. It based on 90KHz has
+     * the same format as PTS (Presentation Time Stamp) in ISO/IEC 13818-1.
+     */
+    uint64_t pts;
+
+    /**
+     * TEMI Descriptor Tag
+     */
+    uint8_t descrTag;
+
+    /**
+     * TEMI Descriptor
+     */
+    vec<uint8_t> descrData;
+};
+
+/**
+ *  Filter Event for MMTP Record data.
+ */
+struct DemuxFilterMmtpRecordEvent {
+    bitfield<DemuxScHevcIndex> scHevcIndexMask;
+
+    /**
+     * Byte number from beginning of the filter's output
+     */
+    uint64_t byteNumber;
+};
+
+/**
+ *  Filter Event for Download data.
+ */
+struct DemuxFilterDownloadEvent {
+    uint32_t itemId;
+
+    /**
+     * MPU sequence number of filtered data (only for MMTP)
+     */
+    uint32_t mpuSequenceNumber;
+
+    uint32_t itemFragmentIndex;
+
+    uint32_t lastItemFragmentIndex;
+
+    /**
+     * Data size in bytes of filtered data
+     */
+    uint16_t dataLength;
+};
+
+/**
+ *  Filter Event for IP payload data.
+ */
+struct DemuxFilterIpPayloadEvent {
+    /**
+     * Data size in bytes of IP data
+     */
+    uint16_t dataLength;
+};
+
+/**
+ * Filter Event.
+ */
+struct DemuxFilterEvent {
+    safe_union Event {
+        DemuxFilterSectionEvent section;
+
+        DemuxFilterMediaEvent media;
+
+        DemuxFilterPesEvent pes;
+
+        DemuxFilterTsRecordEvent tsRecord;
+
+        DemuxFilterMmtpRecordEvent mmtpRecord;
+
+        DemuxFilterDownloadEvent download;
+
+        DemuxFilterIpPayloadEvent ipPayload;
+
+        DemuxFilterTemiEvent temi;
+    };
+
+    /**
+     * An array of events
+     */
+    vec<Event> events;
+};
+
+typedef uint32_t AvSyncHwId;
+
+typedef vec<uint8_t> TunerKeyToken;
+
+/**
+ * A data format in demux's output or input according to ISO/IEC 13818-1.
+ */
+@export
+enum DataFormat : uint32_t {
+    /**
+     * Data is Transport Stream.
+     */
+    TS,
+    /**
+     * Data is Packetized Elementary Stream.
+     */
+    PES,
+    /**
+     * Data is Elementary Stream.
+     */
+    ES,
+    /**
+     * Data is TLV (type-length-value) Stream for JP SHV
+     */
+    SHV_TLV,
+};
+
+typedef DemuxFilterStatus RecordStatus;
+
+/**
+ *  The Settings for the record in DVR.
+ */
+struct RecordSettings {
+    /**
+     * Register for interested status events so that the HAL can send these
+     * status events back to client.
+     */
+    bitfield<RecordStatus> statusMask;
+
+    /**
+     * Unconsumed data size in bytes in the record. The HAL uses it to trigger
+     * OutputStatus::LOW_WATER.
+     */
+    uint32_t lowThreshold;
+
+    /**
+     * Unconsumed data size in bytes in the record. The HAL uses it to trigger
+     * OutputStatus::High_WATER.
+     */
+    uint32_t highThreshold;
+
+    /**
+     * The data format in the record.
+     */
+    DataFormat dataFormat;
+
+    /**
+     * The packet size in bytes in the record.
+     */
+    uint8_t packetSize;
+};
+
+/**
+ * A status of the playback in DVR.
+ */
+@export
+enum PlaybackStatus : uint32_t {
+    /**
+     * The space of the demux's playback is empty.
+     */
+    SPACE_EMPTY = 1 << 0,
+    /**
+     * The spece of the demux's playback is almost empty.
+     */
+    SPACE_ALMOST_EMPTY = 1 << 1,
+    /**
+     * The space of the demux's playback is almost full.
+     */
+    SPACE_ALMOST_FULL = 1 << 2,
+    /**
+     * The space of the demux's playback is full.
+     */
+    SPACE_FULL = 1 << 3,
+};
+
+/**
+ * The Setting for the playback in DVR.
+ */
+struct PlaybackSettings {
+    /**
+     * Register for interested status events so that the HAL can send these
+     * status events back to client.
+     */
+    bitfield<PlaybackStatus> statusMask;
+
+    /**
+     * Unused space size in bytes in the playback. The HAL uses it to trigger
+     * InputStatus::SPACE_ALMOST_EMPTY.
+     */
+    uint32_t lowThreshold;
+
+    /**
+     * Unused space size in bytes in the playback. The HAL uses it to trigger
+     * InputStatus::SPACE_ALMOST_FULL.
+     */
+    uint32_t highThreshold;
+
+    /**
+     * The data format in the playback.
+     */
+    DataFormat dataFormat;
+
+    /**
+     * The packet size in bytes in the playback.
+     */
+    uint8_t packetSize;
+};
+
+/**
+ * The type of DVR.
+ */
+@export
+enum DvrType : uint8_t {
+    RECORD,
+    PLAYBACK,
+};
+
+/**
+ * The Setting for DVR.
+ */
+safe_union DvrSettings {
+    RecordSettings record;
+
+    PlaybackSettings playback;
+};
+
+/**
+ *  Capabilities for Demux.
+ */
+struct DemuxCapabilities {
+    /**
+     * The number of Demux to be supported.
+     */
+    uint32_t numDemux;
+
+    /**
+     * The number of record to be supported.
+     */
+    uint32_t numRecord;
+
+    /**
+     * The number of playback to be supported.
+     */
+    uint32_t numPlayback;
+
+    /**
+     * The number of TS Filter to be supported.
+     */
+    uint32_t numTsFilter;
+
+    /**
+     * The number of Section Filter to be supported.
+     */
+    uint32_t numSectionFilter;
+
+    /**
+     * The number of Audio Filter to be supported.
+     */
+    uint32_t numAudioFilter;
+
+    /**
+     * The number of Video Filter to be supported.
+     */
+    uint32_t numVideoFilter;
+
+    /**
+     * The number of PES Filter to be supported.
+     */
+    uint32_t numPesFilter;
+
+    /**
+     * The number of PCR Filter to be supported.
+     */
+    uint32_t numPcrFilter;
+
+    /**
+     * The maximum number of bytes is supported in the mask of Section Filter.
+     */
+    uint32_t numBytesInSectionFilter;
+
+    bitfield<DemuxFilterMainType> filterCaps;
+
+    /**
+     * The array has same elements as DemuxFilterMainType. linkCaps[i] presents
+     * filter's capability as soource for the ith type in DemuxFilterMainType.
+     * The jth bit of linkCaps[i] is 1 if the output of ith type filter can be
+     * data source for the filter type j.
+     */
+    vec<bitfield<DemuxFilterMainType>> linkCaps;
+
+    bool bTimeFilter;
+};
diff --git a/tv/tuner/1.0/vts/OWNERS b/tv/tuner/1.0/vts/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.0/vts/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..7d6b990
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// 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: "VtsHalTvTunerV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalTvTunerV1_0TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.tv.tuner@1.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlallocatorutils",
+        "libhidlmemory",
+        "libcutils",
+        "libfmq",
+    ],
+    shared_libs: [
+        "libbinder",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
new file mode 100644
index 0000000..da3e300
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -0,0 +1,1215 @@
+/*
+ * 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 "Tuner_hidl_hal_test"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IDemux.h>
+#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
+#include <android/hardware/tv/tuner/1.0/IFilter.h>
+#include <android/hardware/tv/tuner/1.0/IFilterCallback.h>
+#include <android/hardware/tv/tuner/1.0/IFrontend.h>
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <binder/MemoryDealer.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <fstream>
+#include <iostream>
+#include <map>
+
+#define WAIT_TIMEOUT 3000000000
+#define WAIT_TIMEOUT_data_ready 3000000000 * 4
+
+using android::Condition;
+using android::IMemory;
+using android::IMemoryHeap;
+using android::MemoryDealer;
+using android::Mutex;
+using android::sp;
+using android::hardware::EventFlag;
+using android::hardware::fromHeap;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::HidlMemory;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MessageQueue;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::DataFormat;
+using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::DvrSettings;
+using android::hardware::tv::tuner::V1_0::DvrType;
+using android::hardware::tv::tuner::V1_0::FrontendAtscModulation;
+using android::hardware::tv::tuner::V1_0::FrontendAtscSettings;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
+using android::hardware::tv::tuner::V1_0::FrontendEventType;
+using android::hardware::tv::tuner::V1_0::FrontendId;
+using android::hardware::tv::tuner::V1_0::FrontendInnerFec;
+using android::hardware::tv::tuner::V1_0::FrontendScanMessage;
+using android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
+using android::hardware::tv::tuner::V1_0::FrontendSettings;
+using android::hardware::tv::tuner::V1_0::IDemux;
+using android::hardware::tv::tuner::V1_0::IDescrambler;
+using android::hardware::tv::tuner::V1_0::IDvr;
+using android::hardware::tv::tuner::V1_0::IDvrCallback;
+using android::hardware::tv::tuner::V1_0::IFilter;
+using android::hardware::tv::tuner::V1_0::IFilterCallback;
+using android::hardware::tv::tuner::V1_0::IFrontend;
+using android::hardware::tv::tuner::V1_0::IFrontendCallback;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using android::hardware::tv::tuner::V1_0::RecordStatus;
+using android::hardware::tv::tuner::V1_0::Result;
+
+namespace {
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using MQDesc = MQDescriptorSync<uint8_t>;
+
+const std::vector<uint8_t> goldenDataOutputBuffer{
+        0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+        0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+        0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+        0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+        0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+        0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+        0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+        0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+        0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+        0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+        0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
+        0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
+        0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+        0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
+        0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
+        0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
+        0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
+        0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
+        0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
+        0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
+        0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
+        0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
+        0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
+        0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
+        0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
+        0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
+        0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
+        0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
+        0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
+        0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
+        0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
+        0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
+        0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
+        0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
+        0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
+        0x73, 0x63, 0x65, 0x6e, 0x65,
+};
+
+// const uint16_t FMQ_SIZE_4K = 0x1000;
+const uint32_t FMQ_SIZE_1M = 0x100000;
+const uint32_t FMQ_SIZE_16M = 0x1000000;
+
+struct FilterConf {
+    DemuxFilterType type;
+    DemuxFilterSettings setting;
+};
+
+enum FilterEventType : uint8_t {
+    UNDEFINED,
+    SECTION,
+    MEDIA,
+    PES,
+    RECORD,
+    MMTPRECORD,
+    DOWNLOAD,
+    TEMI,
+};
+
+struct PlaybackConf {
+    string inputDataFile;
+    PlaybackSettings setting;
+};
+
+class FrontendCallback : public IFrontendCallback {
+  public:
+    virtual Return<void> onEvent(FrontendEventType frontendEventType) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mEventReceived = true;
+        mEventType = frontendEventType;
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    virtual Return<void> onScanMessage(FrontendScanMessageType /* type */,
+                                       const FrontendScanMessage& /* message */) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mScanMessageReceived = true;
+        mMsgCondition.signal();
+        return Void();
+    };
+
+    void testOnEvent(sp<IFrontend>& frontend, FrontendSettings settings);
+    void testOnDiseqcMessage(sp<IFrontend>& frontend, FrontendSettings settings);
+
+  private:
+    bool mEventReceived = false;
+    bool mDiseqcMessageReceived = false;
+    bool mScanMessageReceived = false;
+    FrontendEventType mEventType;
+    hidl_vec<uint8_t> mEventMessage;
+    android::Mutex mMsgLock;
+    android::Condition mMsgCondition;
+};
+
+void FrontendCallback::testOnEvent(sp<IFrontend>& frontend, FrontendSettings settings) {
+    Result result = frontend->tune(settings);
+
+    EXPECT_TRUE(result == Result::SUCCESS);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "event not received within timeout";
+            return;
+        }
+    }
+}
+
+void FrontendCallback::testOnDiseqcMessage(sp<IFrontend>& frontend, FrontendSettings settings) {
+    Result result = frontend->tune(settings);
+
+    EXPECT_TRUE(result == Result::SUCCESS);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mDiseqcMessageReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "diseqc message not received within timeout";
+            return;
+        }
+    }
+}
+
+class FilterCallback : public IFilterCallback {
+  public:
+    virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        // Temprarily we treat the first coming back filter data on the matching pid a success
+        // once all of the MQ are cleared, means we got all the expected output
+        mFilterIdToEvent = filterEvent;
+        readFilterEventData();
+        mPidFilterOutputCount++;
+        // mFilterIdToMQ.erase(filterEvent.filterId);
+
+        // startFilterEventThread(filterEvent);
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    virtual Return<void> onFilterStatus(const DemuxFilterStatus /*status*/) override {
+        return Void();
+    }
+
+    void setFilterId(uint32_t filterId) { mFilterId = filterId; }
+    void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
+
+    void testFilterDataOutput();
+
+    void startFilterEventThread(DemuxFilterEvent event);
+    static void* __threadLoopFilter(void* threadArgs);
+    void filterThreadLoop(DemuxFilterEvent& event);
+
+    void updateFilterMQ(MQDesc& filterMQDescriptor);
+    void updateGoldenOutputMap(string goldenOutputFile);
+    bool readFilterEventData();
+
+  private:
+    struct FilterThreadArgs {
+        FilterCallback* user;
+        DemuxFilterEvent event;
+    };
+    uint16_t mDataLength = 0;
+    std::vector<uint8_t> mDataOutputBuffer;
+
+    string mFilterIdToGoldenOutput;
+
+    uint32_t mFilterId;
+    FilterEventType mFilterEventType;
+    std::unique_ptr<FilterMQ> mFilterIdToMQ;
+    EventFlag* mFilterIdToMQEventFlag;
+    DemuxFilterEvent mFilterIdToEvent;
+
+    android::Mutex mMsgLock;
+    android::Mutex mFilterOutputLock;
+    android::Condition mMsgCondition;
+    android::Condition mFilterOutputCondition;
+
+    pthread_t mFilterThread;
+
+    int mPidFilterOutputCount = 0;
+};
+
+void FilterCallback::startFilterEventThread(DemuxFilterEvent event) {
+    struct FilterThreadArgs* threadArgs =
+            (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs));
+    threadArgs->user = this;
+    threadArgs->event = event;
+
+    pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs);
+    pthread_setname_np(mFilterThread, "test_playback_input_loop");
+}
+
+void FilterCallback::testFilterDataOutput() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (mPidFilterOutputCount < 1) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
+            return;
+        }
+    }
+    mPidFilterOutputCount = 0;
+    ALOGW("[vts] pass and stop");
+}
+
+void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) {
+    mFilterIdToMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mFilterIdToMQ);
+    EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ->getEventFlagWord(),
+                                           &mFilterIdToMQEventFlag) == android::OK);
+}
+
+void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) {
+    mFilterIdToGoldenOutput = goldenOutputFile;
+}
+
+void* FilterCallback::__threadLoopFilter(void* threadArgs) {
+    FilterCallback* const self =
+            static_cast<FilterCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
+    self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event);
+    return 0;
+}
+
+void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
+    android::Mutex::Autolock autoLock(mFilterOutputLock);
+    // Read from mFilterIdToMQ[event.filterId] per event and filter type
+
+    // Assemble to filterOutput[filterId]
+
+    // check if filterOutput[filterId] matches goldenOutput[filterId]
+
+    // If match, remove filterId entry from MQ map
+
+    // end thread
+}
+
+bool FilterCallback::readFilterEventData() {
+    bool result = false;
+    DemuxFilterEvent filterEvent = mFilterIdToEvent;
+    ALOGW("[vts] reading from filter FMQ %d", mFilterId);
+    // todo separate filter handlers
+    for (int i = 0; i < filterEvent.events.size(); i++) {
+        switch (mFilterEventType) {
+            case FilterEventType::SECTION:
+                mDataLength = filterEvent.events[i].section().dataLength;
+                break;
+            case FilterEventType::PES:
+                mDataLength = filterEvent.events[i].pes().dataLength;
+                break;
+            case FilterEventType::MEDIA:
+                break;
+            case FilterEventType::RECORD:
+                break;
+            case FilterEventType::MMTPRECORD:
+                break;
+            case FilterEventType::DOWNLOAD:
+                break;
+            default:
+                break;
+        }
+        // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not
+        // match";
+
+        mDataOutputBuffer.resize(mDataLength);
+        result = mFilterIdToMQ->read(mDataOutputBuffer.data(), mDataLength);
+        EXPECT_TRUE(result) << "can't read from Filter MQ";
+
+        /*for (int i = 0; i < mDataLength; i++) {
+            EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
+        }*/
+    }
+    mFilterIdToMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+    return result;
+}
+
+class DvrCallback : public IDvrCallback {
+  public:
+    virtual Return<void> onRecordStatus(RecordStatus /*status*/) override { return Void(); }
+
+    virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
+        // android::Mutex::Autolock autoLock(mMsgLock);
+        ALOGW("[vts] playback status %d", status);
+        switch (status) {
+            case PlaybackStatus::SPACE_EMPTY:
+            case PlaybackStatus::SPACE_ALMOST_EMPTY:
+                ALOGW("[vts] keep playback inputing %d", status);
+                mKeepWritingPlaybackFMQ = true;
+                break;
+            case PlaybackStatus::SPACE_ALMOST_FULL:
+            case PlaybackStatus::SPACE_FULL:
+                ALOGW("[vts] stop playback inputing %d", status);
+                mKeepWritingPlaybackFMQ = false;
+                break;
+        }
+        return Void();
+    }
+
+    void testFilterDataOutput();
+    void stopPlaybackThread();
+
+    void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor);
+    static void* __threadLoopPlayback(void* threadArgs);
+    void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ);
+
+  private:
+    struct PlaybackThreadArgs {
+        DvrCallback* user;
+        PlaybackConf* playbackConf;
+        bool* keepWritingPlaybackFMQ;
+    };
+    uint16_t mDataLength = 0;
+    std::vector<uint8_t> mDataOutputBuffer;
+
+    std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
+    std::unique_ptr<FilterMQ> mPlaybackMQ;
+    std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
+    std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
+    EventFlag* mPlaybackMQEventFlag;
+
+    android::Mutex mMsgLock;
+    android::Mutex mPlaybackThreadLock;
+    android::Condition mMsgCondition;
+
+    bool mKeepWritingPlaybackFMQ = true;
+    bool mPlaybackThreadRunning;
+    pthread_t mPlaybackThread;
+
+    int mPidFilterOutputCount = 0;
+};
+
+void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf,
+                                           MQDesc& playbackMQDescriptor) {
+    mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mPlaybackMQ);
+    struct PlaybackThreadArgs* threadArgs =
+            (struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs));
+    threadArgs->user = this;
+    threadArgs->playbackConf = &playbackConf;
+    threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ;
+
+    pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs);
+    pthread_setname_np(mPlaybackThread, "test_playback_input_loop");
+}
+
+void DvrCallback::stopPlaybackThread() {
+    mPlaybackThreadRunning = false;
+    mKeepWritingPlaybackFMQ = false;
+
+    android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+}
+
+void* DvrCallback::__threadLoopPlayback(void* threadArgs) {
+    DvrCallback* const self =
+            static_cast<DvrCallback*>(((struct PlaybackThreadArgs*)threadArgs)->user);
+    self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf,
+                             ((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ);
+    return 0;
+}
+
+void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) {
+    android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+    mPlaybackThreadRunning = true;
+
+    // Create the EventFlag that is used to signal the HAL impl that data have been
+    // written into the Playback FMQ
+    EventFlag* playbackMQEventFlag;
+    EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) ==
+                android::OK);
+
+    // open the stream and get its length
+    std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary);
+    int writeSize = playbackConf->setting.packetSize * 6;
+    char* buffer = new char[writeSize];
+    ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str());
+    if (!inputData.is_open()) {
+        mPlaybackThreadRunning = false;
+        ALOGW("[vts] Error %s", strerror(errno));
+    }
+
+    while (mPlaybackThreadRunning) {
+        // move the stream pointer for packet size * 6 every read until the end
+        while (*keepWritingPlaybackFMQ) {
+            inputData.read(buffer, writeSize);
+            if (!inputData) {
+                int leftSize = inputData.gcount();
+                if (leftSize == 0) {
+                    mPlaybackThreadRunning = false;
+                    break;
+                }
+                inputData.clear();
+                inputData.read(buffer, leftSize);
+                // Write the left over of the input data and quit the thread
+                if (leftSize > 0) {
+                    EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize));
+                    playbackMQEventFlag->wake(
+                            static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+                }
+                mPlaybackThreadRunning = false;
+                break;
+            }
+            // Write input FMQ and notify the Tuner Implementation
+            EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize));
+            playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+            inputData.seekg(writeSize, inputData.cur);
+            sleep(1);
+        }
+    }
+
+    ALOGW("[vts] Playback thread end.");
+
+    delete[] buffer;
+    inputData.close();
+}
+
+// Test environment for Tuner HIDL HAL.
+class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    // get the test environment singleton
+    static TunerHidlEnvironment* Instance() {
+        static TunerHidlEnvironment* instance = new TunerHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<ITuner>(); }
+};
+
+class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+  public:
+    virtual void SetUp() override {
+        mService = ::testing::VtsHalHidlTargetTestBase::getService<ITuner>(
+                TunerHidlEnvironment::Instance()->getServiceName<ITuner>());
+        ASSERT_NE(mService, nullptr);
+    }
+
+    sp<ITuner> mService;
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<IFrontend> mFrontend;
+    sp<FrontendCallback> mFrontendCallback;
+    sp<IDescrambler> mDescrambler;
+    sp<IDemux> mDemux;
+    sp<IDvr> mDvr;
+    sp<IFilter> mFilter;
+    std::map<uint32_t, sp<IFilter>> mFilters;
+    std::map<uint32_t, sp<FilterCallback>> mFilterCallbacks;
+    sp<FilterCallback> mFilterCallback;
+    sp<DvrCallback> mDvrCallback;
+    MQDesc mFilterMQDescriptor;
+    MQDesc mPlaybackMQDescriptor;
+    vector<uint32_t> mUsedFilterIds;
+
+    uint32_t mDemuxId;
+    uint32_t mFilterId;
+
+    pthread_t mPlaybackshread;
+    bool mPlaybackThreadRunning;
+
+    ::testing::AssertionResult createFrontend(int32_t frontendId);
+    ::testing::AssertionResult tuneFrontend(int32_t frontendId);
+    ::testing::AssertionResult stopTuneFrontend(int32_t frontendId);
+    ::testing::AssertionResult closeFrontend(int32_t frontendId);
+    ::testing::AssertionResult createDemux();
+    ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId,
+                                                       FrontendSettings settings);
+    ::testing::AssertionResult getPlaybackMQDescriptor();
+    ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting);
+    ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting);
+    ::testing::AssertionResult getFilterMQDescriptor();
+    ::testing::AssertionResult closeDemux();
+    ::testing::AssertionResult createDescrambler();
+    ::testing::AssertionResult closeDescrambler();
+
+    ::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
+                                                    PlaybackConf playbackConf,
+                                                    vector<string> goldenOutputFiles);
+    ::testing::AssertionResult broadcastDataFlowTest(vector<FilterConf> filterConf,
+                                                     vector<string> goldenOutputFiles);
+};
+
+::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) {
+    Result status;
+
+    mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) {
+        mFrontend = frontend;
+        status = result;
+    });
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    mFrontendCallback = new FrontendCallback();
+    auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
+
+    return ::testing::AssertionResult(callbackStatus.isOk());
+}
+
+::testing::AssertionResult TunerHidlTest::tuneFrontend(int32_t frontendId) {
+    if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Frontend Settings for testing
+    FrontendSettings frontendSettings;
+    FrontendAtscSettings frontendAtscSettings{
+            .frequency = 0,
+            .modulation = FrontendAtscModulation::UNDEFINED,
+    };
+    frontendSettings.atsc(frontendAtscSettings);
+    mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
+
+    FrontendDvbtSettings frontendDvbtSettings{
+            .frequency = 0,
+    };
+    frontendSettings.dvbt(frontendDvbtSettings);
+    mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
+
+    return ::testing::AssertionResult(true);
+}
+
+::testing::AssertionResult TunerHidlTest::stopTuneFrontend(int32_t frontendId) {
+    Result status;
+    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mFrontend->stopTune();
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::closeFrontend(int32_t frontendId) {
+    Result status;
+    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mFrontend->close();
+    mFrontend = nullptr;
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::createDemux() {
+    Result status;
+
+    mService->openDemux([&](Result result, uint32_t demuxId, const sp<IDemux>& demux) {
+        mDemux = demux;
+        mDemuxId = demuxId;
+        status = result;
+    });
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId,
+                                                                  FrontendSettings settings) {
+    Result status;
+
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    mFrontendCallback->testOnEvent(mFrontend, settings);
+
+    status = mDemux->setFrontendDataSource(frontendId);
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::closeDemux() {
+    Result status;
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mDemux->close();
+    mDemux = nullptr;
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::createDescrambler() {
+    Result status;
+
+    mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
+        mDescrambler = descrambler;
+        status = result;
+    });
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mDescrambler->setDemuxSource(mDemuxId);
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Test if demux source can be set more than once.
+    status = mDescrambler->setDemuxSource(mDemuxId);
+    return ::testing::AssertionResult(status == Result::INVALID_STATE);
+}
+
+::testing::AssertionResult TunerHidlTest::closeDescrambler() {
+    Result status;
+    if (!mDescrambler && createDescrambler() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mDescrambler->close();
+    mDescrambler = nullptr;
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::addPlaybackToDemux(PlaybackSettings setting) {
+    Result status;
+
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Create dvr callback
+    mDvrCallback = new DvrCallback();
+
+    // Add playback input to the local demux
+    mDemux->openDvr(DvrType::PLAYBACK, FMQ_SIZE_1M, mDvrCallback,
+                    [&](Result result, const sp<IDvr>& dvr) {
+                        mDvr = dvr;
+                        status = result;
+                    });
+
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    DvrSettings dvrSetting;
+    dvrSetting.playback(setting);
+    status = mDvr->configure(dvrSetting);
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::getPlaybackMQDescriptor() {
+    Result status;
+
+    if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) {
+        return ::testing::AssertionFailure();
+    }
+
+    mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+        mPlaybackMQDescriptor = dvrMQDesc;
+        status = result;
+    });
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type,
+                                                           DemuxFilterSettings setting) {
+    Result status;
+
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Create demux callback
+    mFilterCallback = new FilterCallback();
+
+    // Add filter to the local demux
+    mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback,
+                       [&](Result result, const sp<IFilter>& filter) {
+                           mFilter = filter;
+                           status = result;
+                       });
+
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    mFilter->getId([&](Result result, uint32_t filterId) {
+        mFilterId = filterId;
+        status = result;
+    });
+
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    mFilterCallback->setFilterId(mFilterId);
+
+    FilterEventType eventType = FilterEventType::UNDEFINED;
+    switch (type.mainType) {
+        case DemuxFilterMainType::TS:
+            switch (type.subType.tsFilterType()) {
+                case DemuxTsFilterType::UNDEFINED:
+                    break;
+                case DemuxTsFilterType::SECTION:
+                    eventType = FilterEventType::SECTION;
+                    break;
+                case DemuxTsFilterType::PES:
+                    eventType = FilterEventType::PES;
+                    break;
+                case DemuxTsFilterType::TS:
+                    break;
+                case DemuxTsFilterType::AUDIO:
+                case DemuxTsFilterType::VIDEO:
+                    eventType = FilterEventType::MEDIA;
+                    break;
+                case DemuxTsFilterType::PCR:
+                    break;
+                case DemuxTsFilterType::RECORD:
+                    eventType = FilterEventType::RECORD;
+                    break;
+                case DemuxTsFilterType::TEMI:
+                    eventType = FilterEventType::TEMI;
+                    break;
+            }
+            break;
+        case DemuxFilterMainType::MMTP:
+            /*mmtpSettings*/
+            break;
+        case DemuxFilterMainType::IP:
+            /*ipSettings*/
+            break;
+        case DemuxFilterMainType::TLV:
+            /*tlvSettings*/
+            break;
+        case DemuxFilterMainType::ALP:
+            /*alpSettings*/
+            break;
+        default:
+            break;
+    }
+    mFilterCallback->setFilterEventType(eventType);
+
+    // Configure the filter
+    status = mFilter->configure(setting);
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor() {
+    Result status;
+
+    if (!mDemux || !mFilter) {
+        return ::testing::AssertionFailure();
+    }
+
+    mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) {
+        mFilterMQDescriptor = filterMQDesc;
+        status = result;
+    });
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(
+        vector<FilterConf> filterConf, PlaybackConf playbackConf,
+        vector<string> /*goldenOutputFiles*/) {
+    Result status;
+    int filterIdsSize;
+    // Filter Configuration Module
+    for (int i = 0; i < filterConf.size(); i++) {
+        if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
+                    ::testing::AssertionFailure() ||
+            // TODO use a map to save the FMQs/EvenFlags and pass to callback
+            getFilterMQDescriptor() == ::testing::AssertionFailure()) {
+            return ::testing::AssertionFailure();
+        }
+        filterIdsSize = mUsedFilterIds.size();
+        mUsedFilterIds.resize(filterIdsSize + 1);
+        mUsedFilterIds[filterIdsSize] = mFilterId;
+        mFilters[mFilterId] = mFilter;
+        mFilterCallbacks[mFilterId] = mFilterCallback;
+        mFilterCallback->updateFilterMQ(mFilterMQDescriptor);
+        // mDemuxCallback->updateGoldenOutputMap(goldenOutputFiles[i]);
+        status = mFilter->start();
+        if (status != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+
+    // Playback Input Module
+    PlaybackSettings playbackSetting = playbackConf.setting;
+    if (addPlaybackToDemux(playbackSetting) == ::testing::AssertionFailure() ||
+        getPlaybackMQDescriptor() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+    mDvrCallback->startPlaybackInputThread(playbackConf, mPlaybackMQDescriptor);
+    status = mDvr->start();
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Data Verify Module
+    std::map<uint32_t, sp<FilterCallback>>::iterator it;
+    for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) {
+        it->second->testFilterDataOutput();
+    }
+    mDvrCallback->stopPlaybackThread();
+
+    // Clean Up Module
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+    if (mDvr->stop() != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+    mUsedFilterIds.clear();
+    mFilterCallbacks.clear();
+    mFilters.clear();
+    return closeDemux();
+}
+
+::testing::AssertionResult TunerHidlTest::broadcastDataFlowTest(
+        vector<FilterConf> filterConf, vector<string> /*goldenOutputFiles*/) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return ::testing::AssertionFailure();
+    }
+
+    FrontendDvbtSettings dvbt{
+            .frequency = 1000,
+    };
+    FrontendSettings settings;
+    settings.dvbt(dvbt);
+
+    if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) {
+        return ::testing::AssertionFailure();
+    }
+
+    int filterIdsSize;
+    // Filter Configuration Module
+    for (int i = 0; i < filterConf.size(); i++) {
+        if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
+                    ::testing::AssertionFailure() ||
+            // TODO use a map to save the FMQs/EvenFlags and pass to callback
+            getFilterMQDescriptor() == ::testing::AssertionFailure()) {
+            return ::testing::AssertionFailure();
+        }
+        filterIdsSize = mUsedFilterIds.size();
+        mUsedFilterIds.resize(filterIdsSize + 1);
+        mUsedFilterIds[filterIdsSize] = mFilterId;
+        mFilters[mFilterId] = mFilter;
+        mFilterCallbacks[mFilterId] = mFilterCallback;
+        mFilterCallback->updateFilterMQ(mFilterMQDescriptor);
+        status = mFilter->start();
+        if (status != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+
+    // Data Verify Module
+    std::map<uint32_t, sp<FilterCallback>>::iterator it;
+    for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) {
+        it->second->testFilterDataOutput();
+    }
+
+    // Clean Up Module
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+    if (mFrontend->stopTune() != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+    mUsedFilterIds.clear();
+    mFilterCallbacks.clear();
+    mFilters.clear();
+    return closeDemux();
+}
+
+/*
+ * API STATUS TESTS
+ */
+TEST_F(TunerHidlTest, CreateFrontend) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    description("Create Frontends");
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return;
+    }
+
+    for (size_t i = 0; i < feIds.size(); i++) {
+        ASSERT_TRUE(createFrontend(feIds[i]));
+    }
+}
+
+TEST_F(TunerHidlTest, TuneFrontend) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    description("Tune Frontends and check callback onEvent");
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return;
+    }
+
+    for (size_t i = 0; i < feIds.size(); i++) {
+        ASSERT_TRUE(tuneFrontend(feIds[i]));
+    }
+}
+
+TEST_F(TunerHidlTest, StopTuneFrontend) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    description("stopTune Frontends");
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return;
+    }
+
+    for (size_t i = 0; i < feIds.size(); i++) {
+        ASSERT_TRUE(stopTuneFrontend(feIds[i]));
+    }
+}
+
+TEST_F(TunerHidlTest, CloseFrontend) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    description("Close Frontends");
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return;
+    }
+
+    for (size_t i = 0; i < feIds.size(); i++) {
+        ASSERT_TRUE(closeFrontend(feIds[i]));
+    }
+}
+
+/*TEST_F(TunerHidlTest, CreateDemuxWithFrontend) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    description("Create Demux with Frontend");
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return;
+    }
+
+    FrontendDvbtSettings dvbt{
+        .frequency = 1000,
+    };
+    FrontendSettings settings;
+    settings.dvbt(dvbt);
+
+    for (size_t i = 0; i < feIds.size(); i++) {
+        ASSERT_TRUE(createDemuxWithFrontend(feIds[i], settings));
+        mFrontend->stopTune();
+    }
+}*/
+
+TEST_F(TunerHidlTest, CreateDemux) {
+    description("Create Demux");
+    ASSERT_TRUE(createDemux());
+}
+
+TEST_F(TunerHidlTest, CloseDemux) {
+    description("Close Demux");
+    ASSERT_TRUE(closeDemux());
+}
+
+TEST_F(TunerHidlTest, CreateDescrambler) {
+    description("Create Descrambler");
+    ASSERT_TRUE(createDescrambler());
+}
+
+TEST_F(TunerHidlTest, CloseDescrambler) {
+    description("Close Descrambler");
+    ASSERT_TRUE(closeDescrambler());
+}
+
+/*
+ * DATA FLOW TESTS
+ */
+TEST_F(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) {
+    description("Feed ts data from playback and configure pes filter to get output");
+
+    // todo modulize the filter conf parser
+    vector<FilterConf> filterConf;
+    filterConf.resize(1);
+
+    DemuxFilterSettings filterSetting;
+    DemuxTsFilterSettings tsFilterSetting{
+            .tpid = 18,
+    };
+    DemuxFilterSectionSettings sectionFilterSetting;
+    tsFilterSetting.filterSettings.section(sectionFilterSetting);
+    filterSetting.ts(tsFilterSetting);
+
+    DemuxFilterType type{
+            .mainType = DemuxFilterMainType::TS,
+    };
+    type.subType.tsFilterType(DemuxTsFilterType::SECTION);
+    FilterConf sectionFilterConf{
+            .type = type,
+            .setting = filterSetting,
+    };
+    filterConf[0] = sectionFilterConf;
+
+    PlaybackSettings playbackSetting{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x07fff,
+            .dataFormat = DataFormat::TS,
+            .packetSize = 188,
+    };
+
+    PlaybackConf playbackConf{
+            .inputDataFile = "/vendor/etc/test1.ts",
+            .setting = playbackSetting,
+    };
+
+    vector<string> goldenOutputFiles;
+
+    ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles));
+}
+
+TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) {
+    description("Feed ts data from frontend and test with PES filter");
+
+    // todo modulize the filter conf parser
+    vector<FilterConf> filterConf;
+    filterConf.resize(1);
+
+    DemuxFilterSettings filterSetting;
+    DemuxTsFilterSettings tsFilterSetting{
+            .tpid = 119,
+    };
+    DemuxFilterPesDataSettings pesFilterSetting;
+    tsFilterSetting.filterSettings.pesData(pesFilterSetting);
+    filterSetting.ts(tsFilterSetting);
+
+    DemuxFilterType type{
+            .mainType = DemuxFilterMainType::TS,
+    };
+    type.subType.tsFilterType(DemuxTsFilterType::PES);
+    FilterConf pesFilterConf{
+            .type = type,
+            .setting = filterSetting,
+    };
+    filterConf[0] = pesFilterConf;
+
+    vector<string> goldenOutputFiles;
+
+    ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles));
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(TunerHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    TunerHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/usb/1.0/Android.bp b/usb/1.0/Android.bp
index a00b671..c0e883f 100644
--- a/usb/1.0/Android.bp
+++ b/usb/1.0/Android.bp
@@ -17,4 +17,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/usb/1.0/default/Android.bp b/usb/1.0/default/Android.bp
index 64de821..96d24c1 100644
--- a/usb/1.0/default/Android.bp
+++ b/usb/1.0/default/Android.bp
@@ -26,7 +26,6 @@
     shared_libs: [
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "libhardware",
diff --git a/usb/1.0/default/android.hardware.usb@1.0-service.rc b/usb/1.0/default/android.hardware.usb@1.0-service.rc
index b7a0c63..3c44d21 100644
--- a/usb/1.0/default/android.hardware.usb@1.0-service.rc
+++ b/usb/1.0/default/android.hardware.usb@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.usb-hal-1-0 /vendor/bin/hw/android.hardware.usb@1.0-service
+    interface android.hardware.usb@1.0::IUsb default
     class hal
     user system
     group system
diff --git a/usb/1.0/vts/functional/Android.bp b/usb/1.0/vts/functional/Android.bp
index 683ee17..1a3b56b 100644
--- a/usb/1.0/vts/functional/Android.bp
+++ b/usb/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalUsbV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.usb@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/usb/1.0/vts/functional/VtsHalUsbV1_0TargetTest.cpp b/usb/1.0/vts/functional/VtsHalUsbV1_0TargetTest.cpp
index ee7ef1b..bba75c8 100644
--- a/usb/1.0/vts/functional/VtsHalUsbV1_0TargetTest.cpp
+++ b/usb/1.0/vts/functional/VtsHalUsbV1_0TargetTest.cpp
@@ -20,9 +20,10 @@
 #include <android/hardware/usb/1.0/IUsb.h>
 #include <android/hardware/usb/1.0/IUsbCallback.h>
 #include <android/hardware/usb/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <log/log.h>
 #include <stdlib.h>
 #include <chrono>
@@ -49,20 +50,8 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
-// Test environment for Usb HIDL HAL.
-class UsbHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static UsbHidlEnvironment* Instance() {
-    static UsbHidlEnvironment* instance = new UsbHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<IUsb>(); }
-};
-
 // The main test class for the USB hidl HAL
-class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class UsbHidlTest : public testing::TestWithParam<std::string> {
  public:
   // Callback class for the USB HIDL hal.
   // Usb Hal will call this object upon role switch or port query.
@@ -109,8 +98,7 @@
 
   virtual void SetUp() override {
     ALOGI("Setup");
-    usb = ::testing::VtsHalHidlTargetTestBase::getService<IUsb>(
-        UsbHidlEnvironment::Instance()->getServiceName<IUsb>());
+    usb = IUsb::getService(GetParam());
     ASSERT_NE(usb, nullptr);
 
     usb_cb_2 = new UsbCallback(*this, 2);
@@ -182,7 +170,7 @@
  * Callback oject is created and registered.
  * Check to see if the hidl transaction succeeded.
  */
-TEST_F(UsbHidlTest, setCallback) {
+TEST_P(UsbHidlTest, setCallback) {
   usb_cb_1 = new UsbCallback(*this, 1);
   ASSERT_NE(usb_cb_1, nullptr);
   Return<void> ret = usb->setCallback(usb_cb_1);
@@ -193,7 +181,7 @@
  * Check to see if querying type-c
  * port status succeeds.
  */
-TEST_F(UsbHidlTest, queryPortStatus) {
+TEST_P(UsbHidlTest, queryPortStatus) {
   Return<void> ret = usb->queryPortStatus();
   ASSERT_TRUE(ret.isOk());
   EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -206,7 +194,7 @@
  * This test case tried to switch the port with empty
  * name which is expected to fail.
  */
-TEST_F(UsbHidlTest, switchEmptyPort) {
+TEST_P(UsbHidlTest, switchEmptyPort) {
   struct PortRole role;
   role.type = PortRoleType::DATA_ROLE;
 
@@ -218,52 +206,6 @@
 }
 
 /*
- * Test switching the mode of usb port.
- * Test case queries the usb ports present in device.
- * If there is atleast one usb port, a mode switch
- * to DFP is attempted for the port.
- * The callback parametes are checked to see if the mode
- * switch was successfull. Upon success, Status::SUCCESS
- * is expected to be returned.
- */
-TEST_F(UsbHidlTest, switchModetoDFP) {
-  struct PortRole role;
-  role.type = PortRoleType::MODE;
-  role.role = static_cast<uint32_t>(PortMode::DFP);
-
-  Return<void> ret = usb->queryPortStatus();
-  ASSERT_TRUE(ret.isOk());
-  EXPECT_EQ(std::cv_status::no_timeout, wait());
-  EXPECT_EQ(2, usb_last_cookie);
-
-  if (!usb_last_port_status.portName.empty()) {
-    hidl_string portBeingSwitched = usb_last_port_status.portName;
-    ALOGI("mode portname:%s", portBeingSwitched.c_str());
-    usb_role_switch_done = false;
-    Return<void> ret = usb->switchRole(portBeingSwitched.c_str(), role);
-    ASSERT_TRUE(ret.isOk());
-
-    std::cv_status waitStatus = wait();
-    while (waitStatus == std::cv_status::no_timeout &&
-           usb_role_switch_done == false)
-      waitStatus = wait();
-
-    EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
-    EXPECT_EQ(2, usb_last_cookie);
-
-    EXPECT_EQ(static_cast<uint32_t>(PortRoleType::MODE),
-              static_cast<uint32_t>(usb_last_port_role.type));
-    if (usb_last_status == Status::SUCCESS) {
-      EXPECT_EQ(static_cast<uint32_t>(PortMode::DFP),
-                static_cast<uint32_t>(usb_last_port_role.role));
-    } else {
-      EXPECT_NE(static_cast<uint32_t>(PortMode::UFP),
-                static_cast<uint32_t>(usb_last_port_role.role));
-    }
-  }
-}
-
-/*
  * Test switching the power role of usb port.
  * Test case queries the usb ports present in device.
  * If there is atleast one usb port, a power role switch
@@ -273,7 +215,7 @@
  * is expected to be returned.
  */
 
-TEST_F(UsbHidlTest, switchPowerRole) {
+TEST_P(UsbHidlTest, switchPowerRole) {
   struct PortRole role;
   role.type = PortRoleType::POWER_ROLE;
   role.role = static_cast<uint32_t>(PortPowerRole::SOURCE);
@@ -319,7 +261,7 @@
  * switch was successfull. Upon success, Status::SUCCESS
  * is expected to be returned.
  */
-TEST_F(UsbHidlTest, switchDataRole) {
+TEST_P(UsbHidlTest, switchDataRole) {
   struct PortRole role;
   role.type = PortRoleType::DATA_ROLE;
   role.role = static_cast<uint32_t>(PortDataRole::HOST);
@@ -356,11 +298,7 @@
   }
 }
 
-int main(int argc, char** argv) {
-  ::testing::AddGlobalTestEnvironment(UsbHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  UsbHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, UsbHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IUsb::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/usb/1.1/Android.bp b/usb/1.1/Android.bp
index fb2cc4e..6f2abae 100644
--- a/usb/1.1/Android.bp
+++ b/usb/1.1/Android.bp
@@ -18,4 +18,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/usb/1.2/Android.bp b/usb/1.2/Android.bp
index 5206754..b3ba81f 100644
--- a/usb/1.2/Android.bp
+++ b/usb/1.2/Android.bp
@@ -19,4 +19,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/usb/gadget/1.0/Android.bp b/usb/gadget/1.0/Android.bp
index 7ee432b..4921abf 100644
--- a/usb/gadget/1.0/Android.bp
+++ b/usb/gadget/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/vibrator/1.0/Android.bp b/vibrator/1.0/Android.bp
index acc97d4..792e130 100644
--- a/vibrator/1.0/Android.bp
+++ b/vibrator/1.0/Android.bp
@@ -16,4 +16,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/vibrator/1.0/default/Android.bp b/vibrator/1.0/default/Android.bp
index 0c7d155..b0d0986 100644
--- a/vibrator/1.0/default/Android.bp
+++ b/vibrator/1.0/default/Android.bp
@@ -21,7 +21,6 @@
     srcs: ["Vibrator.cpp"],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "libhardware",
@@ -39,7 +38,6 @@
 
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "libhardware",
diff --git a/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc b/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
index 1123eab..1bd5c10 100644
--- a/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
+++ b/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.vibrator-1-0 /vendor/bin/hw/android.hardware.vibrator@1.0-service
+    interface android.hardware.vibrator@1.0::IVibrator default
     class hal
     user system
     group system
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/Android.bp b/vibrator/1.1/Android.bp
index 2055e5a..0d04a87 100644
--- a/vibrator/1.1/Android.bp
+++ b/vibrator/1.1/Android.bp
@@ -17,4 +17,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
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/Android.bp b/vibrator/1.2/Android.bp
index 481adee..290a0cf 100644
--- a/vibrator/1.2/Android.bp
+++ b/vibrator/1.2/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
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/Android.bp b/vibrator/1.3/Android.bp
index a2ff784..357ea9a 100644
--- a/vibrator/1.3/Android.bp
+++ b/vibrator/1.3/Android.bp
@@ -7,8 +7,8 @@
         enabled: true,
     },
     srcs: [
-        "IVibrator.hal",
         "types.hal",
+        "IVibrator.hal",
     ],
     interfaces: [
         "android.hardware.vibrator@1.0",
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/vibrator/1.3/example/Android.bp b/vibrator/1.3/example/Android.bp
index 36f2ff8..07f1c26 100644
--- a/vibrator/1.3/example/Android.bp
+++ b/vibrator/1.3/example/Android.bp
@@ -23,7 +23,6 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.vibrator@1.0",
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/aidl/Android.bp b/vibrator/aidl/Android.bp
new file mode 100644
index 0000000..1eec1da
--- /dev/null
+++ b/vibrator/aidl/Android.bp
@@ -0,0 +1,18 @@
+aidl_interface {
+    name: "vintf-vibrator",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/vibrator/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+}
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
similarity index 66%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
index 8bb72a1..84556b5 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
+package android.hardware.vibrator;
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
+import android.hardware.vibrator.CompositePrimitive;
 
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
-
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+@VintfStability
+parcelable CompositeEffect {
+    /* Period of silence preceding primitive. */
+    int delayMs;
+    CompositePrimitive primitive;
+    /* 0.0 (exclusive) - 1.0 (inclusive) */
+    float scale;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
new file mode 100644
index 0000000..b9a80ec
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.vibrator;
+
+@VintfStability
+@Backing(type="int")
+enum CompositePrimitive {
+    /**
+     * No haptic effect. Used to generate extended delays between primitives.
+     */
+    NOOP,
+    /**
+     * This effect should produce a sharp, crisp click sensation.
+     */
+    CLICK,
+    /**
+     * A haptic effect that simulates downwards movement with gravity. Often
+     * followed by extra energy of hitting and reverberation to augment
+     * physicality.
+     */
+    THUD,
+    /**
+     * A haptic effect that simulates spinning momentum.
+     */
+    SPIN,
+    /**
+     * A haptic effect that simulates quick upward movement against gravity.
+     */
+    QUICK_RISE,
+    /**
+     * A haptic effect that simulates slow upward movement against gravity.
+     */
+    SLOW_RISE,
+    /**
+     * A haptic effect that simulates quick downwards movement with gravity.
+     */
+    QUICK_FALL,
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/Effect.aidl b/vibrator/aidl/android/hardware/vibrator/Effect.aidl
new file mode 100644
index 0000000..c60bfe9
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/Effect.aidl
@@ -0,0 +1,86 @@
+/*
+ * 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.vibrator;
+
+@VintfStability
+@Backing(type="int")
+enum Effect {
+    /**
+     * A single click effect.
+     *
+     * This effect should produce a sharp, crisp click sensation.
+     */
+    CLICK,
+    /**
+     * A double click effect.
+     *
+     * This effect should produce two sequential sharp, crisp click sensations with a minimal
+     * amount of time between them.
+     */
+    DOUBLE_CLICK,
+    /**
+     * A tick effect.
+     *
+     * This effect should produce a soft, short sensation, like the tick of a clock.
+     */
+    TICK,
+    /**
+     * A thud effect.
+     *
+     * This effect should solid feeling bump, like the depression of a heavy mechanical button.
+     */
+    THUD,
+    /**
+     * A pop effect.
+     *
+     * A short, quick burst effect.
+     */
+    POP,
+    /**
+     * A heavy click effect.
+     *
+     * This should produce a sharp striking sensation, like a click but stronger.
+     */
+    HEAVY_CLICK,
+    /**
+     * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a
+     * pattern that can be played as a ringtone with any audio, depending on the device.
+     */
+    RINGTONE_1,
+    RINGTONE_2,
+    RINGTONE_3,
+    RINGTONE_4,
+    RINGTONE_5,
+    RINGTONE_6,
+    RINGTONE_7,
+    RINGTONE_8,
+    RINGTONE_9,
+    RINGTONE_10,
+    RINGTONE_11,
+    RINGTONE_12,
+    RINGTONE_13,
+    RINGTONE_14,
+    RINGTONE_15,
+    /**
+     * A soft tick effect meant to be played as a texture.
+     *
+     * A soft, short sensation like the tick of a clock. Unlike regular effects, texture effects
+     * are expected to be played multiple times in quick succession, replicating a specific
+     * texture to the user as a form of haptic feedback.
+     */
+    TEXTURE_TICK,
+}
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl
similarity index 66%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl
index 8bb72a1..66f70e5 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
+package android.hardware.vibrator;
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
-
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
-
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+@VintfStability
+@Backing(type="byte")
+enum EffectStrength {
+    LIGHT,
+    MEDIUM,
+    STRONG,
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
new file mode 100644
index 0000000..ebf5faa
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -0,0 +1,168 @@
+/*
+ * 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.vibrator;
+
+import android.hardware.vibrator.IVibratorCallback;
+import android.hardware.vibrator.Effect;
+import android.hardware.vibrator.EffectStrength;
+import android.hardware.vibrator.CompositeEffect;
+import android.hardware.vibrator.CompositePrimitive;
+
+@VintfStability
+interface IVibrator {
+    /**
+     * Whether on w/ IVibratorCallback can be used w/ 'on' function
+     */
+    const int CAP_ON_CALLBACK = 1 << 0;
+    /**
+     * Whether on w/ IVibratorCallback can be used w/ 'perform' function
+     */
+    const int CAP_PERFORM_CALLBACK = 1 << 1;
+    /**
+     * Whether setAmplitude is supported (when external control is disabled)
+     */
+    const int CAP_AMPLITUDE_CONTROL = 1 << 2;
+    /**
+     * Whether setExternalControl is supported.
+     */
+    const int CAP_EXTERNAL_CONTROL = 1 << 3;
+    /**
+     * Whether setAmplitude is supported (when external control is enabled)
+     */
+    const int CAP_EXTERNAL_AMPLITUDE_CONTROL = 1 << 4;
+    /**
+     * Whether compose is supported.
+     */
+    const int CAP_COMPOSE_EFFECTS = 1 << 5;
+
+    /**
+     * Determine capabilities of the vibrator HAL (CAP_* mask)
+     */
+    int getCapabilities();
+
+    /**
+     * Turn off vibrator
+     *
+     * Cancel a previously-started vibration, if any. If a previously-started vibration is
+     * associated with a callback, then onComplete should still be called on that callback.
+     */
+    void off();
+
+    /**
+     * Turn on vibrator
+     *
+     * This function must only be called after the previous timeout has expired or
+     * was canceled (through off()). A callback is only expected to be supported when
+     * getCapabilities CAP_ON_CALLBACK is specified.
+     *
+     * Doing this operation while the vibrator is already on is undefined behavior. Clients should
+     * explicitly call off.
+     *
+     * @param timeoutMs number of milliseconds to vibrate.
+     * @param callback A callback used to inform Frameworks of state change, if supported.
+     */
+    void on(in int timeoutMs, in IVibratorCallback callback);
+
+    /**
+     * Fire off a predefined haptic event.
+     *
+     * A callback is only expected to be supported when getCapabilities CAP_PERFORM_CALLBACK
+     * is specified.
+     *
+     * Doing this operation while the vibrator is already on is undefined behavior. Clients should
+     * explicitly call off.
+     *
+     * @param effect The type of haptic event to trigger.
+     * @param strength The intensity of haptic event to trigger.
+     * @param callback A callback used to inform Frameworks of state change, if supported.
+     * @return The length of time the event is expected to take in
+     *     milliseconds. This doesn't need to be perfectly accurate, but should be a reasonable
+     *     approximation.
+     */
+    int perform(in Effect effect, in EffectStrength strength, in IVibratorCallback callback);
+
+    /**
+     * List supported effects.
+     *
+     * Return the effects which are supported (an effect is expected to be supported at every
+     * strength level.
+     */
+    Effect[] getSupportedEffects();
+
+    /**
+     * Sets the motor's vibrational amplitude.
+     *
+     * Changes the force being produced by the underlying motor. This may not be supported and
+     * this support is reflected in getCapabilities (CAP_AMPLITUDE_CONTROL). When this device
+     * is under external control (via setExternalControl), amplitude control may not be supported
+     * even though it is supported normally. This can be checked with
+     * CAP_EXTERNAL_AMPLITUDE_CONTROL.
+     *
+     * @param amplitude The unitless force setting. Note that this number must
+     *                  be between 0.0 (exclusive) and 1.0 (inclusive). It must
+     *                  do it's best to map it onto the number of steps it does have.
+     */
+    void setAmplitude(in float amplitude);
+
+    /**
+     * Enables/disables control override of vibrator to audio.
+     *
+     * Support is reflected in getCapabilities (CAP_EXTERNAL_CONTROL).
+     *
+     * When this API is set, the vibrator control should be ceded to audio system
+     * for haptic audio. While this is enabled, issuing of other commands to control
+     * the vibrator is unsupported and the resulting behavior is undefined. Amplitude
+     * control may or may not be supported and is reflected in the return value of
+     * getCapabilities (CAP_EXTERNAL_AMPLITUDE_CONTROL) while this is enabled. When this is
+     * disabled, the vibrator should resume to an off state.
+     *
+     * @param enabled Whether external control should be enabled or disabled.
+     */
+    void setExternalControl(in boolean enabled);
+
+    /**
+     * Retrieve composition delay limit.
+     *
+     * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
+     *
+     * @return Maximum delay for a single CompositeEffect[] entry.
+     */
+    int getCompositionDelayMax();
+
+    /**
+     * Retrieve composition size limit.
+     *
+     * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
+     *
+     * @return Maximum number of entries in CompositeEffect[].
+     * @param maxDelayMs Maximum delay for a single CompositeEffect[] entry.
+     */
+    int getCompositionSizeMax();
+
+    /**
+     * Fire off a string of effect primitives, combined to perform richer effects.
+     *
+     * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
+     *
+     * Doing this operation while the vibrator is already on is undefined behavior. Clients should
+     * explicitly call off.
+     *
+     * @param composite Array of composition parameters.
+     */
+    void compose(in CompositeEffect[] composite, in IVibratorCallback callback);
+
+}
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp b/vibrator/aidl/android/hardware/vibrator/IVibratorCallback.aidl
similarity index 66%
copy from wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
copy to vibrator/aidl/android/hardware/vibrator/IVibratorCallback.aidl
index 8bb72a1..43859de 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp
+++ b/vibrator/aidl/android/hardware/vibrator/IVibratorCallback.aidl
@@ -14,13 +14,9 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <android-base/logging.h>
+package android.hardware.vibrator;
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
-
-using ::android::sp;
-using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
-
-sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); }
+@VintfStability
+interface IVibratorCallback {
+    oneway void onComplete();
+}
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
new file mode 100644
index 0000000..dc8867f
--- /dev/null
+++ b/vibrator/aidl/default/Android.bp
@@ -0,0 +1,32 @@
+cc_library_static {
+    name: "libvibratorexampleimpl",
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "vintf-vibrator-ndk_platform",
+    ],
+    export_include_dirs: ["include"],
+    srcs: ["Vibrator.cpp"],
+    visibility: [
+         ":__subpackages__",
+         "//hardware/interfaces/tests/extension/vibrator:__subpackages__",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.vibrator-service.example",
+    relative_install_path: "hw",
+    init_rc: ["vibrator-default.rc"],
+    vintf_fragments: ["vibrator-default.xml"],
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "vintf-vibrator-ndk_platform",
+    ],
+    static_libs: [
+        "libvibratorexampleimpl",
+    ],
+    srcs: ["main.cpp"],
+}
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
new file mode 100644
index 0000000..befdeab
--- /dev/null
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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 "vibrator-impl/Vibrator.h"
+
+#include <android-base/logging.h>
+#include <thread>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+static constexpr int32_t kComposeDelayMaxMs = 1000;
+static constexpr int32_t kComposeSizeMax = 256;
+
+ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
+    LOG(INFO) << "Vibrator reporting capabilities";
+    *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
+                    IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
+                    IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::off() {
+    LOG(INFO) << "Vibrator off";
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
+                                const std::shared_ptr<IVibratorCallback>& callback) {
+    LOG(INFO) << "Vibrator on for timeoutMs: " << timeoutMs;
+    if (callback != nullptr) {
+        std::thread([=] {
+            LOG(INFO) << "Starting on on another thread";
+            usleep(timeoutMs * 1000);
+            LOG(INFO) << "Notifying on complete";
+            if (!callback->onComplete().isOk()) {
+                LOG(ERROR) << "Failed to call onComplete";
+            }
+        }).detach();
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
+                                     const std::shared_ptr<IVibratorCallback>& callback,
+                                     int32_t* _aidl_return) {
+    LOG(INFO) << "Vibrator perform";
+
+    if (effect != Effect::CLICK && effect != Effect::TICK) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+    if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM &&
+        strength != EffectStrength::STRONG) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    constexpr size_t kEffectMillis = 100;
+
+    if (callback != nullptr) {
+        std::thread([=] {
+            LOG(INFO) << "Starting perform on another thread";
+            usleep(kEffectMillis * 1000);
+            LOG(INFO) << "Notifying perform complete";
+            callback->onComplete();
+        }).detach();
+    }
+
+    *_aidl_return = kEffectMillis;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
+    *_aidl_return = {Effect::CLICK, Effect::TICK};
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
+    LOG(INFO) << "Vibrator set amplitude: " << amplitude;
+    if (amplitude <= 0.0f || amplitude > 1.0f) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
+    LOG(INFO) << "Vibrator set external control: " << enabled;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* maxDelayMs) {
+    *maxDelayMs = kComposeDelayMaxMs;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) {
+    *maxSize = kComposeSizeMax;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite,
+                                     const std::shared_ptr<IVibratorCallback>& callback) {
+    if (composite.size() > kComposeSizeMax) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    for (auto& e : composite) {
+        if (e.delayMs > kComposeDelayMaxMs) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        if (e.scale <= 0.0f || e.scale > 1.0f) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        if (e.primitive < CompositePrimitive::NOOP ||
+            e.primitive > CompositePrimitive::QUICK_FALL) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        }
+    }
+
+    std::thread([=] {
+        LOG(INFO) << "Starting compose on another thread";
+
+        for (auto& e : composite) {
+            if (e.delayMs) {
+                usleep(e.delayMs * 1000);
+            }
+            LOG(INFO) << "triggering primitive " << static_cast<int>(e.primitive) << " @ scale "
+                      << e.scale;
+        }
+
+        if (callback != nullptr) {
+            LOG(INFO) << "Notifying perform complete";
+            callback->onComplete();
+        }
+    }).detach();
+
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
new file mode 100644
index 0000000..817ec80
--- /dev/null
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <aidl/android/hardware/vibrator/BnVibrator.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+class Vibrator : public BnVibrator {
+    ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus off() override;
+    ndk::ScopedAStatus on(int32_t timeoutMs,
+                          const std::shared_ptr<IVibratorCallback>& callback) override;
+    ndk::ScopedAStatus perform(Effect effect, EffectStrength strength,
+                               const std::shared_ptr<IVibratorCallback>& callback,
+                               int32_t* _aidl_return) override;
+    ndk::ScopedAStatus getSupportedEffects(std::vector<Effect>* _aidl_return) override;
+    ndk::ScopedAStatus setAmplitude(float amplitude) override;
+    ndk::ScopedAStatus setExternalControl(bool enabled) override;
+    ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs);
+    ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize);
+    ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
+                               const std::shared_ptr<IVibratorCallback>& callback) override;
+};
+
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/vibrator/aidl/default/main.cpp b/vibrator/aidl/default/main.cpp
new file mode 100644
index 0000000..ebb0905
--- /dev/null
+++ b/vibrator/aidl/default/main.cpp
@@ -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.
+ */
+
+#include "vibrator-impl/Vibrator.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::vibrator::Vibrator;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<Vibrator> vib = ndk::SharedRefBase::make<Vibrator>();
+
+    const std::string instance = std::string() + Vibrator::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(vib->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/vibrator/aidl/default/vibrator-default.rc b/vibrator/aidl/default/vibrator-default.rc
new file mode 100644
index 0000000..d17f468
--- /dev/null
+++ b/vibrator/aidl/default/vibrator-default.rc
@@ -0,0 +1,4 @@
+service vendor.vibrator-default /vendor/bin/hw/android.hardware.vibrator-service.example
+    class hal
+    user system
+    group system
diff --git a/vibrator/aidl/default/vibrator-default.xml b/vibrator/aidl/default/vibrator-default.xml
new file mode 100644
index 0000000..49b11ec
--- /dev/null
+++ b/vibrator/aidl/default/vibrator-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.vibrator</name>
+        <fqname>IVibrator/default</fqname>
+    </hal>
+</manifest>
diff --git a/vibrator/aidl/vts/Android.bp b/vibrator/aidl/vts/Android.bp
new file mode 100644
index 0000000..20d53c7
--- /dev/null
+++ b/vibrator/aidl/vts/Android.bp
@@ -0,0 +1,17 @@
+cc_test {
+    name: "VtsHalVibratorTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalVibratorTargetTest.cpp"],
+    shared_libs: [
+        "libbinder",
+    ],
+    static_libs: [
+        "vintf-vibrator-cpp",
+    ],
+    test_suites: [
+        "vts-core",
+    ],
+}
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
new file mode 100644
index 0000000..6f9ba1a
--- /dev/null
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -0,0 +1,382 @@
+/*
+ * 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 <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android/hardware/vibrator/BnVibratorCallback.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <future>
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+using android::hardware::vibrator::BnVibratorCallback;
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+using android::hardware::vibrator::IVibrator;
+
+// TODO(b/143992652): autogenerate
+const std::vector<Effect> kEffects = {
+        Effect::CLICK,       Effect::DOUBLE_CLICK, Effect::TICK,        Effect::THUD,
+        Effect::POP,         Effect::HEAVY_CLICK,  Effect::RINGTONE_1,  Effect::RINGTONE_2,
+        Effect::RINGTONE_3,  Effect::RINGTONE_4,   Effect::RINGTONE_5,  Effect::RINGTONE_6,
+        Effect::RINGTONE_7,  Effect::RINGTONE_8,   Effect::RINGTONE_9,  Effect::RINGTONE_10,
+        Effect::RINGTONE_11, Effect::RINGTONE_12,  Effect::RINGTONE_13, Effect::RINGTONE_14,
+        Effect::RINGTONE_15, Effect::TEXTURE_TICK};
+
+// TODO(b/143992652): autogenerate
+const std::vector<EffectStrength> kEffectStrengths = {EffectStrength::LIGHT, EffectStrength::MEDIUM,
+                                                      EffectStrength::STRONG};
+
+const std::vector<Effect> kInvalidEffects = {
+        static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
+        static_cast<Effect>(static_cast<int32_t>(kEffects.back()) + 1),
+};
+
+const std::vector<EffectStrength> kInvalidEffectStrengths = {
+        static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.front()) - 1),
+        static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.back()) + 1),
+};
+
+// TODO(b/143992652): autogenerate
+const std::vector<CompositePrimitive> kCompositePrimitives = {
+        CompositePrimitive::NOOP,       CompositePrimitive::CLICK,
+        CompositePrimitive::THUD,       CompositePrimitive::SPIN,
+        CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
+        CompositePrimitive::QUICK_FALL,
+};
+// TODO(b/143992652): autogenerate
+
+const std::vector<CompositePrimitive> kInvalidPrimitives = {
+        static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
+        static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
+};
+
+class CompletionCallback : public BnVibratorCallback {
+  public:
+    CompletionCallback(const std::function<void()>& callback) : mCallback(callback) {}
+    Status onComplete() override {
+        mCallback();
+        return Status::ok();
+    }
+
+  private:
+    std::function<void()> mCallback;
+};
+
+class VibratorAidl : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        vibrator = android::waitForDeclaredService<IVibrator>(String16(GetParam().c_str()));
+        ASSERT_NE(vibrator, nullptr);
+        ASSERT_TRUE(vibrator->getCapabilities(&capabilities).isOk());
+    }
+
+    sp<IVibrator> vibrator;
+    int32_t capabilities;
+};
+
+TEST_P(VibratorAidl, OnThenOffBeforeTimeout) {
+    EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
+    sleep(1);
+    EXPECT_TRUE(vibrator->off().isOk());
+}
+
+TEST_P(VibratorAidl, OnWithCallback) {
+    if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return;
+
+    std::promise<void> completionPromise;
+    std::future<void> completionFuture{completionPromise.get_future()};
+    sp<CompletionCallback> callback =
+            new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+    uint32_t durationMs = 250;
+    std::chrono::milliseconds timeout{durationMs * 2};
+    EXPECT_TRUE(vibrator->on(durationMs, callback).isOk());
+    EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+    EXPECT_TRUE(vibrator->off().isOk());
+}
+
+TEST_P(VibratorAidl, OnCallbackNotSupported) {
+    if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) {
+        sp<CompletionCallback> callback = new CompletionCallback([] {});
+        EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, vibrator->on(250, callback).exceptionCode());
+    }
+}
+
+TEST_P(VibratorAidl, ValidateEffect) {
+    std::vector<Effect> supported;
+    ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
+
+    for (Effect effect : kEffects) {
+        bool isEffectSupported =
+                std::find(supported.begin(), supported.end(), effect) != supported.end();
+
+        for (EffectStrength strength : kEffectStrengths) {
+            int32_t lengthMs = 0;
+            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
+
+            if (isEffectSupported) {
+                EXPECT_TRUE(status.isOk()) << toString(effect) << " " << toString(strength);
+                EXPECT_GT(lengthMs, 0);
+                usleep(lengthMs * 1000);
+            } else {
+                EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
+                        << toString(effect) << " " << toString(strength);
+                EXPECT_EQ(lengthMs, 0);
+            }
+        }
+    }
+}
+
+TEST_P(VibratorAidl, ValidateEffectWithCallback) {
+    if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return;
+
+    std::vector<Effect> supported;
+    ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
+
+    for (Effect effect : kEffects) {
+        bool isEffectSupported =
+                std::find(supported.begin(), supported.end(), effect) != supported.end();
+
+        for (EffectStrength strength : kEffectStrengths) {
+            std::promise<void> completionPromise;
+            std::future<void> completionFuture{completionPromise.get_future()};
+            sp<CompletionCallback> callback =
+                    new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+            int lengthMs = 0;
+            Status status = vibrator->perform(effect, strength, callback, &lengthMs);
+
+            if (isEffectSupported) {
+                EXPECT_TRUE(status.isOk());
+                EXPECT_GT(lengthMs, 0);
+            } else {
+                EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+                EXPECT_EQ(lengthMs, 0);
+            }
+
+            if (!status.isOk()) continue;
+
+            std::chrono::milliseconds timeout{lengthMs * 2};
+            EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+        }
+    }
+}
+
+TEST_P(VibratorAidl, ValidateEffectWithCallbackNotSupported) {
+    if (capabilities & IVibrator::CAP_PERFORM_CALLBACK) return;
+
+    for (Effect effect : kEffects) {
+        for (EffectStrength strength : kEffectStrengths) {
+            sp<CompletionCallback> callback = new CompletionCallback([] {});
+            int lengthMs;
+            Status status = vibrator->perform(effect, strength, callback, &lengthMs);
+            EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
+            EXPECT_EQ(lengthMs, 0);
+        }
+    }
+}
+
+TEST_P(VibratorAidl, InvalidEffectsUnsupported) {
+    for (Effect effect : kInvalidEffects) {
+        for (EffectStrength strength : kEffectStrengths) {
+            int32_t lengthMs;
+            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
+            EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
+                    << toString(effect) << " " << toString(strength);
+        }
+    }
+    for (Effect effect : kEffects) {
+        for (EffectStrength strength : kInvalidEffectStrengths) {
+            int32_t lengthMs;
+            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
+            EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
+                    << toString(effect) << " " << toString(strength);
+        }
+    }
+}
+
+TEST_P(VibratorAidl, ChangeVibrationAmplitude) {
+    if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
+        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.1f).exceptionCode());
+        EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
+        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.5f).exceptionCode());
+        sleep(1);
+        EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(1.0f).exceptionCode());
+        sleep(1);
+    }
+}
+
+TEST_P(VibratorAidl, AmplitudeOutsideRangeFails) {
+    if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(-1).exceptionCode());
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(0).exceptionCode());
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(1.1).exceptionCode());
+    }
+}
+
+TEST_P(VibratorAidl, AmplitudeReturnsUnsupportedMatchingCapabilities) {
+    if ((capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) == 0) {
+        EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, vibrator->setAmplitude(1).exceptionCode());
+    }
+}
+
+TEST_P(VibratorAidl, ChangeVibrationExternalControl) {
+    if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
+        EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
+        sleep(1);
+        EXPECT_TRUE(vibrator->setExternalControl(false).isOk());
+        sleep(1);
+    }
+}
+
+TEST_P(VibratorAidl, ExternalAmplitudeControl) {
+    const bool supportsExternalAmplitudeControl =
+            (capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0;
+
+    if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
+        EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
+
+        Status amplitudeStatus = vibrator->setAmplitude(0.5);
+        if (supportsExternalAmplitudeControl) {
+            EXPECT_TRUE(amplitudeStatus.isOk());
+        } else {
+            EXPECT_EQ(amplitudeStatus.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+        }
+        EXPECT_TRUE(vibrator->setExternalControl(false).isOk());
+    } else {
+        EXPECT_FALSE(supportsExternalAmplitudeControl);
+    }
+}
+
+TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) {
+    if ((capabilities & IVibrator::CAP_EXTERNAL_CONTROL) == 0) {
+        EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION,
+                  vibrator->setExternalControl(true).exceptionCode());
+    }
+}
+
+TEST_P(VibratorAidl, ComposeValidPrimitives) {
+    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        int32_t maxDelay, maxSize;
+
+        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
+        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
+
+        std::vector<CompositeEffect> composite;
+
+        for (auto primitive : kCompositePrimitives) {
+            CompositeEffect effect;
+
+            effect.delayMs = std::rand() % (maxDelay + 1);
+            effect.primitive = primitive;
+            effect.scale = static_cast<float>(std::rand()) / RAND_MAX ?: 1.0f;
+            composite.emplace_back(effect);
+
+            if (composite.size() == maxSize) {
+                EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+                composite.clear();
+                vibrator->off();
+            }
+        }
+
+        if (composite.size() != 0) {
+            EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+            vibrator->off();
+        }
+    }
+}
+
+TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) {
+    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        for (auto primitive : kInvalidPrimitives) {
+            std::vector<CompositeEffect> composite(1);
+
+            for (auto& effect : composite) {
+                effect.delayMs = 0;
+                effect.primitive = primitive;
+                effect.scale = 1.0f;
+            }
+            EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION,
+                      vibrator->compose(composite, nullptr).exceptionCode());
+            vibrator->off();
+        }
+    }
+}
+
+TEST_P(VibratorAidl, CompseDelayBoundary) {
+    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        int32_t maxDelay;
+
+        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
+
+        std::vector<CompositeEffect> composite(1);
+        CompositeEffect effect;
+
+        effect.delayMs = 1;
+        effect.primitive = CompositePrimitive::CLICK;
+        effect.scale = 1.0f;
+
+        std::fill(composite.begin(), composite.end(), effect);
+        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+
+        effect.delayMs = maxDelay + 1;
+
+        std::fill(composite.begin(), composite.end(), effect);
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->compose(composite, nullptr).exceptionCode());
+        vibrator->off();
+    }
+}
+
+TEST_P(VibratorAidl, CompseSizeBoundary) {
+    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        int32_t maxSize;
+
+        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
+
+        std::vector<CompositeEffect> composite(maxSize);
+        CompositeEffect effect;
+
+        effect.delayMs = 1;
+        effect.primitive = CompositePrimitive::CLICK;
+        effect.scale = 1.0f;
+
+        std::fill(composite.begin(), composite.end(), effect);
+        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+
+        composite.emplace_back(effect);
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->compose(composite, nullptr).exceptionCode());
+        vibrator->off();
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IVibrator::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/vr/1.0/Android.bp b/vr/1.0/Android.bp
index ca47a6e..f91f874 100644
--- a/vr/1.0/Android.bp
+++ b/vr/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/vr/1.0/default/Android.bp b/vr/1.0/default/Android.bp
index ddc1bfb..cfb2808 100644
--- a/vr/1.0/default/Android.bp
+++ b/vr/1.0/default/Android.bp
@@ -12,7 +12,6 @@
         "libcutils",
         "libutils",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.vr@1.0",
     ],
 }
@@ -30,7 +29,6 @@
         "libutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.vr@1.0",
     ],
 }
diff --git a/vr/1.0/default/android.hardware.vr@1.0-service.rc b/vr/1.0/default/android.hardware.vr@1.0-service.rc
index fc4934c..5486674 100644
--- a/vr/1.0/default/android.hardware.vr@1.0-service.rc
+++ b/vr/1.0/default/android.hardware.vr@1.0-service.rc
@@ -1,4 +1,5 @@
 service vendor.vr-1-0 /vendor/bin/hw/android.hardware.vr@1.0-service
+    interface android.hardware.vr@1.0::IVr default
     class hal
     user system
     group system
diff --git a/vr/1.0/vts/functional/Android.bp b/vr/1.0/vts/functional/Android.bp
index 958cce7..bd0336c 100644
--- a/vr/1.0/vts/functional/Android.bp
+++ b/vr/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalVrV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.vr@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
index b165613..c08e5ca 100644
--- a/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
+++ b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
@@ -15,11 +15,12 @@
  */
 
 #define LOG_TAG "vr_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/vr/1.0/IVr.h>
+#include <gtest/gtest.h>
 #include <hardware/vr.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 using ::android::hardware::vr::V1_0::IVr;
@@ -27,24 +28,11 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
-// Test environment for Vr HIDL HAL.
-class VrHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static VrHidlEnvironment* Instance() {
-    static VrHidlEnvironment* instance = new VrHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<IVr>(); }
-};
-
 // The main test class for VR HIDL HAL.
-class VrHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class VrHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   void SetUp() override {
-    vr = ::testing::VtsHalHidlTargetTestBase::getService<IVr>(
-        VrHidlEnvironment::Instance()->getServiceName<IVr>());
+    vr = IVr::getService(GetParam());
     ASSERT_NE(vr, nullptr);
   }
 
@@ -54,19 +42,19 @@
 };
 
 // Sanity check that Vr::init does not crash.
-TEST_F(VrHidlTest, Init) {
+TEST_P(VrHidlTest, Init) {
   EXPECT_TRUE(vr->init().isOk());
 }
 
 // Sanity check Vr::setVrMode is able to enable and disable VR mode.
-TEST_F(VrHidlTest, SetVrMode) {
+TEST_P(VrHidlTest, SetVrMode) {
   EXPECT_TRUE(vr->init().isOk());
   EXPECT_TRUE(vr->setVrMode(true).isOk());
   EXPECT_TRUE(vr->setVrMode(false).isOk());
 }
 
 // Sanity check that Vr::init and Vr::setVrMode can be used in any order.
-TEST_F(VrHidlTest, ReInit) {
+TEST_P(VrHidlTest, ReInit) {
   EXPECT_TRUE(vr->init().isOk());
   EXPECT_TRUE(vr->setVrMode(true).isOk());
   EXPECT_TRUE(vr->init().isOk());
@@ -75,11 +63,8 @@
   EXPECT_TRUE(vr->setVrMode(false).isOk());
 }
 
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(VrHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  VrHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, VrHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVr::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
diff --git a/weaver/1.0/Android.bp b/weaver/1.0/Android.bp
index 7f93b10..7d5b8fe 100644
--- a/weaver/1.0/Android.bp
+++ b/weaver/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/weaver/1.0/vts/functional/Android.bp b/weaver/1.0/vts/functional/Android.bp
index 9fdbb18..3942deb 100644
--- a/weaver/1.0/vts/functional/Android.bp
+++ b/weaver/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalWeaverV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.weaver@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp b/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp
index de2a1de..ae92c36 100644
--- a/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp
+++ b/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp
@@ -15,12 +15,12 @@
  */
 
 #include <android/hardware/weaver/1.0/IWeaver.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <limits>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 using ::android::hardware::weaver::V1_0::IWeaver;
 using ::android::hardware::weaver::V1_0::WeaverConfig;
 using ::android::hardware::weaver::V1_0::WeaverReadStatus;
@@ -34,22 +34,9 @@
 const std::vector<uint8_t> VALUE{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
 const std::vector<uint8_t> OTHER_VALUE{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 255, 255};
 
-// Test environment for Weaver HIDL HAL.
-class WeaverHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static WeaverHidlEnvironment* Instance() {
-        static WeaverHidlEnvironment* instance = new WeaverHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IWeaver>(); }
-};
-
-struct WeaverHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+struct WeaverHidlTest : public ::testing::TestWithParam<std::string> {
     virtual void SetUp() override {
-        weaver = ::testing::VtsHalHidlTargetTestBase::getService<IWeaver>(
-            WeaverHidlEnvironment::Instance()->getServiceName<IWeaver>());
+        weaver = IWeaver::getService(GetParam());
         ASSERT_NE(weaver, nullptr);
     }
 
@@ -61,7 +48,7 @@
 /*
  * Checks config values are suitably large
  */
-TEST_F(WeaverHidlTest, GetConfig) {
+TEST_P(WeaverHidlTest, GetConfig) {
     WeaverStatus status;
     WeaverConfig config;
 
@@ -83,7 +70,7 @@
 /*
  * Gets the config twice and checks they are the same
  */
-TEST_F(WeaverHidlTest, GettingConfigMultipleTimesGivesSameResult) {
+TEST_P(WeaverHidlTest, GettingConfigMultipleTimesGivesSameResult) {
     WeaverConfig config1;
     WeaverConfig config2;
 
@@ -114,7 +101,7 @@
 /*
  * Gets the number of slots from the config and writes a key and value to the last one
  */
-TEST_F(WeaverHidlTest, WriteToLastSlot) {
+TEST_P(WeaverHidlTest, WriteToLastSlot) {
     WeaverStatus status;
     WeaverConfig config;
     const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -134,7 +121,7 @@
  * Writes a key and value to a slot
  * Reads the slot with the same key and receives the value that was previously written
  */
-TEST_F(WeaverHidlTest, WriteFollowedByReadGivesTheSameValue) {
+TEST_P(WeaverHidlTest, WriteFollowedByReadGivesTheSameValue) {
     constexpr uint32_t slotId = 0;
     const auto ret = weaver->write(slotId, KEY, VALUE);
     ASSERT_TRUE(ret.isOk());
@@ -162,7 +149,7 @@
  * Overwrites the slot with a new key and value
  * Reads the slot with the new key and receives the new value
  */
-TEST_F(WeaverHidlTest, OverwritingSlotUpdatesTheValue) {
+TEST_P(WeaverHidlTest, OverwritingSlotUpdatesTheValue) {
     constexpr uint32_t slotId = 0;
     const auto initialWriteRet = weaver->write(slotId, WRONG_KEY, VALUE);
     ASSERT_TRUE(initialWriteRet.isOk());
@@ -193,7 +180,7 @@
  * Writes a key and value to a slot
  * Reads the slot with a different key so does not receive the value
  */
-TEST_F(WeaverHidlTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) {
+TEST_P(WeaverHidlTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) {
     constexpr uint32_t slotId = 0;
     const auto ret = weaver->write(slotId, KEY, VALUE);
     ASSERT_TRUE(ret.isOk());
@@ -217,7 +204,7 @@
 /*
  * Writing to an invalid slot fails
  */
-TEST_F(WeaverHidlTest, WritingToInvalidSlotFails) {
+TEST_P(WeaverHidlTest, WritingToInvalidSlotFails) {
     WeaverStatus status;
     WeaverConfig config;
     const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -240,7 +227,7 @@
 /*
  * Reading from an invalid slot fails rather than incorrect key
  */
-TEST_F(WeaverHidlTest, ReadingFromInvalidSlotFails) {
+TEST_P(WeaverHidlTest, ReadingFromInvalidSlotFails) {
     WeaverStatus status;
     WeaverConfig config;
     const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -276,7 +263,7 @@
 /*
  * Writing a key that is too large fails
  */
-TEST_F(WeaverHidlTest, WriteWithTooLargeKeyFails) {
+TEST_P(WeaverHidlTest, WriteWithTooLargeKeyFails) {
     WeaverStatus status;
     WeaverConfig config;
     const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -297,7 +284,7 @@
 /*
  * Writing a value that is too large fails
  */
-TEST_F(WeaverHidlTest, WriteWithTooLargeValueFails) {
+TEST_P(WeaverHidlTest, WriteWithTooLargeValueFails) {
     WeaverStatus status;
     WeaverConfig config;
     const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -318,7 +305,7 @@
 /*
  * Reading with a key that is loo large fails
  */
-TEST_F(WeaverHidlTest, ReadWithTooLargeKeyFails) {
+TEST_P(WeaverHidlTest, ReadWithTooLargeKeyFails) {
     WeaverStatus status;
     WeaverConfig config;
     const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
@@ -349,11 +336,7 @@
     EXPECT_EQ(timeout, 0u);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(WeaverHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    WeaverHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, WeaverHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IWeaver::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/Android.bp b/wifi/1.0/Android.bp
index c5ee1bb..958ff3f 100644
--- a/wifi/1.0/Android.bp
+++ b/wifi/1.0/Android.bp
@@ -28,4 +28,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/wifi/1.0/IWifiP2pIface.hal b/wifi/1.0/IWifiP2pIface.hal
index b908591..025f7ab 100644
--- a/wifi/1.0/IWifiP2pIface.hal
+++ b/wifi/1.0/IWifiP2pIface.hal
@@ -19,6 +19,6 @@
 import IWifiIface;
 
 /**
- * Interface used to represent a single NAN iface.
+ * Interface used to represent a single P2P iface.
  */
 interface IWifiP2pIface extends IWifiIface {};
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 397ad17..95bb59c 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -28,7 +28,10 @@
     shared_libs: [
         "libnativehelper",
     ],
-    static_libs: ["android.hardware.wifi@1.0"],
+    static_libs: [
+        "android.hardware.wifi@1.0",
+        "libwifi-system-iface"
+    ],
 }
 
 cc_test {
@@ -48,6 +51,7 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "libwifi-system-iface"
     ],
     test_suites: ["general-tests"],
 }
@@ -62,6 +66,7 @@
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
         "android.hardware.wifi@1.0",
+        "libwifi-system-iface"
     ],
     test_suites: ["general-tests"],
 }
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index 97a371b..d584d4b 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -14,14 +14,19 @@
  * limitations under the License.
  */
 
+#include <android/log.h>
+
 #include <VtsHalHidlTargetTestBase.h>
 
+#include <wifi_system/interface_tool.h>
+
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
 
 using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiApIface;
 using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::V1_0::IWifiIface;
 using ::android::hardware::wifi::V1_0::IWifiNanIface;
 using ::android::hardware::wifi::V1_0::IWifiP2pIface;
 using ::android::hardware::wifi::V1_0::IWifiRttController;
@@ -34,6 +39,7 @@
 using ::android::sp;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
+using ::android::wifi_system::InterfaceTool;
 
 extern WifiHidlEnvironment* gEnv;
 
@@ -87,14 +93,21 @@
 }
 }  // namespace
 
-sp<IWifi> getWifi() {
-    sp<IWifi> wifi = ::testing::VtsHalHidlTargetTestBase::getService<IWifi>(
-        gEnv->getServiceName<IWifi>());
-    return wifi;
+sp<IWifi> getWifi(const std::string& instance_name) {
+    if ((!gEnv && instance_name.empty()) || (gEnv && !instance_name.empty())) {
+        ALOGE("instance_name and gEnv must have one and only one set.");
+        return nullptr;
+    }
+    if (gEnv) {
+        return ::testing::VtsHalHidlTargetTestBase::getService<IWifi>(
+            gEnv->getServiceName<IWifi>());
+    } else {
+        return IWifi::getService(instance_name);
+    }
 }
 
-sp<IWifiChip> getWifiChip() {
-    sp<IWifi> wifi = getWifi();
+sp<IWifiChip> getWifiChip(const std::string& instance_name) {
+    sp<IWifi> wifi = getWifi(instance_name);
     if (!wifi.get()) {
         return nullptr;
     }
@@ -122,8 +135,18 @@
     return status_and_chip.second;
 }
 
-sp<IWifiApIface> getWifiApIface() {
-    sp<IWifiChip> wifi_chip = getWifiChip();
+void setIfaceUp(const sp<IWifiIface>& iface) {
+    // Set the iface up before retrurning the object.
+    const auto& status_and_name = HIDL_INVOKE(iface, getName);
+    if (status_and_name.first.code == WifiStatusCode::SUCCESS) {
+        const auto& iface_name = status_and_name.second;
+        InterfaceTool iface_tool;
+        iface_tool.SetUpState(iface_name.c_str(), true);
+    }
+}
+
+sp<IWifiApIface> getWifiApIface(const std::string& instance_name) {
+    sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
     if (!wifi_chip.get()) {
         return nullptr;
     }
@@ -134,11 +157,12 @@
     if (status_and_iface.first.code != WifiStatusCode::SUCCESS) {
         return nullptr;
     }
+    setIfaceUp(status_and_iface.second);
     return status_and_iface.second;
 }
 
-sp<IWifiNanIface> getWifiNanIface() {
-    sp<IWifiChip> wifi_chip = getWifiChip();
+sp<IWifiNanIface> getWifiNanIface(const std::string& instance_name) {
+    sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
     if (!wifi_chip.get()) {
         return nullptr;
     }
@@ -149,11 +173,12 @@
     if (status_and_iface.first.code != WifiStatusCode::SUCCESS) {
         return nullptr;
     }
+    setIfaceUp(status_and_iface.second);
     return status_and_iface.second;
 }
 
-sp<IWifiP2pIface> getWifiP2pIface() {
-    sp<IWifiChip> wifi_chip = getWifiChip();
+sp<IWifiP2pIface> getWifiP2pIface(const std::string& instance_name) {
+    sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
     if (!wifi_chip.get()) {
         return nullptr;
     }
@@ -164,11 +189,12 @@
     if (status_and_iface.first.code != WifiStatusCode::SUCCESS) {
         return nullptr;
     }
+    setIfaceUp(status_and_iface.second);
     return status_and_iface.second;
 }
 
-sp<IWifiStaIface> getWifiStaIface() {
-    sp<IWifiChip> wifi_chip = getWifiChip();
+sp<IWifiStaIface> getWifiStaIface(const std::string& instance_name) {
+    sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
     if (!wifi_chip.get()) {
         return nullptr;
     }
@@ -179,15 +205,16 @@
     if (status_and_iface.first.code != WifiStatusCode::SUCCESS) {
         return nullptr;
     }
+    setIfaceUp(status_and_iface.second);
     return status_and_iface.second;
 }
 
-sp<IWifiRttController> getWifiRttController() {
-    sp<IWifiChip> wifi_chip = getWifiChip();
+sp<IWifiRttController> getWifiRttController(const std::string& instance_name) {
+    sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
     if (!wifi_chip.get()) {
         return nullptr;
     }
-    sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface();
+    sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface(instance_name);
     if (!wifi_sta_iface.get()) {
         return nullptr;
     }
@@ -206,8 +233,8 @@
                                                    configured_mode_id);
 }
 
-void stopWifi() {
-    sp<IWifi> wifi = getWifi();
+void stopWifi(const std::string& instance_name) {
+    sp<IWifi> wifi = getWifi(instance_name);
     ASSERT_NE(wifi, nullptr);
     HIDL_INVOKE(wifi, stop);
 }
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
index d430ce0..529b142 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -31,14 +31,21 @@
 // Note: We only have a single instance of each of these objects currently.
 // These helper functions should be modified to return vectors if we support
 // multiple instances.
-android::sp<android::hardware::wifi::V1_0::IWifi> getWifi();
-android::sp<android::hardware::wifi::V1_0::IWifiChip> getWifiChip();
-android::sp<android::hardware::wifi::V1_0::IWifiApIface> getWifiApIface();
-android::sp<android::hardware::wifi::V1_0::IWifiNanIface> getWifiNanIface();
-android::sp<android::hardware::wifi::V1_0::IWifiP2pIface> getWifiP2pIface();
-android::sp<android::hardware::wifi::V1_0::IWifiStaIface> getWifiStaIface();
+// TODO(b/143892896): Remove the default value as part of the cleanup.
+android::sp<android::hardware::wifi::V1_0::IWifi> getWifi(
+    const std::string& instance_name = "");
+android::sp<android::hardware::wifi::V1_0::IWifiChip> getWifiChip(
+    const std::string& instance_name = "");
+android::sp<android::hardware::wifi::V1_0::IWifiApIface> getWifiApIface(
+    const std::string& instance_name = "");
+android::sp<android::hardware::wifi::V1_0::IWifiNanIface> getWifiNanIface(
+    const std::string& instance_name = "");
+android::sp<android::hardware::wifi::V1_0::IWifiP2pIface> getWifiP2pIface(
+    const std::string& instance_name = "");
+android::sp<android::hardware::wifi::V1_0::IWifiStaIface> getWifiStaIface(
+    const std::string& instance_name = "");
 android::sp<android::hardware::wifi::V1_0::IWifiRttController>
-getWifiRttController();
+getWifiRttController(const std::string& instance_name = "");
 // Configure the chip in a mode to support the creation of the provided
 // iface type.
 bool configureChipToSupportIfaceType(
@@ -46,7 +53,7 @@
     android::hardware::wifi::V1_0::IfaceType type,
     android::hardware::wifi::V1_0::ChipModeId* configured_mode_id);
 // Used to trigger IWifi.stop() at the end of every test.
-void stopWifi();
+void stopWifi(const std::string& instance_name = "");
 
 class WifiHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
    protected:
diff --git a/wifi/1.1/Android.bp b/wifi/1.1/Android.bp
index a4499c8..a34ac44 100644
--- a/wifi/1.1/Android.bp
+++ b/wifi/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp
index 6662314..6d7635d 100644
--- a/wifi/1.1/vts/functional/Android.bp
+++ b/wifi/1.1/vts/functional/Android.bp
@@ -26,6 +26,7 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "libwifi-system-iface"
     ],
     test_suites: ["general-tests"],
 }
diff --git a/wifi/1.2/Android.bp b/wifi/1.2/Android.bp
index 1863eaf..c28d09b 100644
--- a/wifi/1.2/Android.bp
+++ b/wifi/1.2/Android.bp
@@ -22,4 +22,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp
index b2956ce..97853d0 100644
--- a/wifi/1.2/vts/functional/Android.bp
+++ b/wifi/1.2/vts/functional/Android.bp
@@ -28,6 +28,7 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "libwifi-system-iface"
     ],
     test_suites: ["general-tests"],
 }
@@ -44,6 +45,7 @@
         "android.hardware.wifi@1.0",
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
+        "libwifi-system-iface"
     ],
     test_suites: ["general-tests"],
 }
diff --git a/wifi/1.3/Android.bp b/wifi/1.3/Android.bp
index 401c7a6..3719c2b 100644
--- a/wifi/1.3/Android.bp
+++ b/wifi/1.3/Android.bp
@@ -20,4 +20,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/1.3/default/Android.mk b/wifi/1.3/default/Android.mk
index 0a3809c..29f1c42 100644
--- a/wifi/1.3/default/Android.mk
+++ b/wifi/1.3/default/Android.mk
@@ -59,7 +59,6 @@
     libbase \
     libcutils \
     libhidlbase \
-    libhidltransport \
     liblog \
     libnl \
     libutils \
@@ -86,7 +85,6 @@
     libbase \
     libcutils \
     libhidlbase \
-    libhidltransport \
     liblog \
     libnl \
     libutils \
@@ -117,7 +115,6 @@
     libbase \
     libcutils \
     libhidlbase \
-    libhidltransport \
     liblog \
     libnl \
     libutils \
@@ -160,7 +157,6 @@
     libbase \
     libcutils \
     libhidlbase \
-    libhidltransport \
     liblog \
     libnl \
     libutils \
diff --git a/wifi/1.3/default/android.hardware.wifi@1.0-service.rc b/wifi/1.3/default/android.hardware.wifi@1.0-service.rc
index cf849d0..2317bac 100644
--- a/wifi/1.3/default/android.hardware.wifi@1.0-service.rc
+++ b/wifi/1.3/default/android.hardware.wifi@1.0-service.rc
@@ -1,4 +1,7 @@
 service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
+    interface android.hardware.wifi@1.0::IWifi default
+    interface android.hardware.wifi@1.1::IWifi default
+    interface android.hardware.wifi@1.2::IWifi default
     class hal
     capabilities NET_ADMIN NET_RAW SYS_MODULE
     user wifi
diff --git a/wifi/1.3/default/service.cpp b/wifi/1.3/default/service.cpp
index fcbc37c..0b41d28 100644
--- a/wifi/1.3/default/service.cpp
+++ b/wifi/1.3/default/service.cpp
@@ -58,7 +58,7 @@
             std::make_shared<WifiIfaceUtil>(iface_tool),
             std::make_shared<WifiFeatureFlags>());
     if (kLazyService) {
-        LazyServiceRegistrar registrar;
+        auto registrar = LazyServiceRegistrar::getInstance();
         CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
             << "Failed to register wifi HAL";
     } else {
diff --git a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
index dbf7bd6..4e9ebde 100644
--- a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
@@ -170,12 +170,14 @@
 
         legacy_hal::wifi_channel_stat channel_stat1 = {
             .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+            .on_time = 0x1111,
             .cca_busy_time = 0x55,
-            .on_time = 0x1111};
+        };
         legacy_hal::wifi_channel_stat channel_stat2 = {
             .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+            .on_time = 0x2222,
             .cca_busy_time = 0x66,
-            .on_time = 0x2222};
+        };
         radio.channel_stats.push_back(channel_stat1);
         radio.channel_stats.push_back(channel_stat2);
     }
diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp
index 53c8f08..9ffda8b 100644
--- a/wifi/1.3/vts/functional/Android.bp
+++ b/wifi/1.3/vts/functional/Android.bp
@@ -28,5 +28,6 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "libwifi-system-iface"
     ],
 }
diff --git a/wifi/hostapd/1.0/Android.bp b/wifi/hostapd/1.0/Android.bp
index 9ee976e..cce1182 100644
--- a/wifi/hostapd/1.0/Android.bp
+++ b/wifi/hostapd/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/hostapd/1.0/vts/functional/Android.bp b/wifi/hostapd/1.0/vts/functional/Android.bp
index 93867d2..b53d002 100644
--- a/wifi/hostapd/1.0/vts/functional/Android.bp
+++ b/wifi/hostapd/1.0/vts/functional/Android.bp
@@ -26,7 +26,6 @@
         "android.hardware.wifi.hostapd@1.0",
         "android.hardware.wifi.hostapd@1.1",
         "android.hardware.wifi@1.0",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
@@ -46,10 +45,9 @@
         "android.hardware.wifi.hostapd@1.0",
         "android.hardware.wifi.hostapd@1.1",
         "android.hardware.wifi@1.0",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp b/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp
index 0303b20..4b62b15 100644
--- a/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp
+++ b/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp
@@ -14,36 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.0/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
 
-#include "hostapd_hidl_test_utils.h"
-
-class WifiHostapdHidlEnvironment_1_0 : public WifiHostapdHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiHostapdHidlEnvironment_1_0* Instance() {
-        static WifiHostapdHidlEnvironment_1_0* instance =
-            new WifiHostapdHidlEnvironment_1_0;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::wifi::V1_0::IWifi>();
-        registerTestService<android::hardware::wifi::hostapd::V1_0::IHostapd>();
-    }
-
-   private:
-    WifiHostapdHidlEnvironment_1_0() {}
-};
-
-WifiHostapdHidlEnvironment* gEnv = WifiHostapdHidlEnvironment_1_0::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp
index 8ee71fb..5a978ca 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp
@@ -17,18 +17,22 @@
 #include <android-base/logging.h>
 #include <cutils/properties.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
 
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
 #include "hostapd_hidl_call_util.h"
 #include "hostapd_hidl_test_utils.h"
 
 using ::android::sp;
 using ::android::hardware::hidl_vec;
-using ::android::hardware::wifi::hostapd::V1_0::IHostapd;
 using ::android::hardware::wifi::hostapd::V1_0::HostapdStatus;
 using ::android::hardware::wifi::hostapd::V1_0::HostapdStatusCode;
+using ::android::hardware::wifi::hostapd::V1_0::IHostapd;
+using ::android::hardware::wifi::V1_0::IWifi;
 
 namespace {
 constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1',
@@ -38,16 +42,20 @@
 constexpr int kIfaceInvalidChannel = 567;
 }  // namespace
 
-class HostapdHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class HostapdHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        stopSupplicantIfNeeded();
-        startHostapdAndWaitForHidlService();
-        hostapd_ = getHostapd();
+        wifi_instance_name_ = std::get<0>(GetParam());
+        hostapd_instance_name_ = std::get<1>(GetParam());
+        stopSupplicantIfNeeded(wifi_instance_name_);
+        startHostapdAndWaitForHidlService(wifi_instance_name_,
+                                          hostapd_instance_name_);
+        hostapd_ = IHostapd::getService(hostapd_instance_name_);
         ASSERT_NE(hostapd_.get(), nullptr);
     }
 
-    virtual void TearDown() override { stopHostapd(); }
+    virtual void TearDown() override { stopHostapd(wifi_instance_name_); }
 
    protected:
     std::string getPrimaryWlanIfaceName() {
@@ -121,6 +129,8 @@
     }
     // IHostapd object used for all tests in this fixture.
     sp<IHostapd> hostapd_;
+    std::string wifi_instance_name_;
+    std::string hostapd_instance_name_;
 };
 
 /*
@@ -128,17 +138,19 @@
  * Ensures that an instance of the IHostapd proxy object is
  * successfully created.
  */
-TEST(HostapdHidlTestNoFixture, Create) {
-    startHostapdAndWaitForHidlService();
-    EXPECT_NE(nullptr, getHostapd().get());
-    stopHostapd();
+TEST_P(HostapdHidlTest, Create) {
+    stopHostapd(wifi_instance_name_);
+    startHostapdAndWaitForHidlService(wifi_instance_name_,
+                                      hostapd_instance_name_);
+    sp<IHostapd> hostapd = IHostapd::getService(hostapd_instance_name_);
+    EXPECT_NE(nullptr, hostapd.get());
 }
 
 /**
  * Adds an access point with PSK network config & ACS enabled.
  * Access point creation should pass.
  */
-TEST_F(HostapdHidlTest, AddPskAccessPointWithAcs) {
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) {
     if (!is_1_1(hostapd_)) {
         auto status = HIDL_INVOKE(hostapd_, addAccessPoint,
                                   getIfaceParamsWithAcs(), getPskNwParams());
@@ -151,7 +163,7 @@
  * Adds an access point with Open network config & ACS enabled.
  * Access point creation should pass.
  */
-TEST_F(HostapdHidlTest, AddOpenAccessPointWithAcs) {
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) {
     if (!is_1_1(hostapd_)) {
         auto status = HIDL_INVOKE(hostapd_, addAccessPoint,
                                   getIfaceParamsWithAcs(), getOpenNwParams());
@@ -164,7 +176,7 @@
  * Adds an access point with PSK network config & ACS disabled.
  * Access point creation should pass.
  */
-TEST_F(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
+TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
     if (!is_1_1(hostapd_)) {
         auto status = HIDL_INVOKE(hostapd_, addAccessPoint,
                                   getIfaceParamsWithoutAcs(), getPskNwParams());
@@ -176,7 +188,7 @@
  * Adds an access point with Open network config & ACS disabled.
  * Access point creation should pass.
  */
-TEST_F(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
     if (!is_1_1(hostapd_)) {
         auto status =
             HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithoutAcs(),
@@ -189,7 +201,7 @@
  * Adds & then removes an access point with PSK network config & ACS enabled.
  * Access point creation & removal should pass.
  */
-TEST_F(HostapdHidlTest, RemoveAccessPointWithAcs) {
+TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) {
     if (!is_1_1(hostapd_)) {
         auto status = HIDL_INVOKE(hostapd_, addAccessPoint,
                                   getIfaceParamsWithAcs(), getPskNwParams());
@@ -207,7 +219,7 @@
  * Adds & then removes an access point with PSK network config & ACS disabled.
  * Access point creation & removal should pass.
  */
-TEST_F(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
+TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
     if (!is_1_1(hostapd_)) {
         auto status = HIDL_INVOKE(hostapd_, addAccessPoint,
                                   getIfaceParamsWithoutAcs(), getPskNwParams());
@@ -222,7 +234,7 @@
  * Adds an access point with invalid channel.
  * Access point creation should fail.
  */
-TEST_F(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
+TEST_P(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
     if (!is_1_1(hostapd_)) {
         auto status =
             HIDL_INVOKE(hostapd_, addAccessPoint,
@@ -235,7 +247,7 @@
  * Adds an access point with invalid PSK network config.
  * Access point creation should fail.
  */
-TEST_F(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
+TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
     if (!is_1_1(hostapd_)) {
         auto status =
             HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithoutAcs(),
@@ -248,6 +260,13 @@
  * Terminate
  * This terminates the service.
  */
-TEST_F(HostapdHidlTest, Terminate) {
-    hostapd_->terminate();
-}
+TEST_P(HostapdHidlTest, Terminate) { hostapd_->terminate(); }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, HostapdHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IHostapd::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
index 1c499e7..6058fd2 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
@@ -44,13 +44,11 @@
 using ::android::wifi_system::HostapdManager;
 using ::android::wifi_system::SupplicantManager;
 
-extern WifiHostapdHidlEnvironment* gEnv;
-
 namespace {
 // Helper function to initialize the driver and firmware to AP mode
 // using the vendor HAL HIDL interface.
-void initilializeDriverAndFirmware() {
-    sp<IWifiChip> wifi_chip = getWifiChip();
+void initilializeDriverAndFirmware(const std::string& wifi_instance_name) {
+    sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
     ChipModeId mode_id;
     EXPECT_TRUE(configureChipToSupportIfaceType(
         wifi_chip, ::android::hardware::wifi::V1_0::IfaceType::AP, &mode_id));
@@ -58,7 +56,9 @@
 
 // Helper function to deinitialize the driver and firmware
 // using the vendor HAL HIDL interface.
-void deInitilializeDriverAndFirmware() { stopWifi(); }
+void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) {
+    stopWifi(wifi_instance_name);
+}
 }  // namespace
 
 // Utility class to wait for wpa_hostapd's HIDL service registration.
@@ -110,45 +110,42 @@
     std::condition_variable condition_;
 };
 
-void stopSupplicantIfNeeded() {
+void stopSupplicantIfNeeded(const std::string& instance_name) {
     SupplicantManager supplicant_manager;
     if (supplicant_manager.IsSupplicantRunning()) {
         LOG(INFO) << "Supplicant is running, stop supplicant first.";
         ASSERT_TRUE(supplicant_manager.StopSupplicant());
-        deInitilializeDriverAndFirmware();
+        deInitilializeDriverAndFirmware(instance_name);
         ASSERT_FALSE(supplicant_manager.IsSupplicantRunning());
     }
 }
 
-void stopHostapd() {
+void stopHostapd(const std::string& instance_name) {
     HostapdManager hostapd_manager;
 
     ASSERT_TRUE(hostapd_manager.StopHostapd());
-    deInitilializeDriverAndFirmware();
+    deInitilializeDriverAndFirmware(instance_name);
 }
 
-void startHostapdAndWaitForHidlService() {
-    initilializeDriverAndFirmware();
+void startHostapdAndWaitForHidlService(
+    const std::string& wifi_instance_name,
+    const std::string& hostapd_instance_name) {
+    initilializeDriverAndFirmware(wifi_instance_name);
 
     android::sp<ServiceNotificationListener> notification_listener =
         new ServiceNotificationListener();
-    string service_name = gEnv->getServiceName<IHostapd>();
     ASSERT_TRUE(notification_listener->registerForHidlServiceNotifications(
-        service_name));
+        hostapd_instance_name));
 
     HostapdManager hostapd_manager;
     ASSERT_TRUE(hostapd_manager.StartHostapd());
 
-    ASSERT_TRUE(notification_listener->waitForHidlService(200, service_name));
+    ASSERT_TRUE(
+        notification_listener->waitForHidlService(500, hostapd_instance_name));
 }
 
 bool is_1_1(const sp<IHostapd>& hostapd) {
     sp<::android::hardware::wifi::hostapd::V1_1::IHostapd> hostapd_1_1 =
         ::android::hardware::wifi::hostapd::V1_1::IHostapd::castFrom(hostapd);
     return hostapd_1_1.get() != nullptr;
-}
-
-sp<IHostapd> getHostapd() {
-    return ::testing::VtsHalHidlTargetTestBase::getService<IHostapd>(
-        gEnv->getServiceName<IHostapd>());
-}
+}
\ No newline at end of file
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
index 9b3df42..5cb4f01 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
@@ -20,32 +20,18 @@
 #include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
 #include <android/hardware/wifi/hostapd/1.1/IHostapd.h>
 
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 // Used to stop the android wifi framework before every test.
-void stopWifiFramework();
-void startWifiFramework();
-void stopSupplicantIfNeeded();
-void stopHostapd();
+void stopWifiFramework(const std::string& instance_name);
+void startWifiFramework(const std::string& instance_name);
+void stopSupplicantIfNeeded(const std::string& instance_name);
+void stopHostapd(const std::string& instance_name);
 // Used to configure the chip, driver and start wpa_hostapd before every
 // test.
-void startHostapdAndWaitForHidlService();
+void startHostapdAndWaitForHidlService(
+    const std::string& wifi_instance_name,
+    const std::string& hostapd_instance_name);
 
-// Helper functions to obtain references to the various HIDL interface objects.
-// Note: We only have a single instance of each of these objects currently.
-// These helper functions should be modified to return vectors if we support
-// multiple instances.
-android::sp<android::hardware::wifi::hostapd::V1_0::IHostapd> getHostapd();
 bool is_1_1(const android::sp<android::hardware::wifi::hostapd::V1_0::IHostapd>&
                 hostapd);
 
-class WifiHostapdHidlEnvironment
-    : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    virtual void HidlSetUp() override { stopHostapd(); }
-    virtual void HidlTearDown() override {
-        startHostapdAndWaitForHidlService();
-    }
-};
-
 #endif /* HOSTAPD_HIDL_TEST_UTILS_H */
diff --git a/wifi/hostapd/1.1/Android.bp b/wifi/hostapd/1.1/Android.bp
index d4170b6..64fbc93 100644
--- a/wifi/hostapd/1.1/Android.bp
+++ b/wifi/hostapd/1.1/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/hostapd/1.1/vts/functional/Android.bp b/wifi/hostapd/1.1/vts/functional/Android.bp
index bbf5246..c963fe3 100644
--- a/wifi/hostapd/1.1/vts/functional/Android.bp
+++ b/wifi/hostapd/1.1/vts/functional/Android.bp
@@ -14,26 +14,6 @@
 // limitations under the License.
 //
 
-cc_library_static {
-    name: "VtsHalWifiHostapdV1_1TargetTestUtil",
-    defaults: ["VtsHalTargetTestDefaults"],
-    srcs: ["hostapd_hidl_test_utils_1_1.cpp"],
-    export_include_dirs: [
-        "."
-    ],
-    static_libs: [
-        "VtsHalWifiV1_0TargetTestUtil",
-        "VtsHalWifiHostapdV1_0TargetTestUtil",
-        "android.hardware.wifi.hostapd@1.0",
-        "android.hardware.wifi.hostapd@1.1",
-        "android.hardware.wifi@1.0",
-        "libcrypto",
-        "libgmock",
-        "libwifi-system",
-        "libwifi-system-iface",
-    ],
-}
-
 cc_test {
     name: "VtsHalWifiHostapdV1_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
@@ -44,15 +24,13 @@
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
         "VtsHalWifiHostapdV1_0TargetTestUtil",
-        "VtsHalWifiHostapdV1_1TargetTestUtil",
         "android.hardware.wifi.hostapd@1.0",
         "android.hardware.wifi.hostapd@1.1",
         "android.hardware.wifi@1.0",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp b/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp
index 6916db2..7e0f3cd 100644
--- a/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp
+++ b/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp
@@ -14,38 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.0/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
 
-#include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
-
-class WifiHostapdHidlEnvironment_1_1 : public WifiHostapdHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiHostapdHidlEnvironment_1_1* Instance() {
-        static WifiHostapdHidlEnvironment_1_1* instance =
-            new WifiHostapdHidlEnvironment_1_1;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::wifi::V1_0::IWifi>();
-        registerTestService<android::hardware::wifi::hostapd::V1_0::IHostapd>();
-        registerTestService<android::hardware::wifi::hostapd::V1_1::IHostapd>();
-    }
-
-   private:
-    WifiHostapdHidlEnvironment_1_1() {}
-};
-
-WifiHostapdHidlEnvironment* gEnv = WifiHostapdHidlEnvironment_1_1::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
\ No newline at end of file
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
index b053549..1804d8c 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
@@ -17,13 +17,15 @@
 #include <android-base/logging.h>
 #include <cutils/properties.h>
 
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/hostapd/1.1/IHostapd.h>
 
 #include "hostapd_hidl_call_util.h"
 #include "hostapd_hidl_test_utils.h"
-#include "hostapd_hidl_test_utils_1_1.h"
 
 using ::android::sp;
 using ::android::hardware::hidl_string;
@@ -33,6 +35,7 @@
 using ::android::hardware::wifi::hostapd::V1_0::HostapdStatusCode;
 using ::android::hardware::wifi::hostapd::V1_1::IHostapd;
 using ::android::hardware::wifi::hostapd::V1_1::IHostapdCallback;
+using ::android::hardware::wifi::V1_0::IWifi;
 
 namespace {
 constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1',
@@ -42,16 +45,20 @@
 constexpr int kIfaceInvalidChannel = 567;
 }  // namespace
 
-class HostapdHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class HostapdHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        stopSupplicantIfNeeded();
-        startHostapdAndWaitForHidlService();
-        hostapd_ = getHostapd_1_1();
+        wifi_instance_name_ = std::get<0>(GetParam());
+        hostapd_instance_name_ = std::get<1>(GetParam());
+        stopSupplicantIfNeeded(wifi_instance_name_);
+        startHostapdAndWaitForHidlService(wifi_instance_name_,
+                                          hostapd_instance_name_);
+        hostapd_ = IHostapd::getService(hostapd_instance_name_);
         ASSERT_NE(hostapd_.get(), nullptr);
     }
 
-    virtual void TearDown() override { stopHostapd(); }
+    virtual void TearDown() override { stopHostapd(wifi_instance_name_); }
 
    protected:
     std::string getPrimaryWlanIfaceName() {
@@ -152,6 +159,8 @@
 
     // IHostapd object used for all tests in this fixture.
     sp<IHostapd> hostapd_;
+    std::string wifi_instance_name_;
+    std::string hostapd_instance_name_;
 };
 
 class IfaceCallback : public IHostapdCallback {
@@ -164,7 +173,7 @@
 /*
  * RegisterCallback
  */
-TEST_F(HostapdHidlTest, registerCallback) {
+TEST_P(HostapdHidlTest, registerCallback) {
     hostapd_->registerCallback(
         new IfaceCallback(), [](const HostapdStatus& status) {
             EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
@@ -175,7 +184,7 @@
  * Adds an access point with PSK network config & ACS enabled.
  * Access point creation should pass.
  */
-TEST_F(HostapdHidlTest, AddPskAccessPointWithAcs) {
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                               getIfaceParamsWithAcs(), getPskNwParams());
     // TODO: b/140172237, fix this in R.
@@ -186,7 +195,7 @@
  * Adds an access point with PSK network config, ACS enabled & channel Range.
  * Access point creation should pass.
  */
-TEST_F(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) {
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) {
     auto status =
         HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                     getIfaceParamsWithAcsAndChannelRange(), getPskNwParams());
@@ -198,7 +207,7 @@
  * Adds an access point with invalid channel range.
  * Access point creation should fail.
  */
-TEST_F(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidChannelRange) {
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidChannelRange) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                               getIfaceParamsWithAcsAndInvalidChannelRange(),
                               getPskNwParams());
@@ -210,7 +219,7 @@
  * Adds an access point with Open network config & ACS enabled.
  * Access point creation should pass.
  */
-TEST_F(HostapdHidlTest, AddOpenAccessPointWithAcs) {
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                               getIfaceParamsWithAcs(), getOpenNwParams());
     // TODO: b/140172237, fix this in R
@@ -221,7 +230,7 @@
  * Adds an access point with PSK network config & ACS disabled.
  * Access point creation should pass.
  */
-TEST_F(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
+TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                               getIfaceParamsWithoutAcs(), getPskNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
@@ -231,7 +240,7 @@
  * Adds an access point with Open network config & ACS disabled.
  * Access point creation should pass.
  */
-TEST_F(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                               getIfaceParamsWithoutAcs(), getOpenNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
@@ -241,7 +250,7 @@
  * Adds & then removes an access point with PSK network config & ACS enabled.
  * Access point creation & removal should pass.
  */
-TEST_F(HostapdHidlTest, RemoveAccessPointWithAcs) {
+TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                               getIfaceParamsWithAcs(), getPskNwParams());
     // TODO: b/140172237, fix this in R
@@ -257,7 +266,7 @@
  * Adds & then removes an access point with PSK network config & ACS disabled.
  * Access point creation & removal should pass.
  */
-TEST_F(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
+TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                               getIfaceParamsWithoutAcs(), getPskNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
@@ -270,7 +279,7 @@
  * Adds an access point with invalid channel.
  * Access point creation should fail.
  */
-TEST_F(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
+TEST_P(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
     auto status =
         HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                     getIfaceParamsWithInvalidChannel(), getPskNwParams());
@@ -281,9 +290,18 @@
  * Adds an access point with invalid PSK network config.
  * Access point creation should fail.
  */
-TEST_F(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
+TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
     auto status =
         HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(),
                     getInvalidPskNwParams());
     EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, HostapdHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::hostapd::V1_1::IHostapd::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.h b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.h
deleted file mode 100644
index c43ddfa..0000000
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef HOSTAPD_HIDL_TEST_UTILS_1_1_H
-#define HOSTAPD_HIDL_TEST_UTILS_1_1_H
-
-#include <android/hardware/wifi/hostapd/1.1/IHostapd.h>
-
-#include <VtsHalHidlTargetTestEnvBase.h>
-
-// Helper functions to obtain references to the various HIDL interface objects.
-// Note: We only have a single instance of each of these objects currently.
-// These helper functions should be modified to return vectors if we support
-// multiple instances.
-android::sp<android::hardware::wifi::hostapd::V1_1::IHostapd> getHostapd_1_1();
-
-#endif /* HOSTAPD_HIDL_TEST_UTILS_1_1_H */
diff --git a/wifi/offload/1.0/Android.bp b/wifi/offload/1.0/Android.bp
index 1a9ae73..110bb70 100644
--- a/wifi/offload/1.0/Android.bp
+++ b/wifi/offload/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/wifi/offload/1.0/vts/functional/Android.bp b/wifi/offload/1.0/vts/functional/Android.bp
index de15aa7..965c946 100644
--- a/wifi/offload/1.0/vts/functional/Android.bp
+++ b/wifi/offload/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalWifiOffloadV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.wifi.offload@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp b/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
index dbe4e74..83d834c 100644
--- a/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
+++ b/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
@@ -20,10 +20,11 @@
 #include <android/hardware/wifi/offload/1.0/IOffload.h>
 #include <android/hardware/wifi/offload/1.0/IOffloadCallback.h>
 #include <android/hardware/wifi/offload/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 
 #include <vector>
 
@@ -69,33 +70,11 @@
     OffloadStatus error_code_;
 };
 
-// Test environment for Weaver HIDL HAL.
-class WifiOffloadHidlEnvironment
-    : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static WifiOffloadHidlEnvironment* Instance() {
-        static WifiOffloadHidlEnvironment* instance =
-            new WifiOffloadHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<IOffload>();
-    }
-
-   private:
-    WifiOffloadHidlEnvironment() {}
-};
-
 // The main test class for WifiOffload HIDL HAL.
-class WifiOffloadHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiOffloadHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_offload_ =
-            ::testing::VtsHalHidlTargetTestBase::getService<IOffload>(
-                WifiOffloadHidlEnvironment::Instance()
-                    ->getServiceName<IOffload>());
+        wifi_offload_ = IOffload::getService(GetParam());
         ASSERT_NE(wifi_offload_, nullptr);
 
         wifi_offload_cb_ = new OffloadCallback();
@@ -136,7 +115,7 @@
 /*
  * Verify that setEventCallback method returns without errors
  */
-TEST_F(WifiOffloadHidlTest, setEventCallback) {
+TEST_P(WifiOffloadHidlTest, setEventCallback) {
     auto returnObject = wifi_offload_->setEventCallback(wifi_offload_cb_);
     ASSERT_EQ(true, returnObject.isOk());
 }
@@ -144,7 +123,7 @@
 /*
  * Verify that subscribeScanResults method returns without errors
  */
-TEST_F(WifiOffloadHidlTest, subscribeScanResults) {
+TEST_P(WifiOffloadHidlTest, subscribeScanResults) {
     const auto& result = HIDL_INVOKE(wifi_offload_, subscribeScanResults, 0);
     ASSERT_EQ(OffloadStatusCode::OK, result.code);
 }
@@ -152,7 +131,7 @@
 /*
  * Verify that unsubscribeScanResults method returns without errors
  */
-TEST_F(WifiOffloadHidlTest, unsubscribeScanResults) {
+TEST_P(WifiOffloadHidlTest, unsubscribeScanResults) {
     auto returnObject = wifi_offload_->unsubscribeScanResults();
     ASSERT_EQ(true, returnObject.isOk());
 }
@@ -160,7 +139,7 @@
 /*
  * Verify that configureScans method returns without errors
  */
-TEST_F(WifiOffloadHidlTest, configureScans) {
+TEST_P(WifiOffloadHidlTest, configureScans) {
     ScanParam* pScanParam = new ScanParam();
     std::vector<uint32_t> frequencyList = {kFrequency1, kFrequency2};
     pScanParam->disconnectedModeScanIntervalMs =
@@ -192,7 +171,7 @@
 /*
  * Verify that getScanStats returns without any errors
  */
-TEST_F(WifiOffloadHidlTest, getScanStats) {
+TEST_P(WifiOffloadHidlTest, getScanStats) {
     const auto& result = HIDL_INVOKE(wifi_offload_, getScanStats);
     OffloadStatus status = result.first;
     ASSERT_EQ(OffloadStatusCode::OK, status.code);
@@ -201,7 +180,7 @@
 /*
  * Verify that onScanResult callback is invoked
  */
-TEST_F(WifiOffloadHidlTest, getScanResults) {
+TEST_P(WifiOffloadHidlTest, getScanResults) {
     wifi_offload_->setEventCallback(wifi_offload_cb_);
     std::vector<ScanResult> scan_results;
     std::vector<uint8_t> ssid(kSsid1, kSsid1 + sizeof(kSsid1));
@@ -223,7 +202,7 @@
 /*
  * Verify that onError callback is invoked
  */
-TEST_F(WifiOffloadHidlTest, getError) {
+TEST_P(WifiOffloadHidlTest, getError) {
     wifi_offload_->setEventCallback(wifi_offload_cb_);
     OffloadStatus status = {OffloadStatusCode::ERROR, ""};
     wifi_offload_cb_->onError(status);
@@ -231,12 +210,8 @@
     ASSERT_EQ(true, res.no_timeout);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(WifiOffloadHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    WifiOffloadHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiOffloadHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IOffload::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/offload/1.0/vts/functional/hidl_call_util.h b/wifi/offload/1.0/vts/functional/hidl_call_util.h
index f3ca517..99868e8 100644
--- a/wifi/offload/1.0/vts/functional/hidl_call_util.h
+++ b/wifi/offload/1.0/vts/functional/hidl_call_util.h
@@ -21,8 +21,6 @@
 #include <type_traits>
 #include <utility>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace {
 namespace detail {
 template <typename>
diff --git a/wifi/supplicant/1.0/Android.bp b/wifi/supplicant/1.0/Android.bp
index c99706d..d91512f 100644
--- a/wifi/supplicant/1.0/Android.bp
+++ b/wifi/supplicant/1.0/Android.bp
@@ -26,4 +26,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index bdccac1..15525bb 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -26,7 +26,6 @@
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
         "android.hardware.wifi@1.0",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
@@ -48,12 +47,11 @@
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
         "android.hardware.wifi@1.0",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
 cc_test {
@@ -69,9 +67,9 @@
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
         "android.hardware.wifi@1.0",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
     ],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
index 6ca0546..f582cc1 100644
--- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
@@ -14,40 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-
 #include "supplicant_hidl_test_utils.h"
-#include "wifi_hidl_test_utils.h"
 
-class WifiSupplicantHidlEnvironment_1_0 : public WifiSupplicantHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiSupplicantHidlEnvironment_1_0* Instance() {
-        static WifiSupplicantHidlEnvironment_1_0* instance =
-            new WifiSupplicantHidlEnvironment_1_0;
-        return instance;
-    }
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::wifi::V1_0::IWifi>();
-        registerTestService<
-            ::android::hardware::wifi::supplicant::V1_0::ISupplicant>();
-    }
-
-   private:
-    WifiSupplicantHidlEnvironment_1_0() {}
-};
-
-WifiSupplicantHidlEnvironment* gEnv =
-    WifiSupplicantHidlEnvironment_1_0::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        int status = RUN_ALL_TESTS();
-        LOG(INFO) << "Test result = " << status;
-    }
-    return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_call_util.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_call_util.h
index 1c0fcec..3fa6f9d 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_call_util.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_call_util.h
@@ -25,8 +25,6 @@
 #include <type_traits>
 #include <utility>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace {
 namespace detail {
 template <typename>
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
index 436b88b..4f25465 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
@@ -16,35 +16,47 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicant.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "supplicant_hidl_test_utils.h"
 
 using ::android::sp;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantIface;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
-using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
 
-extern WifiSupplicantHidlEnvironment* gEnv;
-
-class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        supplicant_ = getSupplicant();
+        wifi_instance_name_ = std::get<0>(GetParam());
+        supplicant_instance_name_ = std::get<1>(GetParam());
+        stopSupplicant(wifi_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                             supplicant_instance_name_);
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
         ASSERT_NE(supplicant_.get(), nullptr);
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
+    virtual void TearDown() override { stopSupplicant(wifi_instance_name_); }
 
    protected:
     // ISupplicant object used for all tests in this fixture.
     sp<ISupplicant> supplicant_;
+    bool isP2pOn_ = false;
+    std::string wifi_instance_name_;
+    std::string supplicant_instance_name_;
 };
 
 /*
@@ -52,16 +64,19 @@
  * Ensures that an instance of the ISupplicant proxy object is
  * successfully created.
  */
-TEST(SupplicantHidlTestNoFixture, Create) {
-    startSupplicantAndWaitForHidlService();
-    EXPECT_NE(nullptr, getSupplicant().get());
-    stopSupplicant();
+TEST_P(SupplicantHidlTest, Create) {
+    // Stop the proxy object created in setup.
+    stopSupplicant(wifi_instance_name_);
+    startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                         supplicant_instance_name_);
+    EXPECT_NE(nullptr,
+              getSupplicant(supplicant_instance_name_, isP2pOn_).get());
 }
 
 /*
  * ListInterfaces
  */
-TEST_F(SupplicantHidlTest, ListInterfaces) {
+TEST_P(SupplicantHidlTest, ListInterfaces) {
     std::vector<ISupplicant::IfaceInfo> ifaces;
     supplicant_->listInterfaces(
         [&](const SupplicantStatus& status,
@@ -74,7 +89,7 @@
               std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) {
                   return iface.type == IfaceType::STA;
               }));
-    if (gEnv->isP2pOn) {
+    if (isP2pOn_) {
         EXPECT_NE(
             ifaces.end(),
             std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) {
@@ -86,7 +101,7 @@
 /*
  * GetInterface
  */
-TEST_F(SupplicantHidlTest, GetInterface) {
+TEST_P(SupplicantHidlTest, GetInterface) {
     std::vector<ISupplicant::IfaceInfo> ifaces;
     supplicant_->listInterfaces(
         [&](const SupplicantStatus& status,
@@ -107,7 +122,7 @@
 /*
  * SetDebugParams
  */
-TEST_F(SupplicantHidlTest, SetDebugParams) {
+TEST_P(SupplicantHidlTest, SetDebugParams) {
     bool show_timestamp = true;
     bool show_keys = true;
     ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
@@ -124,7 +139,7 @@
 /*
  * GetDebugLevel
  */
-TEST_F(SupplicantHidlTest, GetDebugLevel) {
+TEST_P(SupplicantHidlTest, GetDebugLevel) {
     bool show_timestamp = true;
     bool show_keys = true;
     ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
@@ -142,7 +157,7 @@
 /*
  * IsDebugShowTimestampEnabled
  */
-TEST_F(SupplicantHidlTest, IsDebugShowTimestampEnabled) {
+TEST_P(SupplicantHidlTest, IsDebugShowTimestampEnabled) {
     bool show_timestamp = true;
     bool show_keys = true;
     ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
@@ -160,7 +175,7 @@
 /*
  * IsDebugShowKeysEnabled
  */
-TEST_F(SupplicantHidlTest, IsDebugShowKeysEnabled) {
+TEST_P(SupplicantHidlTest, IsDebugShowKeysEnabled) {
     bool show_timestamp = true;
     bool show_keys = true;
     ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
@@ -178,15 +193,24 @@
 /*
  * SetConcurrenyPriority
  */
-TEST_F(SupplicantHidlTest, SetConcurrencyPriority) {
+TEST_P(SupplicantHidlTest, SetConcurrencyPriority) {
     supplicant_->setConcurrencyPriority(
         IfaceType::STA, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
         });
-    if (gEnv->isP2pOn) {
+    if (isP2pOn_) {
         supplicant_->setConcurrencyPriority(
             IfaceType::P2P, [](const SupplicantStatus& status) {
                 EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
             });
     }
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            ISupplicant::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index 47c3056..d47e42f 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -56,8 +56,8 @@
 
 // Helper function to initialize the driver and firmware to STA mode
 // using the vendor HAL HIDL interface.
-void initilializeDriverAndFirmware() {
-    sp<IWifiChip> wifi_chip = getWifiChip();
+void initilializeDriverAndFirmware(const std::string& wifi_instance_name) {
+    sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
     ChipModeId mode_id;
     EXPECT_TRUE(configureChipToSupportIfaceType(
         wifi_chip, ::android::hardware::wifi::V1_0::IfaceType::STA, &mode_id));
@@ -65,7 +65,9 @@
 
 // Helper function to deinitialize the driver and firmware
 // using the vendor HAL HIDL interface.
-void deInitilializeDriverAndFirmware() { stopWifi(); }
+void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) {
+    stopWifi(wifi_instance_name);
+}
 
 // Helper function to find any iface of the desired type exposed.
 bool findIfaceOfType(sp<ISupplicant> supplicant, IfaceType desired_type,
@@ -154,28 +156,38 @@
     std::condition_variable condition_;
 };
 
-void stopSupplicant() {
+void stopSupplicant() { stopSupplicant(""); }
+
+void stopSupplicant(const std::string& wifi_instance_name) {
     SupplicantManager supplicant_manager;
 
     ASSERT_TRUE(supplicant_manager.StopSupplicant());
-    deInitilializeDriverAndFirmware();
+    deInitilializeDriverAndFirmware(wifi_instance_name);
     ASSERT_FALSE(supplicant_manager.IsSupplicantRunning());
 }
 
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 void startSupplicantAndWaitForHidlService() {
-    initilializeDriverAndFirmware();
+    startSupplicantAndWaitForHidlService("",
+                                         gEnv->getServiceName<ISupplicant>());
+}
+
+void startSupplicantAndWaitForHidlService(
+    const std::string& wifi_instance_name,
+    const std::string& supplicant_instance_name) {
+    initilializeDriverAndFirmware(wifi_instance_name);
 
     android::sp<ServiceNotificationListener> notification_listener =
         new ServiceNotificationListener();
-    string service_name = gEnv->getServiceName<ISupplicant>();
     ASSERT_TRUE(notification_listener->registerForHidlServiceNotifications(
-        service_name));
+        supplicant_instance_name));
 
     SupplicantManager supplicant_manager;
     ASSERT_TRUE(supplicant_manager.StartSupplicant());
     ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
 
-    ASSERT_TRUE(notification_listener->waitForHidlService(200, service_name));
+    ASSERT_TRUE(notification_listener->waitForHidlService(
+        500, supplicant_instance_name));
 }
 
 bool is_1_1(const sp<ISupplicant>& supplicant) {
@@ -218,6 +230,7 @@
         });
 }
 
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 sp<ISupplicant> getSupplicant() {
     sp<ISupplicant> supplicant =
         ::testing::VtsHalHidlTargetTestBase::getService<ISupplicant>(
@@ -232,8 +245,28 @@
     return supplicant;
 }
 
+sp<ISupplicant> getSupplicant(const std::string& supplicant_instance_name,
+                              bool isP2pOn) {
+    sp<ISupplicant> supplicant =
+        ISupplicant::getService(supplicant_instance_name);
+    // For 1.1 supplicant, we need to add interfaces at initialization.
+    if (is_1_1(supplicant)) {
+        addSupplicantStaIface_1_1(supplicant);
+        if (isP2pOn) {
+            addSupplicantP2pIface_1_1(supplicant);
+        }
+    }
+    return supplicant;
+}
+
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 sp<ISupplicantStaIface> getSupplicantStaIface() {
     sp<ISupplicant> supplicant = getSupplicant();
+    return getSupplicantStaIface(supplicant);
+}
+
+sp<ISupplicantStaIface> getSupplicantStaIface(
+    const sp<ISupplicant>& supplicant) {
     if (!supplicant.get()) {
         return nullptr;
     }
@@ -257,8 +290,14 @@
     return sta_iface;
 }
 
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 sp<ISupplicantStaNetwork> createSupplicantStaNetwork() {
-    sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface();
+    return createSupplicantStaNetwork(getSupplicant());
+}
+
+sp<ISupplicantStaNetwork> createSupplicantStaNetwork(
+    const sp<ISupplicant>& supplicant) {
+    sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface(supplicant);
     if (!sta_iface.get()) {
         return nullptr;
     }
@@ -278,8 +317,13 @@
     return sta_network;
 }
 
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 sp<ISupplicantP2pIface> getSupplicantP2pIface() {
-    sp<ISupplicant> supplicant = getSupplicant();
+    return getSupplicantP2pIface(getSupplicant());
+}
+
+sp<ISupplicantP2pIface> getSupplicantP2pIface(
+    const sp<ISupplicant>& supplicant) {
     if (!supplicant.get()) {
         return nullptr;
     }
@@ -303,8 +347,12 @@
     return p2p_iface;
 }
 
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 bool turnOnExcessiveLogging() {
-    sp<ISupplicant> supplicant = getSupplicant();
+    return turnOnExcessiveLogging(getSupplicant());
+}
+
+bool turnOnExcessiveLogging(const sp<ISupplicant>& supplicant) {
     if (!supplicant.get()) {
         return false;
     }
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
index 21a1ae6..40ad695 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
@@ -25,21 +25,47 @@
 
 #include <getopt.h>
 
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include "wifi_hidl_test_utils.h"
 
 // Used to stop the android wifi framework before every test.
 void stopWifiFramework();
+void stopWifiFramework(const std::string& wifi_instance_name);
 void startWifiFramework();
+void startWifiFramework(const std::string& wifi_instance_name);
+
 void stopSupplicant();
+void stopSupplicant(const std::string& wifi_instance_name);
 // Used to configure the chip, driver and start wpa_supplicant before every
 // test.
-void startSupplicantAndWaitForHidlService();
+void startSupplicantAndWaitForHidlService(
+    const std::string& wifi_instance_name,
+    const std::string& supplicant_instance_name);
 
 // Helper functions to obtain references to the various HIDL interface objects.
 // Note: We only have a single instance of each of these objects currently.
 // These helper functions should be modified to return vectors if we support
 // multiple instances.
 android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>
+getSupplicant(const std::string& supplicant_instance_name, bool isP2pOn);
+android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface>
+getSupplicantStaIface(
+    const android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>&
+        supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork>
+createSupplicantStaNetwork(
+    const android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>&
+        supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface>
+getSupplicantP2pIface(
+    const android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>&
+        supplicant);
+bool turnOnExcessiveLogging(
+    const android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>&
+        supplicant);
+
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
+void startSupplicantAndWaitForHidlService();
+android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>
 getSupplicant();
 android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface>
 getSupplicantStaIface();
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
index 0181f7b..8d6f38d 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
@@ -15,9 +15,12 @@
  */
 
 #include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIface.h>
 
 #include "supplicant_hidl_call_util.h"
@@ -30,11 +33,13 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIfaceCallback;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantNetworkId;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::V1_0::IWifi;
 
 namespace {
 constexpr uint8_t kTestSsidPostfix[] = {'t', 'e', 's', 't'};
@@ -66,26 +71,38 @@
 constexpr SupplicantNetworkId kTestNetworkId = 5;
 }  // namespace
 
-class SupplicantP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantP2pIfaceHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        EXPECT_TRUE(turnOnExcessiveLogging());
-        p2p_iface_ = getSupplicantP2pIface();
+        wifi_instance_name_ = std::get<0>(GetParam());
+        supplicant_instance_name_ = std::get<1>(GetParam());
+        stopSupplicant(wifi_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                             supplicant_instance_name_);
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        p2p_iface_ = getSupplicantP2pIface(supplicant_);
         ASSERT_NE(p2p_iface_.get(), nullptr);
 
         memcpy(mac_addr_.data(), kTestMacAddr, mac_addr_.size());
         memcpy(peer_mac_addr_.data(), kTestPeerMacAddr, peer_mac_addr_.size());
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
+    virtual void TearDown() override { stopSupplicant(wifi_instance_name_); }
 
    protected:
+    bool isP2pOn_ = false;
+    sp<ISupplicant> supplicant_;
     // ISupplicantP2pIface object used for all tests in this fixture.
     sp<ISupplicantP2pIface> p2p_iface_;
     // MAC address to use for various tests.
     std::array<uint8_t, 6> mac_addr_;
     std::array<uint8_t, 6> peer_mac_addr_;
+    std::string wifi_instance_name_;
+    std::string supplicant_instance_name_;
 };
 
 class IfaceCallback : public ISupplicantP2pIfaceCallback {
@@ -177,16 +194,20 @@
  * Ensures that an instance of the ISupplicantP2pIface proxy object is
  * successfully created.
  */
-TEST(SupplicantP2pIfaceHidlTestNoFixture, Create) {
-    startSupplicantAndWaitForHidlService();
-    EXPECT_NE(nullptr, getSupplicantP2pIface().get());
-    stopSupplicant();
+TEST_P(SupplicantP2pIfaceHidlTest, Create) {
+    stopSupplicant(wifi_instance_name_);
+    startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                         supplicant_instance_name_);
+    sp<ISupplicantP2pIface> p2p_iface = getSupplicantP2pIface(
+        getSupplicant(supplicant_instance_name_, isP2pOn_));
+
+    EXPECT_NE(nullptr, p2p_iface.get());
 }
 
 /*
  * RegisterCallback
  */
-TEST_F(SupplicantP2pIfaceHidlTest, RegisterCallback) {
+TEST_P(SupplicantP2pIfaceHidlTest, RegisterCallback) {
     p2p_iface_->registerCallback(
         new IfaceCallback(), [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -196,7 +217,7 @@
 /*
  * GetName
  */
-TEST_F(SupplicantP2pIfaceHidlTest, GetName) {
+TEST_P(SupplicantP2pIfaceHidlTest, GetName) {
     const auto& status_and_interface_name = HIDL_INVOKE(p2p_iface_, getName);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               status_and_interface_name.first.code);
@@ -206,7 +227,7 @@
 /*
  * GetType
  */
-TEST_F(SupplicantP2pIfaceHidlTest, GetType) {
+TEST_P(SupplicantP2pIfaceHidlTest, GetType) {
     const auto& status_and_interface_type = HIDL_INVOKE(p2p_iface_, getType);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               status_and_interface_type.first.code);
@@ -216,7 +237,7 @@
 /*
  * GetDeviceAddress
  */
-TEST_F(SupplicantP2pIfaceHidlTest, GetDeviceAddress) {
+TEST_P(SupplicantP2pIfaceHidlTest, GetDeviceAddress) {
     p2p_iface_->getDeviceAddress(
         [](const SupplicantStatus& status,
            const hidl_array<uint8_t, 6>& /* mac_addr */) {
@@ -227,7 +248,7 @@
 /*
  * SetSsidPostfix
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetSsidPostfix) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetSsidPostfix) {
     std::vector<uint8_t> ssid(kTestSsidPostfix,
                               kTestSsidPostfix + sizeof(kTestSsidPostfix));
     p2p_iface_->setSsidPostfix(ssid, [](const SupplicantStatus& status) {
@@ -238,7 +259,7 @@
 /*
  * Find
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Find) {
+TEST_P(SupplicantP2pIfaceHidlTest, Find) {
     p2p_iface_->find(kTestFindTimeout, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -247,7 +268,7 @@
 /*
  * StopFind
  */
-TEST_F(SupplicantP2pIfaceHidlTest, StopFind) {
+TEST_P(SupplicantP2pIfaceHidlTest, StopFind) {
     p2p_iface_->find(kTestFindTimeout, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -260,7 +281,7 @@
 /*
  * Flush
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Flush) {
+TEST_P(SupplicantP2pIfaceHidlTest, Flush) {
     p2p_iface_->flush([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -269,7 +290,7 @@
 /*
  * Connect
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Connect) {
+TEST_P(SupplicantP2pIfaceHidlTest, Connect) {
     p2p_iface_->connect(
         mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
         kTestConnectPin, false, false, kTestConnectGoIntent,
@@ -282,7 +303,7 @@
 /*
  * CancelConnect
  */
-TEST_F(SupplicantP2pIfaceHidlTest, CancelConnect) {
+TEST_P(SupplicantP2pIfaceHidlTest, CancelConnect) {
     p2p_iface_->connect(
         mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
         kTestConnectPin, false, false, kTestConnectGoIntent,
@@ -299,7 +320,7 @@
 /*
  * ProvisionDiscovery
  */
-TEST_F(SupplicantP2pIfaceHidlTest, ProvisionDiscovery) {
+TEST_P(SupplicantP2pIfaceHidlTest, ProvisionDiscovery) {
     p2p_iface_->provisionDiscovery(
         mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
         [](const SupplicantStatus& status) {
@@ -311,7 +332,7 @@
 /*
  * AddGroup
  */
-TEST_F(SupplicantP2pIfaceHidlTest, AddGroup) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddGroup) {
     p2p_iface_->addGroup(false, kTestNetworkId,
                          [](const SupplicantStatus& /* status */) {
                              // TODO: Figure out the initialization sequence for
@@ -324,7 +345,7 @@
 /*
  * RemoveGroup
  */
-TEST_F(SupplicantP2pIfaceHidlTest, RemoveGroup) {
+TEST_P(SupplicantP2pIfaceHidlTest, RemoveGroup) {
     // This is not going to work with fake values.
     EXPECT_NE(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(p2p_iface_, removeGroup, kTestGroupIfName).code);
@@ -333,7 +354,7 @@
 /*
  * Reject
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Reject) {
+TEST_P(SupplicantP2pIfaceHidlTest, Reject) {
     p2p_iface_->reject(mac_addr_, [](const SupplicantStatus& status) {
         // This is not going to work with fake values.
         EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
@@ -343,7 +364,7 @@
 /*
  * Invite
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Invite) {
+TEST_P(SupplicantP2pIfaceHidlTest, Invite) {
     p2p_iface_->invite(kTestGroupIfName, mac_addr_, peer_mac_addr_,
                        [](const SupplicantStatus& status) {
                            // This is not going to work with fake values.
@@ -355,7 +376,7 @@
 /*
  * Reinvoke
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Reinvoke) {
+TEST_P(SupplicantP2pIfaceHidlTest, Reinvoke) {
     p2p_iface_->reinvoke(
         kTestNetworkId, mac_addr_, [](const SupplicantStatus& status) {
             // This is not going to work with fake values.
@@ -367,7 +388,7 @@
 /*
  * ConfigureExtListen
  */
-TEST_F(SupplicantP2pIfaceHidlTest, ConfigureExtListen) {
+TEST_P(SupplicantP2pIfaceHidlTest, ConfigureExtListen) {
     p2p_iface_->configureExtListen(kTestExtListenPeriod, kTestExtListenInterval,
                                    [](const SupplicantStatus& status) {
                                        EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -378,7 +399,7 @@
 /*
  * SetListenChannel
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetListenChannel) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetListenChannel) {
     p2p_iface_->setListenChannel(
         kTestChannel, kTestOperatingClass, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -388,7 +409,7 @@
 /*
  * SetDisallowedFrequencies
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetDisallowedFrequencies) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetDisallowedFrequencies) {
     std::vector<ISupplicantP2pIface::FreqRange> ranges = {
         {kTestFreqRange[0], kTestFreqRange[1]}};
     p2p_iface_->setDisallowedFrequencies(
@@ -400,7 +421,7 @@
 /*
  * GetSsid
  */
-TEST_F(SupplicantP2pIfaceHidlTest, GetSsid) {
+TEST_P(SupplicantP2pIfaceHidlTest, GetSsid) {
     std::array<uint8_t, 6> mac_addr;
     memcpy(mac_addr.data(), kTestMacAddr, mac_addr.size());
     p2p_iface_->getSsid(mac_addr, [](const SupplicantStatus& status,
@@ -413,7 +434,7 @@
 /*
  * GetGroupCapability
  */
-TEST_F(SupplicantP2pIfaceHidlTest, GetGroupCapability) {
+TEST_P(SupplicantP2pIfaceHidlTest, GetGroupCapability) {
     std::array<uint8_t, 6> mac_addr;
     memcpy(mac_addr.data(), kTestMacAddr, mac_addr.size());
     p2p_iface_->getGroupCapability(
@@ -426,7 +447,7 @@
 /*
  * FlushServices
  */
-TEST_F(SupplicantP2pIfaceHidlTest, FlushServices) {
+TEST_P(SupplicantP2pIfaceHidlTest, FlushServices) {
     p2p_iface_->flushServices([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -435,7 +456,7 @@
 /*
  * SetMiracastMode
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetMiracastMode) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetMiracastMode) {
     p2p_iface_->setMiracastMode(ISupplicantP2pIface::MiracastMode::DISABLED,
                                 [](const SupplicantStatus& status) {
                                     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -456,7 +477,7 @@
 /*
  * SetGroupIdle
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetGroupIdle) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetGroupIdle) {
     // This is not going to work with fake values.
     EXPECT_NE(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(p2p_iface_, setGroupIdle, kTestGroupIfName,
@@ -467,7 +488,7 @@
 /*
  * SetPowerSave
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetPowerSave) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetPowerSave) {
     // This is not going to work with fake values.
     EXPECT_NE(
         SupplicantStatusCode::SUCCESS,
@@ -481,7 +502,7 @@
 /*
  * SetWpsDeviceName
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsDeviceName) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsDeviceName) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsDeviceName, kTestWpsDeviceName).code);
@@ -490,7 +511,7 @@
 /*
  * SetWpsDeviceType
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsDeviceType) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsDeviceType) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsDeviceType, kTestWpsDeviceType).code);
@@ -499,7 +520,7 @@
 /*
  * SetWpsManufacturer
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsManufacturer) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsManufacturer) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsManufacturer, kTestWpsManufacturer).code);
@@ -508,7 +529,7 @@
 /*
  * SetWpsModelName
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsModelName) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsModelName) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(p2p_iface_, setWpsModelName, kTestWpsModelName).code);
 }
@@ -516,7 +537,7 @@
 /*
  * SetWpsModelNumber
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsModelNumber) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsModelNumber) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsModelNumber, kTestWpsModelNumber).code);
@@ -525,7 +546,7 @@
 /*
  * SetWpsSerialNumber
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsSerialNumber) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsSerialNumber) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsSerialNumber, kTestWpsSerialNumber).code);
@@ -534,7 +555,7 @@
 /*
  * SetWpsConfigMethods
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsConfigMethods) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsConfigMethods) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsConfigMethods, kTestWpsConfigMethods)
@@ -548,7 +569,7 @@
  * This also tests that removeBonjourSerive() returns error when there is no
  * existing bonjour service with the same query data.
  */
-TEST_F(SupplicantP2pIfaceHidlTest, AddAndRemoveBonjourService) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddAndRemoveBonjourService) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(
                   p2p_iface_, addBonjourService,
@@ -584,7 +605,7 @@
  * This also tests that removeUpnpService() returns error when there is no
  * exsiting upnp service with the same service name.
  */
-TEST_F(SupplicantP2pIfaceHidlTest, AddAndRemoveUpnpService) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddAndRemoveUpnpService) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(p2p_iface_, addUpnpService, 0 /* version */,
                           kTestUpnpServiceName)
@@ -604,7 +625,7 @@
 /*
  * EnableWfd
  */
-TEST_F(SupplicantP2pIfaceHidlTest, EnableWfd) {
+TEST_P(SupplicantP2pIfaceHidlTest, EnableWfd) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(p2p_iface_, enableWfd, true).code);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -614,8 +635,17 @@
 /*
  * SetWfdDeviceInfo
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWfdDeviceInfo) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWfdDeviceInfo) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWfdDeviceInfo, kTestWfdDeviceInfo).code);
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantP2pIfaceHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            ISupplicant::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
index ec102d5..089b3cd 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -15,9 +15,12 @@
  */
 
 #include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIface.h>
 
 #include "supplicant_hidl_call_util.h"
@@ -30,12 +33,14 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIfaceCallback;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantNetworkId;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::V1_0::IWifi;
 
 namespace {
 constexpr uint8_t kTestMacAddr[] = {0x56, 0x67, 0x67, 0xf4, 0x56, 0x92};
@@ -61,24 +66,36 @@
 constexpr uint16_t kTestWpsConfigMethods = 0xffff;
 }  // namespace
 
-class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantStaIfaceHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        EXPECT_TRUE(turnOnExcessiveLogging());
-        sta_iface_ = getSupplicantStaIface();
+        wifi_instance_name_ = std::get<0>(GetParam());
+        supplicant_instance_name_ = std::get<1>(GetParam());
+        stopSupplicant(wifi_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                             supplicant_instance_name_);
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_iface_ = getSupplicantStaIface(supplicant_);
         ASSERT_NE(sta_iface_.get(), nullptr);
 
         memcpy(mac_addr_.data(), kTestMacAddr, mac_addr_.size());
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
+    virtual void TearDown() override { stopSupplicant(wifi_instance_name_); }
 
    protected:
+    bool isP2pOn_ = false;
+    sp<ISupplicant> supplicant_;
     // ISupplicantStaIface object used for all tests in this fixture.
     sp<ISupplicantStaIface> sta_iface_;
     // MAC address to use for various tests.
     std::array<uint8_t, 6> mac_addr_;
+    std::string wifi_instance_name_;
+    std::string supplicant_instance_name_;
 };
 
 class IfaceCallback : public ISupplicantStaIfaceCallback {
@@ -159,16 +176,19 @@
  * Ensures that an instance of the ISupplicantStaIface proxy object is
  * successfully created.
  */
-TEST(SupplicantStaIfaceHidlTestNoFixture, Create) {
-    startSupplicantAndWaitForHidlService();
-    EXPECT_NE(nullptr, getSupplicantStaIface().get());
-    stopSupplicant();
+TEST_P(SupplicantStaIfaceHidlTest, Create) {
+    stopSupplicant(wifi_instance_name_);
+    startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                         supplicant_instance_name_);
+    EXPECT_NE(nullptr, getSupplicantStaIface(
+                           getSupplicant(supplicant_instance_name_, isP2pOn_))
+                           .get());
 }
 
 /*
  * RegisterCallback
  */
-TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback) {
+TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback) {
     sta_iface_->registerCallback(
         new IfaceCallback(), [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -178,7 +198,7 @@
 /*
  * GetName
  */
-TEST_F(SupplicantStaIfaceHidlTest, GetName) {
+TEST_P(SupplicantStaIfaceHidlTest, GetName) {
     const auto& status_and_interface_name = HIDL_INVOKE(sta_iface_, getName);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               status_and_interface_name.first.code);
@@ -188,7 +208,7 @@
 /*
  * GetType
  */
-TEST_F(SupplicantStaIfaceHidlTest, GetType) {
+TEST_P(SupplicantStaIfaceHidlTest, GetType) {
     const auto& status_and_interface_type = HIDL_INVOKE(sta_iface_, getType);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               status_and_interface_type.first.code);
@@ -198,14 +218,15 @@
 /*
  * listNetworks.
  */
-TEST_F(SupplicantStaIfaceHidlTest, listNetworks) {
+TEST_P(SupplicantStaIfaceHidlTest, listNetworks) {
     sta_iface_->listNetworks([](const SupplicantStatus& status,
                                 const hidl_vec<SupplicantNetworkId>& ids) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
         EXPECT_EQ(0u, ids.size());
     });
 
-    sp<ISupplicantStaNetwork> sta_network = createSupplicantStaNetwork();
+    sp<ISupplicantStaNetwork> sta_network =
+        createSupplicantStaNetwork(supplicant_);
     EXPECT_NE(nullptr, sta_network.get());
 
     sta_iface_->listNetworks([](const SupplicantStatus& status,
@@ -218,7 +239,7 @@
 /*
  * Reassociate.
  */
-TEST_F(SupplicantStaIfaceHidlTest, Reassociate) {
+TEST_P(SupplicantStaIfaceHidlTest, Reassociate) {
     sta_iface_->reassociate([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -227,7 +248,7 @@
 /*
  * Reconnect.
  */
-TEST_F(SupplicantStaIfaceHidlTest, Reconnect) {
+TEST_P(SupplicantStaIfaceHidlTest, Reconnect) {
     sta_iface_->reconnect([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::FAILURE_IFACE_NOT_DISCONNECTED,
                   status.code);
@@ -237,7 +258,7 @@
 /*
  * Disconnect.
  */
-TEST_F(SupplicantStaIfaceHidlTest, Disconnect) {
+TEST_P(SupplicantStaIfaceHidlTest, Disconnect) {
     sta_iface_->disconnect([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -246,7 +267,7 @@
 /*
  * SetPowerSave.
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetPowerSave) {
+TEST_P(SupplicantStaIfaceHidlTest, SetPowerSave) {
     sta_iface_->setPowerSave(true, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -258,7 +279,7 @@
 /*
  * InitiateTdlsDiscover.
  */
-TEST_F(SupplicantStaIfaceHidlTest, InitiateTdlsDiscover) {
+TEST_P(SupplicantStaIfaceHidlTest, InitiateTdlsDiscover) {
     sta_iface_->initiateTdlsDiscover(
         mac_addr_, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -268,7 +289,7 @@
 /*
  * InitiateTdlsSetup.
  */
-TEST_F(SupplicantStaIfaceHidlTest, InitiateTdlsSetup) {
+TEST_P(SupplicantStaIfaceHidlTest, InitiateTdlsSetup) {
     sta_iface_->initiateTdlsSetup(
         mac_addr_, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -278,7 +299,7 @@
 /*
  * InitiateTdlsTeardown.
  */
-TEST_F(SupplicantStaIfaceHidlTest, InitiateTdlsTeardown) {
+TEST_P(SupplicantStaIfaceHidlTest, InitiateTdlsTeardown) {
     sta_iface_->initiateTdlsTeardown(
         mac_addr_, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -288,7 +309,7 @@
 /*
  * InitiateAnqpQuery.
  */
-TEST_F(SupplicantStaIfaceHidlTest, InitiateAnqpQuery) {
+TEST_P(SupplicantStaIfaceHidlTest, InitiateAnqpQuery) {
     std::vector<ISupplicantStaIface::AnqpInfoId> anqp_ids(
         kTestAnqpInfoIds, kTestAnqpInfoIds + sizeof(kTestAnqpInfoIds));
     std::vector<ISupplicantStaIface::Hs20AnqpSubtypes> hs_types(
@@ -304,7 +325,7 @@
 /*
  * InitiateHs20IconQuery.
  */
-TEST_F(SupplicantStaIfaceHidlTest, InitiateHs20IconQuery) {
+TEST_P(SupplicantStaIfaceHidlTest, InitiateHs20IconQuery) {
     sta_iface_->initiateHs20IconQuery(
         mac_addr_, kTestHs20IconFile, [](const SupplicantStatus& status) {
             // These requests will fail unless the BSSID mentioned is actually
@@ -316,7 +337,7 @@
 /*
  * GetMacAddress.
  */
-TEST_F(SupplicantStaIfaceHidlTest, GetMacAddress) {
+TEST_P(SupplicantStaIfaceHidlTest, GetMacAddress) {
     sta_iface_->getMacAddress([](const SupplicantStatus& status,
                                  const hidl_array<uint8_t, 6>& mac_addr) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -328,7 +349,7 @@
 /*
  * StartRxFilter.
  */
-TEST_F(SupplicantStaIfaceHidlTest, StartRxFilter) {
+TEST_P(SupplicantStaIfaceHidlTest, StartRxFilter) {
     sta_iface_->startRxFilter([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -337,7 +358,7 @@
 /*
  * StopRxFilter.
  */
-TEST_F(SupplicantStaIfaceHidlTest, StopRxFilter) {
+TEST_P(SupplicantStaIfaceHidlTest, StopRxFilter) {
     sta_iface_->stopRxFilter([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -346,7 +367,7 @@
 /*
  * AddRxFilter.
  */
-TEST_F(SupplicantStaIfaceHidlTest, AddRxFilter) {
+TEST_P(SupplicantStaIfaceHidlTest, AddRxFilter) {
     sta_iface_->addRxFilter(ISupplicantStaIface::RxFilterType::V4_MULTICAST,
                             [](const SupplicantStatus& status) {
                                 EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -362,7 +383,7 @@
 /*
  * RemoveRxFilter.
  */
-TEST_F(SupplicantStaIfaceHidlTest, RemoveRxFilter) {
+TEST_P(SupplicantStaIfaceHidlTest, RemoveRxFilter) {
     sta_iface_->removeRxFilter(ISupplicantStaIface::RxFilterType::V4_MULTICAST,
                                [](const SupplicantStatus& status) {
                                    EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -378,7 +399,7 @@
 /*
  * SetBtCoexistenceMode.
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetBtCoexistenceMode) {
+TEST_P(SupplicantStaIfaceHidlTest, SetBtCoexistenceMode) {
     sta_iface_->setBtCoexistenceMode(
         ISupplicantStaIface::BtCoexistenceMode::ENABLED,
         [](const SupplicantStatus& status) {
@@ -399,7 +420,7 @@
 /*
  * SetBtCoexistenceScanModeEnabled.
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetBtCoexistenceScanModeEnabled) {
+TEST_P(SupplicantStaIfaceHidlTest, SetBtCoexistenceScanModeEnabled) {
     sta_iface_->setBtCoexistenceScanModeEnabled(
         true, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -413,7 +434,7 @@
 /*
  * SetSuspendModeEnabled.
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetSuspendModeEnabled) {
+TEST_P(SupplicantStaIfaceHidlTest, SetSuspendModeEnabled) {
     sta_iface_->setSuspendModeEnabled(true, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -426,7 +447,7 @@
 /*
  * SetCountryCode.
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetCountryCode) {
+TEST_P(SupplicantStaIfaceHidlTest, SetCountryCode) {
     sta_iface_->setCountryCode(
         kTestCountryCode, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -436,7 +457,7 @@
 /*
  * SetWpsDeviceName
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsDeviceName) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsDeviceName) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsDeviceName, kTestWpsDeviceName).code);
@@ -445,7 +466,7 @@
 /*
  * SetWpsDeviceType
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsDeviceType) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsDeviceType) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsDeviceType, kTestWpsDeviceType).code);
@@ -454,7 +475,7 @@
 /*
  * SetWpsManufacturer
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsManufacturer) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsManufacturer) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsManufacturer, kTestWpsManufacturer).code);
@@ -463,7 +484,7 @@
 /*
  * SetWpsModelName
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsModelName) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsModelName) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_iface_, setWpsModelName, kTestWpsModelName).code);
 }
@@ -471,7 +492,7 @@
 /*
  * SetWpsModelNumber
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsModelNumber) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsModelNumber) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsModelNumber, kTestWpsModelNumber).code);
@@ -480,7 +501,7 @@
 /*
  * SetWpsSerialNumber
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsSerialNumber) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsSerialNumber) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsSerialNumber, kTestWpsSerialNumber).code);
@@ -489,7 +510,7 @@
 /*
  * SetWpsConfigMethods
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsConfigMethods) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsConfigMethods) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsConfigMethods, kTestWpsConfigMethods)
@@ -499,7 +520,7 @@
 /*
  * SetExternalSim
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetExternalSim) {
+TEST_P(SupplicantStaIfaceHidlTest, SetExternalSim) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_iface_, setExternalSim, true).code);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -509,7 +530,7 @@
 /*
  * AddExtRadioWork
  */
-TEST_F(SupplicantStaIfaceHidlTest, AddExtRadioWork) {
+TEST_P(SupplicantStaIfaceHidlTest, AddExtRadioWork) {
     const auto& status_and_radio_work_id =
         HIDL_INVOKE(sta_iface_, addExtRadioWork, kTestRadioWorkName,
                     kTestRadioWorkFrequency, kTestRadioWorkTimeout);
@@ -524,9 +545,18 @@
 /*
  * RemoveExtRadioWork
  */
-TEST_F(SupplicantStaIfaceHidlTest, RemoveExtRadioWork) {
+TEST_P(SupplicantStaIfaceHidlTest, RemoveExtRadioWork) {
     // This fails because there is no on going radio work with kTestRadioWorkId.
     EXPECT_NE(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, removeExtRadioWork, kTestRadioWorkId).code);
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaIfaceHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            ISupplicant::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
index 832dd41..52f77a1 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -16,14 +16,16 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "supplicant_hidl_call_util.h"
 #include "supplicant_hidl_test_utils.h"
+#include "wifi_hidl_test_utils.h"
 
 using ::android::sp;
 using ::android::hardware::hidl_array;
@@ -32,12 +34,14 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
 using ::android::hardware::wifi::supplicant::V1_0::
     ISupplicantStaNetworkCallback;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::V1_0::IWifi;
 
 namespace {
 constexpr char kTestSsidStr[] = "TestSsid1234";
@@ -74,37 +78,50 @@
      ISupplicantStaNetwork::PairwiseCipherMask::TKIP);
 }  // namespace
 
-class SupplicantStaNetworkHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantStaNetworkHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        EXPECT_TRUE(turnOnExcessiveLogging());
-        sta_network_ = createSupplicantStaNetwork();
+        wifi_instance_name_ = std::get<0>(GetParam());
+        supplicant_instance_name_ = std::get<1>(GetParam());
+        stopSupplicant(wifi_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                             supplicant_instance_name_);
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_network_ = createSupplicantStaNetwork(supplicant_);
         ASSERT_NE(sta_network_.get(), nullptr);
 
         ssid_.assign(kTestSsidStr, kTestSsidStr + strlen(kTestSsidStr));
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
+    virtual void TearDown() override { stopSupplicant(wifi_instance_name_); }
 
    protected:
     void removeNetwork() {
-      sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface();
-      ASSERT_NE(nullptr, sta_iface.get());
-      uint32_t net_id;
-      sta_network_->getId([&](const SupplicantStatus& status, int network_id) {
-              ASSERT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-              net_id = network_id;
-          });
-      sta_iface->removeNetwork(net_id, [](const SupplicantStatus& status) {
-              ASSERT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-          });
+        sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface(supplicant_);
+        ASSERT_NE(nullptr, sta_iface.get());
+        uint32_t net_id;
+        sta_network_->getId(
+            [&](const SupplicantStatus& status, int network_id) {
+                ASSERT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                net_id = network_id;
+            });
+        sta_iface->removeNetwork(net_id, [](const SupplicantStatus& status) {
+            ASSERT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
     }
 
+    bool isP2pOn_ = false;
+    sp<ISupplicant> supplicant_;
     // ISupplicantStaNetwork object used for all tests in this fixture.
     sp<ISupplicantStaNetwork> sta_network_;
     // SSID to use for various tests.
     std::vector<uint8_t> ssid_;
+    std::string wifi_instance_name_;
+    std::string supplicant_instance_name_;
 };
 
 class NetworkCallback : public ISupplicantStaNetworkCallback {
@@ -126,16 +143,20 @@
  * Ensures that an instance of the ISupplicantStaNetwork proxy object is
  * successfully created.
  */
-TEST(SupplicantStaNetworkHidlTestNoFixture, Create) {
-    startSupplicantAndWaitForHidlService();
-    EXPECT_NE(nullptr, createSupplicantStaNetwork().get());
-    stopSupplicant();
+TEST_P(SupplicantStaNetworkHidlTest, Create) {
+    stopSupplicant(wifi_instance_name_);
+    startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                         supplicant_instance_name_);
+    sp<ISupplicant> supplicant =
+        getSupplicant(supplicant_instance_name_, isP2pOn_);
+    EXPECT_TRUE(turnOnExcessiveLogging(supplicant));
+    EXPECT_NE(nullptr, createSupplicantStaNetwork(supplicant).get());
 }
 
 /*
  * RegisterCallback
  */
-TEST_F(SupplicantStaNetworkHidlTest, RegisterCallback) {
+TEST_P(SupplicantStaNetworkHidlTest, RegisterCallback) {
     sta_network_->registerCallback(
         new NetworkCallback(), [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -145,7 +166,7 @@
 /*
  * GetInterfaceName
  */
-TEST_F(SupplicantStaNetworkHidlTest, GetInterfaceName) {
+TEST_P(SupplicantStaNetworkHidlTest, GetInterfaceName) {
     const auto& status_and_interface_name =
         HIDL_INVOKE(sta_network_, getInterfaceName);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -156,7 +177,7 @@
 /*
  * GetType
  */
-TEST_F(SupplicantStaNetworkHidlTest, GetType) {
+TEST_P(SupplicantStaNetworkHidlTest, GetType) {
     const auto& status_and_interface_type = HIDL_INVOKE(sta_network_, getType);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               status_and_interface_type.first.code);
@@ -167,7 +188,7 @@
 /*
  * SetGetSsid
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetSsid) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetSsid) {
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -181,7 +202,7 @@
 /*
  * SetGetBssid
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetBssid) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetBssid) {
     std::array<uint8_t, 6> set_bssid;
     memcpy(set_bssid.data(), kTestBssid, set_bssid.size());
     sta_network_->setBssid(set_bssid, [](const SupplicantStatus& status) {
@@ -199,7 +220,7 @@
 /*
  * SetGetKeyMgmt
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt) {
     sta_network_->setKeyMgmt(kTestKeyMgmt, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -213,7 +234,7 @@
 /*
  * SetGetProto
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetProto) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetProto) {
     sta_network_->setProto(kTestProto, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -226,7 +247,7 @@
 /*
  * SetGetKeyAuthAlg
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetAuthAlg) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetAuthAlg) {
     sta_network_->setAuthAlg(kTestAuthAlg, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -240,7 +261,7 @@
 /*
  * SetGetGroupCipher
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher) {
     sta_network_->setGroupCipher(
         kTestGroupCipher, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -255,7 +276,7 @@
 /*
  * SetGetPairwiseCipher
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher) {
     sta_network_->setPairwiseCipher(
         kTestPairwiseCipher, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -270,7 +291,7 @@
 /*
  * SetGetPskPassphrase
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetPskPassphrase) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetPskPassphrase) {
     sta_network_->setPskPassphrase(
         kTestPskPassphrase, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -285,7 +306,7 @@
 /*
  * SetGetPsk
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetPsk) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetPsk) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, setPsk, kTestPsk).code);
     const auto& status_and_psk = HIDL_INVOKE(sta_network_, getPsk);
@@ -297,7 +318,7 @@
 /*
  * SetGetWepKeys
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetWepTxKeyIdx) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetWepTxKeyIdx) {
     sta_network_->setWepTxKeyIdx(
         kTestWepTxKeyIdx, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -312,7 +333,7 @@
 /*
  * SetGetWepKeys
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetWepKeys) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetWepKeys) {
     for (uint32_t i = 0;
          i < static_cast<uint32_t>(
                  ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM);
@@ -334,7 +355,7 @@
 /*
  * SetGetScanSsid
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetScanSsid) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetScanSsid) {
     sta_network_->setScanSsid(
         true, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -349,7 +370,7 @@
 /*
  * SetGetRequirePmf
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetRequirePmf) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetRequirePmf) {
     sta_network_->setRequirePmf(
         true, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -364,7 +385,7 @@
 /*
  * SetGetIdStr
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetIdStr) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetIdStr) {
     sta_network_->setIdStr(
         kTestIdStr, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -376,11 +397,10 @@
         });
 }
 
-
 /*
  * SetGetEapMethod
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapMethod) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapMethod) {
     ISupplicantStaNetwork::EapMethod set_eap_method =
         ISupplicantStaNetwork::EapMethod::PEAP;
     sta_network_->setEapMethod(
@@ -398,7 +418,7 @@
 /*
  * SetGetEapPhase2Method
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapPhase2Method) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapPhase2Method) {
     ISupplicantStaNetwork::EapMethod set_eap_method =
         ISupplicantStaNetwork::EapMethod::PEAP;
     sta_network_->setEapMethod(
@@ -422,7 +442,7 @@
 /*
  * SetGetEapIdentity
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapIdentity) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapIdentity) {
     std::vector<uint8_t> set_identity(kTestIdentity, kTestIdentity + sizeof(kTestIdentity));
     sta_network_->setEapIdentity(
         set_identity, [](const SupplicantStatus& status) {
@@ -438,7 +458,7 @@
 /*
  * SetGetEapAnonymousIdentity
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapAnonymousIdentity) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapAnonymousIdentity) {
     std::vector<uint8_t> set_identity(kTestIdentity, kTestIdentity + sizeof(kTestIdentity));
     sta_network_->setEapAnonymousIdentity(
         set_identity, [](const SupplicantStatus& status) {
@@ -454,7 +474,7 @@
 /*
  * SetGetEapPassword
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapPassword) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapPassword) {
     std::vector<uint8_t> set_eap_passwd(
         kTestEapPasswdStr, kTestEapPasswdStr + strlen(kTestEapPasswdStr));
     sta_network_->setEapPassword(
@@ -471,7 +491,7 @@
 /*
  * SetGetEapCACert
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapCACert) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapCACert) {
     sta_network_->setEapCACert(
         kTestEapCert, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -486,7 +506,7 @@
 /*
  * SetGetEapCAPath
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapCAPath) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapCAPath) {
     sta_network_->setEapCAPath(
         kTestEapCert, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -501,7 +521,7 @@
 /*
  * SetGetEapClientCert
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapClientCert) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapClientCert) {
     sta_network_->setEapClientCert(
         kTestEapCert, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -516,7 +536,7 @@
 /*
  * SetGetEapPrivateKeyId
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapPrivateKeyId) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapPrivateKeyId) {
     sta_network_->setEapPrivateKeyId(
         kTestEapPrivateKeyId, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -531,7 +551,7 @@
 /*
  * SetGetEapAltSubjectMatch
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapAltSubjectMatch) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapAltSubjectMatch) {
     sta_network_->setEapAltSubjectMatch(
         kTestEapMatch, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -546,7 +566,7 @@
 /*
  * SetGetEapSubjectMatch
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapSubjectMatch) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapSubjectMatch) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_network_, setEapSubjectMatch, kTestEapMatch).code);
@@ -561,7 +581,7 @@
 /*
  * SetGetEapDomainSuffixMatch
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapDomainSuffixMatch) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapDomainSuffixMatch) {
     sta_network_->setEapDomainSuffixMatch(
         kTestEapMatch, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -576,7 +596,7 @@
 /*
  * SetGetEapEngine
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapEngine) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapEngine) {
     sta_network_->setEapEngine(
         true, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -591,7 +611,7 @@
 /*
  * SetGetEapEngineID
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapEngineID) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapEngineID) {
     sta_network_->setEapEngineID(
         kTestEapEngineID, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -606,7 +626,7 @@
 /*
  * Enable
  */
-TEST_F(SupplicantStaNetworkHidlTest, Enable) {
+TEST_P(SupplicantStaNetworkHidlTest, Enable) {
     // wpa_supplicant doesn't perform any connection initiation
     // unless atleast the Ssid and Ket mgmt params are set.
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
@@ -633,7 +653,7 @@
 /*
  * Disable
  */
-TEST_F(SupplicantStaNetworkHidlTest, Disable) {
+TEST_P(SupplicantStaNetworkHidlTest, Disable) {
     // wpa_supplicant doesn't perform any connection initiation
     // unless atleast the Ssid and Ket mgmt params are set.
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
@@ -656,7 +676,7 @@
 /*
  * Select.
  */
-TEST_F(SupplicantStaNetworkHidlTest, Select) {
+TEST_P(SupplicantStaNetworkHidlTest, Select) {
     // wpa_supplicant doesn't perform any connection initiation
     // unless atleast the Ssid and Ket mgmt params are set.
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
@@ -679,7 +699,7 @@
 /*
  * SendNetworkEapSimGsmAuthResponse
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimGsmAuthResponse) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapSimGsmAuthResponse) {
     std::vector<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
         params;
     ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams param;
@@ -695,7 +715,7 @@
 /*
  * SendNetworkEapSimGsmAuthFailure
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimGsmAuthFailure) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapSimGsmAuthFailure) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, sendNetworkEapSimGsmAuthFailure).code);
 }
@@ -703,7 +723,7 @@
 /*
  * SendNetworkEapSimUmtsAuthResponse
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAuthResponse) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAuthResponse) {
     ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams params;
     params.res = std::vector<uint8_t>(kTestRes, kTestRes + sizeof(kTestRes));
     memcpy(params.ik.data(), kTestIk, params.ik.size());
@@ -717,7 +737,7 @@
 /*
  * SendNetworkEapSimUmtsAuthFailure
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAuthFailure) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAuthFailure) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, sendNetworkEapSimUmtsAuthFailure).code);
 }
@@ -725,7 +745,7 @@
 /*
  * SendNetworkEapSimUmtsAutsResponse
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAutsResponse) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAutsResponse) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, sendNetworkEapSimUmtsAutsResponse,
                           kTestAutParam)
@@ -735,7 +755,7 @@
 /*
  * SendNetworkEapIdentityResponse
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse) {
     sta_network_->sendNetworkEapIdentityResponse(
         std::vector<uint8_t>(kTestIdentity,
                              kTestIdentity + sizeof(kTestIdentity)),
@@ -747,7 +767,7 @@
 /*
  * SetUpdateIdentifier
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetUpdateIdentifier) {
+TEST_P(SupplicantStaNetworkHidlTest, SetUpdateIdentifier) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_network_, setUpdateIdentifier, kTestUpdateIdentifier)
@@ -757,7 +777,7 @@
 /*
  * SetProactiveKeyCaching
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetProactiveKeyCaching) {
+TEST_P(SupplicantStaNetworkHidlTest, SetProactiveKeyCaching) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, setProactiveKeyCaching, true).code);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -767,7 +787,7 @@
 /*
  * GetWpsNfcConfigurationToken
  */
-TEST_F(SupplicantStaNetworkHidlTest, GetWpsNfcConfigurationToken) {
+TEST_P(SupplicantStaNetworkHidlTest, GetWpsNfcConfigurationToken) {
     ASSERT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, setSsid, ssid_).code);
     ASSERT_EQ(SupplicantStatusCode::SUCCESS,
@@ -780,3 +800,12 @@
     EXPECT_EQ(SupplicantStatusCode::SUCCESS, status_and_token.first.code);
     EXPECT_FALSE(0 == status_and_token.second.size());
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaNetworkHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            ISupplicant::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.1/Android.bp b/wifi/supplicant/1.1/Android.bp
index 832d1ad..6d940d1 100644
--- a/wifi/supplicant/1.1/Android.bp
+++ b/wifi/supplicant/1.1/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/supplicant/1.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp
index 353ae4b..8457532 100644
--- a/wifi/supplicant/1.1/vts/functional/Android.bp
+++ b/wifi/supplicant/1.1/vts/functional/Android.bp
@@ -27,7 +27,6 @@
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
         "android.hardware.wifi@1.0",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
@@ -51,7 +50,6 @@
         "android.hardware.wifi.supplicant@1.1",
         "android.hardware.wifi@1.0",
         "android.hardware.wifi@1.1",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
diff --git a/wifi/supplicant/1.2/Android.bp b/wifi/supplicant/1.2/Android.bp
index c685022..185d2b8 100644
--- a/wifi/supplicant/1.2/Android.bp
+++ b/wifi/supplicant/1.2/Android.bp
@@ -21,4 +21,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp
index 1b970e1..b7949d1 100644
--- a/wifi/supplicant/1.2/vts/functional/Android.bp
+++ b/wifi/supplicant/1.2/vts/functional/Android.bp
@@ -29,7 +29,6 @@
         "android.hardware.wifi.supplicant@1.1",
         "android.hardware.wifi.supplicant@1.2",
         "android.hardware.wifi@1.0",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
@@ -54,7 +53,6 @@
         "android.hardware.wifi.supplicant@1.2",
         "android.hardware.wifi@1.0",
         "android.hardware.wifi@1.1",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
@@ -79,7 +77,6 @@
         "android.hardware.wifi.supplicant@1.2",
         "android.hardware.wifi@1.0",
         "android.hardware.wifi@1.1",
-        "libcrypto",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",