Merge qt-r1-dev-plus-aosp-without-vendor (5817612) into stage-aosp-master

Bug: 135460123
Change-Id: Ia07db5c8afeed7fe22a2b18d867a38390f910a81
Merged-In: Ibbd540dbb5baee46360d3fe9469212cfd8f550ba
diff --git a/Android.bp b/Android.bp
index 927e227..dd84737 100644
--- a/Android.bp
+++ b/Android.bp
@@ -24,6 +24,11 @@
         "VtsHalHidlTargetTestBase",
         "libhidl-gen-utils",
     ],
+
+    header_libs: [
+        "libhidl_gtest_helpers",
+    ],
+
     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: [
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/audio/common/all-versions/default/service/Android.mk b/audio/common/all-versions/default/service/Android.mk
index b57a1ae..236f1fd 100644
--- a/audio/common/all-versions/default/service/Android.mk
+++ b/audio/common/all-versions/default/service/Android.mk
@@ -34,11 +34,9 @@
     libcutils \
     libbinder \
     libhidlbase \
-    libhidltransport \
     liblog \
     libutils \
     libhardware \
-    libhwbinder \
     android.hardware.audio@2.0 \
     android.hardware.audio@4.0 \
     android.hardware.audio@5.0 \
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
index a1af3c4..000ce18 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -24,7 +24,6 @@
         "libfmq",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "android.hardware.audio.common-util",
diff --git a/audio/effect/all-versions/default/Android.bp b/audio/effect/all-versions/default/Android.bp
index f23a463..653b30c 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",
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/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/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/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index a11d452..3fd0539 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",
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/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/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/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/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/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/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/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/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/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/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/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.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/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/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/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.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/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 6e1bc8f..be8d7ca 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -426,7 +426,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.thermal</name>
-        <version>1.0-1</version>
+        <version>1.0</version>
         <version>2.0</version>
         <interface>
             <name>IThermal</name>
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/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/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/current.txt b/current.txt
index fbb9752..b7383ea 100644
--- a/current.txt
+++ b/current.txt
@@ -574,6 +574,7 @@
 # ABI preserving changes to HALs during Android R
 b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
 ad431c8de51c07934a068e3043d8dd0537ac4d3158627706628b123f42df48dc android.hardware.neuralnetworks@1.0::IPreparedModel
+fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice
 aafcc10cf04ab247e86d4582586c71c6b4c2b8c479241ffa7fe37deb659fc942 android.hardware.neuralnetworks@1.2::IPreparedModel
 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
 fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
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/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/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/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/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/software/Android.bp b/gatekeeper/1.0/software/Android.bp
index 148c989..24c81f6 100644
--- a/gatekeeper/1.0/software/Android.bp
+++ b/gatekeeper/1.0/software/Android.bp
@@ -15,7 +15,6 @@
         "libbase",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "liblog",
         "libcrypto",
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.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/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/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/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.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.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/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/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.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/health/1.0/default/Android.bp b/health/1.0/default/Android.bp
index 8fbb8c3..049e393 100644
--- a/health/1.0/default/Android.bp
+++ b/health/1.0/default/Android.bp
@@ -12,7 +12,6 @@
     shared_libs: [
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.health@1.0",
     ],
diff --git a/health/1.0/default/Android.mk b/health/1.0/default/Android.mk
index 199ab41..bbf37af 100644
--- a/health/1.0/default/Android.mk
+++ b/health/1.0/default/Android.mk
@@ -13,7 +13,6 @@
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     libhidlbase \
-    libhidltransport \
     liblog \
     libutils \
     android.hardware.health@1.0 \
@@ -39,7 +38,6 @@
     libbase \
     libutils \
     libhidlbase \
-    libhidltransport \
     android.hardware.health@1.0 \
 
 include $(BUILD_EXECUTABLE)
diff --git a/health/2.0/README.md b/health/2.0/README.md
index 58ea9e3..4ecfb9a 100644
--- a/health/2.0/README.md
+++ b/health/2.0/README.md
@@ -44,7 +44,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..1c455d3 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",
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/vts/functional/Android.bp b/health/storage/1.0/vts/functional/Android.bp
index b18e36f..87502f8 100644
--- a/health/storage/1.0/vts/functional/Android.bp
+++ b/health/storage/1.0/vts/functional/Android.bp
@@ -21,7 +21,6 @@
     static_libs: ["android.hardware.health.storage@1.0"],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
     ],
     test_suites: ["general-tests"],
 }
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/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/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/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/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/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 293c50c..9e6cce7 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -4339,75 +4339,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)));
+    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) {
     // 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);
     }
 }
 
@@ -4421,39 +4407,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) {
     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;
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/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/media/omx/1.0/vts/functional/common/Android.bp b/media/omx/1.0/vts/functional/common/Android.bp
index 5a79e55..cdc52fb 100644
--- a/media/omx/1.0/vts/functional/common/Android.bp
+++ b/media/omx/1.0/vts/functional/common/Android.bp
@@ -29,21 +29,6 @@
         "android.hidl.memory@1.0",
         "android.hardware.media.omx@1.0",
         "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
-        "android.hardware.graphics.common@1.0",
-        "android.hardware.graphics.common@1.1",
-        "android.hardware.graphics.common@1.2",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
-    ],
-    export_static_lib_headers: [
-        "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
-        "android.hardware.graphics.common@1.0",
-        "android.hardware.graphics.common@1.1",
-        "android.hardware.graphics.common@1.2",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
     ],
 }
 
@@ -55,12 +40,7 @@
     static_libs: [
         "VtsHalMediaOmxV1_0CommonUtil",
         "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
-        "android.hardware.graphics.common@1.0",
-        "android.hardware.graphics.common@1.1",
-        "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.graphics.common@1.0",
         "android.hardware.media.omx@1.0",
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
index 8d4c022..f299e36 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
@@ -22,11 +22,8 @@
 #include <android-base/logging.h>
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <android/hardware/graphics/mapper/2.0/types.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/types.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
@@ -34,9 +31,7 @@
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMapper.h>
 #include <android/hidl/memory/1.0/IMemory.h>
-
-#include <atomic>
-#include <variant>
+#include <cutils/atomic.h>
 
 using ::android::hardware::graphics::common::V1_0::BufferUsage;
 using ::android::hardware::graphics::common::V1_0::PixelFormat;
@@ -200,104 +195,67 @@
                             BufferInfo* buffer, uint32_t nFrameWidth,
                             uint32_t nFrameHeight, int32_t* nStride,
                             int format) {
-    struct AllocatorV2 : public GrallocV2 {
-        sp<IAllocator> mAllocator;
-        sp<IMapper> mMapper;
-        AllocatorV2(sp<IAllocator>&& allocator, sp<IMapper>&& mapper)
-              : mAllocator{std::move(allocator)}, mMapper{std::move(mapper)} {}
-        AllocatorV2() = default;
-    };
-    struct AllocatorV3 : public GrallocV3 {
-        sp<IAllocator> mAllocator;
-        sp<IMapper> mMapper;
-        AllocatorV3(sp<IAllocator>&& allocator, sp<IMapper>&& mapper)
-              : mAllocator{std::move(allocator)}, mMapper{std::move(mapper)} {}
-        AllocatorV3() = default;
-    };
-    std::variant<AllocatorV2, AllocatorV3> grallocVar;
+    android::hardware::media::omx::V1_0::Status status;
+    sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator =
+        android::hardware::graphics::allocator::V2_0::IAllocator::getService();
+    ASSERT_NE(nullptr, allocator.get());
 
-    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper2{};
-    sp<android::hardware::graphics::mapper::V3_0::IMapper> mapper3{};
-    sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator2{};
-    sp<android::hardware::graphics::allocator::V3_0::IAllocator> allocator3 =
-        android::hardware::graphics::allocator::V3_0::IAllocator::getService();
-    if (allocator3) {
-        mapper3 =
-            android::hardware::graphics::mapper::V3_0::IMapper::getService();
-        ASSERT_NE(nullptr, mapper3.get());
-        grallocVar.emplace<AllocatorV3>(std::move(allocator3), std::move(mapper3));
-    } else {
-        allocator2 =
-            android::hardware::graphics::allocator::V2_0::IAllocator::getService();
-        ASSERT_NE(nullptr, allocator2.get());
-        mapper2 =
-            android::hardware::graphics::mapper::V2_0::IMapper::getService();
-        ASSERT_NE(nullptr, allocator2.get());
-        grallocVar.emplace<AllocatorV2>(std::move(allocator2), std::move(mapper2));
-    }
+    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
+        android::hardware::graphics::mapper::V2_0::IMapper::getService();
+    ASSERT_NE(mapper.get(), nullptr);
 
-    android::hardware::media::omx::V1_0::Status status{};
-    uint64_t usage{};
-    ASSERT_TRUE(omxNode->getGraphicBufferUsage(
+    android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo
+        descriptorInfo;
+    uint32_t usage;
+
+    descriptorInfo.width = nFrameWidth;
+    descriptorInfo.height = nFrameHeight;
+    descriptorInfo.layerCount = 1;
+    descriptorInfo.format = static_cast<PixelFormat>(format);
+    descriptorInfo.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN);
+    omxNode->getGraphicBufferUsage(
         portIndex,
         [&status, &usage](android::hardware::media::omx::V1_0::Status _s,
                           uint32_t _n1) {
             status = _s;
             usage = _n1;
-        }).isOk());
-    ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+        });
+    if (status == android::hardware::media::omx::V1_0::Status::OK) {
+        descriptorInfo.usage |= usage;
+    }
 
-    static std::atomic_int32_t bufferIdCounter{0};
+    ::android::hardware::hidl_vec<uint32_t> descriptor;
+    android::hardware::graphics::mapper::V2_0::Error error;
+    mapper->createDescriptor(
+        descriptorInfo, [&error, &descriptor](
+                            android::hardware::graphics::mapper::V2_0::Error _s,
+                            ::android::hardware::hidl_vec<uint32_t> _n1) {
+            error = _s;
+            descriptor = _n1;
+        });
+    ASSERT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE);
 
-    std::visit([buffer, nFrameWidth, nFrameHeight, format, usage, nStride](auto&& gralloc) {
-            using Gralloc = std::remove_reference_t<decltype(gralloc)>;
-            using Descriptor = typename Gralloc::Descriptor;
-            using DescriptorInfo = typename Gralloc::DescriptorInfo;
-            using Error = typename Gralloc::Error;
-            using Format = typename Gralloc::Format;
-            using Usage = typename Gralloc::Usage;
-
-            Error error{};
-            Descriptor descriptor{};
-
-            DescriptorInfo descriptorInfo{};
-            descriptorInfo.width = nFrameWidth;
-            descriptorInfo.height = nFrameHeight;
-            descriptorInfo.layerCount = 1;
-            descriptorInfo.format = static_cast<Format>(format);
-            descriptorInfo.usage = usage | Usage(BufferUsage::CPU_READ_OFTEN);
-
-            gralloc.mMapper->createDescriptor(descriptorInfo,
-                    [&error, &descriptor](
-                        Error _s,
-                        const Descriptor& _n1) {
-                    error = _s;
-                    descriptor = _n1;
-                });
-            ASSERT_EQ(error, Error::NONE);
-
-            gralloc.mAllocator->allocate(
-                descriptor, 1,
-                [&](Error _s, uint32_t _n1,
-                    const ::android::hardware::hidl_vec<
-                        ::android::hardware::hidl_handle>& _n2) {
-                    ASSERT_EQ(Error::NONE, _s);
-                    *nStride = _n1;
-                    buffer->omxBuffer.nativeHandle = _n2[0];
-                    buffer->omxBuffer.attr.anwBuffer.width = nFrameWidth;
-                    buffer->omxBuffer.attr.anwBuffer.height = nFrameHeight;
-                    buffer->omxBuffer.attr.anwBuffer.stride = _n1;
-                    buffer->omxBuffer.attr.anwBuffer.format =
-                        static_cast<PixelFormat>(descriptorInfo.format);
-                    buffer->omxBuffer.attr.anwBuffer.usage =
-                        static_cast<uint32_t>(descriptorInfo.usage);
-                    buffer->omxBuffer.attr.anwBuffer.layerCount =
-                        descriptorInfo.layerCount;
-                    buffer->omxBuffer.attr.anwBuffer.id =
-                        (static_cast<uint64_t>(getpid()) << 32) |
-                        bufferIdCounter.fetch_add(1, std::memory_order_relaxed);
-                });
-        }, grallocVar);
+    static volatile int32_t nextId = 0;
+    uint64_t id = static_cast<uint64_t>(getpid()) << 32;
+    allocator->allocate(
+        descriptor, 1,
+        [&](android::hardware::graphics::mapper::V2_0::Error _s, uint32_t _n1,
+            const ::android::hardware::hidl_vec<
+                ::android::hardware::hidl_handle>& _n2) {
+            ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE,
+                      _s);
+            *nStride = _n1;
+            buffer->omxBuffer.nativeHandle = _n2[0];
+            buffer->omxBuffer.attr.anwBuffer.width = nFrameWidth;
+            buffer->omxBuffer.attr.anwBuffer.height = nFrameHeight;
+            buffer->omxBuffer.attr.anwBuffer.stride = _n1;
+            buffer->omxBuffer.attr.anwBuffer.format = descriptorInfo.format;
+            buffer->omxBuffer.attr.anwBuffer.usage = descriptorInfo.usage;
+            buffer->omxBuffer.attr.anwBuffer.layerCount =
+                descriptorInfo.layerCount;
+            buffer->omxBuffer.attr.anwBuffer.id =
+                id | static_cast<uint32_t>(android_atomic_inc(&nextId));
+        });
 }
 
 // allocate buffers needed on a component port
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
index 08af26b..1575ba2 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
@@ -22,16 +22,6 @@
 #endif
 
 #include <getopt.h>
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
-#include <android/hardware/graphics/common/1.0/types.h>
-#include <android/hardware/graphics/common/1.1/types.h>
-#include <android/hardware/graphics/common/1.2/types.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/2.0/types.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/types.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <utils/Condition.h>
 #include <utils/List.h>
@@ -298,36 +288,6 @@
 /*
  * common functions declarations
  */
-struct GrallocV2 {
-    using Format = android::hardware::graphics::common::V1_0::PixelFormat;
-    using Usage = android::hardware::hidl_bitfield<
-            android::hardware::graphics::common::V1_0::BufferUsage>;
-
-    using IAllocator = android::hardware::graphics::allocator::V2_0::IAllocator;
-
-    using IMapper = android::hardware::graphics::mapper::V2_0::IMapper;
-    using Error = android::hardware::graphics::mapper::V2_0::Error;
-    using Descriptor = android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-    using YCbCrLayout = android::hardware::graphics::mapper::V2_0::YCbCrLayout;
-    using DescriptorInfo = IMapper::BufferDescriptorInfo;
-    using Rect = IMapper::Rect;
-};
-
-struct GrallocV3 {
-    using Format = android::hardware::graphics::common::V1_2::PixelFormat;
-    using Usage = android::hardware::hidl_bitfield<
-            android::hardware::graphics::common::V1_2::BufferUsage>;
-
-    using IAllocator = android::hardware::graphics::allocator::V3_0::IAllocator;
-
-    using IMapper = android::hardware::graphics::mapper::V3_0::IMapper;
-    using Error = android::hardware::graphics::mapper::V3_0::Error;
-    using Descriptor = android::hardware::graphics::mapper::V3_0::BufferDescriptor;
-    using YCbCrLayout = android::hardware::graphics::mapper::V3_0::YCbCrLayout;
-    using DescriptorInfo = IMapper::BufferDescriptorInfo;
-    using Rect = IMapper::Rect;
-};
-
 Return<android::hardware::media::omx::V1_0::Status> setRole(
     sp<IOmxNode> omxNode, const char* role);
 
diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
index 2280cee..a740a80 100644
--- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
+++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
@@ -63,7 +63,6 @@
 #include <media_video_hidl_test_common.h>
 #include <system/window.h>
 #include <fstream>
-#include <variant>
 
 static ComponentTestEnvironment* gEnv = nullptr;
 
@@ -365,61 +364,6 @@
     return Void();
 };
 
-// Variant of mappers
-struct MapperV2 : public GrallocV2 {
-    sp<IMapper> mMapper;
-    MapperV2(sp<IMapper>&& mapper): mMapper{std::move(mapper)} {}
-    MapperV2() = default;
-    android::hardware::Return<void> lock(
-            void* buffer,
-            Usage usage,
-            const Rect& rect,
-            const android::hardware::hidl_handle& handle,
-            Error* error,
-            void** data) {
-        return mMapper->lock(buffer, usage, rect, handle,
-                             [error, data](Error e, void* d) {
-                                *error = e;
-                                *data = d;
-                             });
-    }
-};
-struct MapperV3 : public GrallocV3 {
-    sp<IMapper> mMapper;
-    MapperV3(sp<IMapper>&& mapper): mMapper{std::move(mapper)} {}
-    MapperV3() = default;
-    android::hardware::Return<void> lock(
-            void* buffer,
-            Usage usage,
-            const Rect& rect,
-            const android::hardware::hidl_handle& handle,
-            Error* error,
-            void** data) {
-        return mMapper->lock(buffer, usage, rect, handle,
-                             [error, data](Error e, void* d, int32_t, int32_t) {
-                                *error = e;
-                                *data = d;
-                             });
-    }
-};
-using MapperVar = std::variant<MapperV2, MapperV3>;
-// Initializes the MapperVar by trying services of different versions.
-bool initialize(MapperVar& mapperVar) {
-    sp<android::hardware::graphics::mapper::V3_0::IMapper> mapper3 =
-        android::hardware::graphics::mapper::V3_0::IMapper::getService();
-    if (mapper3) {
-        mapperVar.emplace<MapperV3>(std::move(mapper3));
-        return true;
-    }
-    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper2 =
-        android::hardware::graphics::mapper::V2_0::IMapper::getService();
-    if (mapper2) {
-        mapperVar.emplace<MapperV2>(std::move(mapper2));
-        return true;
-    }
-    return false;
-}
-
 // request VOP refresh
 void requestIDR(sp<IOmxNode> omxNode, OMX_U32 portIndex) {
     android::hardware::media::omx::V1_0::Status status;
@@ -630,166 +574,150 @@
 
 int colorFormatConversion(BufferInfo* buffer, void* buff, PixelFormat format,
                           std::ifstream& eleStream) {
-    MapperVar mapperVar;
-    if (!initialize(mapperVar)) {
-        EXPECT_TRUE(false) << "failed to obtain mapper service";
-        return 1;
+    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
+        android::hardware::graphics::mapper::V2_0::IMapper::getService();
+    EXPECT_NE(mapper.get(), nullptr);
+    if (mapper.get() == nullptr) return 1;
+
+    android::hardware::hidl_handle fence;
+    android::hardware::graphics::mapper::V2_0::IMapper::Rect rect;
+    android::hardware::graphics::mapper::V2_0::YCbCrLayout ycbcrLayout;
+    android::hardware::graphics::mapper::V2_0::Error error;
+    rect.left = 0;
+    rect.top = 0;
+    rect.width = buffer->omxBuffer.attr.anwBuffer.width;
+    rect.height = buffer->omxBuffer.attr.anwBuffer.height;
+
+    if (format == PixelFormat::YV12 || format == PixelFormat::YCRCB_420_SP ||
+        format == PixelFormat::YCBCR_420_888) {
+        mapper->lockYCbCr(
+            buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, fence,
+            [&](android::hardware::graphics::mapper::V2_0::Error _e,
+                android::hardware::graphics::mapper::V2_0::YCbCrLayout _n1) {
+                error = _e;
+                ycbcrLayout = _n1;
+            });
+        EXPECT_EQ(error,
+                  android::hardware::graphics::mapper::V2_0::Error::NONE);
+        if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
+            return 1;
+
+        int size = ((rect.width * rect.height * 3) >> 1);
+        char* img = new char[size];
+        if (img == nullptr) return 1;
+        eleStream.read(img, size);
+        if (eleStream.gcount() != size) {
+            delete[] img;
+            return 1;
+        }
+
+        char* imgTmp = img;
+        char* ipBuffer = static_cast<char*>(ycbcrLayout.y);
+        for (size_t y = rect.height; y > 0; --y) {
+            memcpy(ipBuffer, imgTmp, rect.width);
+            ipBuffer += ycbcrLayout.yStride;
+            imgTmp += rect.width;
+        }
+
+        if (format == PixelFormat::YV12)
+            EXPECT_EQ(ycbcrLayout.chromaStep, 1U);
+        else if (format == PixelFormat::YCRCB_420_SP)
+            EXPECT_EQ(ycbcrLayout.chromaStep, 2U);
+
+        ipBuffer = static_cast<char*>(ycbcrLayout.cb);
+        for (size_t y = rect.height >> 1; y > 0; --y) {
+            for (int32_t x = 0; x < (rect.width >> 1); ++x) {
+                ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
+            }
+            ipBuffer += ycbcrLayout.cStride;
+        }
+        ipBuffer = static_cast<char*>(ycbcrLayout.cr);
+        for (size_t y = rect.height >> 1; y > 0; --y) {
+            for (int32_t x = 0; x < (rect.width >> 1); ++x) {
+                ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
+            }
+            ipBuffer += ycbcrLayout.cStride;
+        }
+
+        delete[] img;
+
+        mapper->unlock(buff,
+                       [&](android::hardware::graphics::mapper::V2_0::Error _e,
+                           android::hardware::hidl_handle _n1) {
+                           error = _e;
+                           fence = _n1;
+                       });
+        EXPECT_EQ(error,
+                  android::hardware::graphics::mapper::V2_0::Error::NONE);
+        if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
+            return 1;
+    } else {
+        void* data;
+        mapper->lock(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, fence,
+                     [&](android::hardware::graphics::mapper::V2_0::Error _e,
+                         void* _n1) {
+                         error = _e;
+                         data = _n1;
+                     });
+        EXPECT_EQ(error,
+                  android::hardware::graphics::mapper::V2_0::Error::NONE);
+        if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
+            return 1;
+
+        if (format == PixelFormat::BGRA_8888) {
+            char* ipBuffer = static_cast<char*>(data);
+            for (size_t y = rect.height; y > 0; --y) {
+                eleStream.read(ipBuffer, rect.width * 4);
+                if (eleStream.gcount() != rect.width * 4) return 1;
+                ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4;
+            }
+        } else {
+            EXPECT_TRUE(false) << "un expected pixel format";
+            return 1;
+        }
+
+        mapper->unlock(buff,
+                       [&](android::hardware::graphics::mapper::V2_0::Error _e,
+                           android::hardware::hidl_handle _n1) {
+                           error = _e;
+                           fence = _n1;
+                       });
+        EXPECT_EQ(error,
+                  android::hardware::graphics::mapper::V2_0::Error::NONE);
+        if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
+            return 1;
     }
 
-    return std::visit([buffer, buff, format, &eleStream](auto&& mapper) -> int {
-            using Gralloc = std::remove_reference_t<decltype(mapper)>;
-            using Error = typename Gralloc::Error;
-            using Rect = typename Gralloc::Rect;
-            using Usage = typename Gralloc::Usage;
-            using YCbCrLayout = typename Gralloc::YCbCrLayout;
-
-            android::hardware::hidl_handle fence;
-            Rect rect;
-            YCbCrLayout ycbcrLayout;
-            Error error;
-            rect.left = 0;
-            rect.top = 0;
-            rect.width = buffer->omxBuffer.attr.anwBuffer.width;
-            rect.height = buffer->omxBuffer.attr.anwBuffer.height;
-
-            if (format == PixelFormat::YV12 || format == PixelFormat::YCRCB_420_SP ||
-                format == PixelFormat::YCBCR_420_888) {
-                mapper.mMapper->lockYCbCr(
-                        buff,
-                        static_cast<Usage>(
-                            buffer->omxBuffer.attr.anwBuffer.usage),
-                        rect,
-                        fence,
-                        [&](Error _e,
-                            const YCbCrLayout& _n1) {
-                            error = _e;
-                            ycbcrLayout = _n1;
-                        });
-                EXPECT_EQ(error, Error::NONE);
-                if (error != Error::NONE)
-                    return 1;
-
-                int size = ((rect.width * rect.height * 3) >> 1);
-                char* img = new char[size];
-                if (img == nullptr) return 1;
-                eleStream.read(img, size);
-                if (eleStream.gcount() != size) {
-                    delete[] img;
-                    return 1;
-                }
-
-                char* imgTmp = img;
-                char* ipBuffer = static_cast<char*>(ycbcrLayout.y);
-                for (size_t y = rect.height; y > 0; --y) {
-                    memcpy(ipBuffer, imgTmp, rect.width);
-                    ipBuffer += ycbcrLayout.yStride;
-                    imgTmp += rect.width;
-                }
-
-                if (format == PixelFormat::YV12)
-                    EXPECT_EQ(ycbcrLayout.chromaStep, 1U);
-                else if (format == PixelFormat::YCRCB_420_SP)
-                    EXPECT_EQ(ycbcrLayout.chromaStep, 2U);
-
-                ipBuffer = static_cast<char*>(ycbcrLayout.cb);
-                for (size_t y = rect.height >> 1; y > 0; --y) {
-                    for (int32_t x = 0; x < (rect.width >> 1); ++x) {
-                        ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
-                    }
-                    ipBuffer += ycbcrLayout.cStride;
-                }
-                ipBuffer = static_cast<char*>(ycbcrLayout.cr);
-                for (size_t y = rect.height >> 1; y > 0; --y) {
-                    for (int32_t x = 0; x < (rect.width >> 1); ++x) {
-                        ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
-                    }
-                    ipBuffer += ycbcrLayout.cStride;
-                }
-
-                delete[] img;
-
-                mapper.mMapper->unlock(buff,
-                               [&](Error _e,
-                                   const android::hardware::hidl_handle& _n1) {
-                                   error = _e;
-                                   fence = _n1;
-                               });
-                EXPECT_EQ(error, Error::NONE);
-                if (error != Error::NONE)
-                    return 1;
-            } else {
-                void* data;
-                mapper.lock(
-                        buff,
-                        buffer->omxBuffer.attr.anwBuffer.usage,
-                        rect,
-                        fence,
-                        &error,
-                        &data);
-                EXPECT_EQ(error, Error::NONE);
-                if (error != Error::NONE)
-                    return 1;
-
-                if (format == PixelFormat::BGRA_8888) {
-                    char* ipBuffer = static_cast<char*>(data);
-                    for (size_t y = rect.height; y > 0; --y) {
-                        eleStream.read(ipBuffer, rect.width * 4);
-                        if (eleStream.gcount() != rect.width * 4) return 1;
-                        ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4;
-                    }
-                } else {
-                    EXPECT_TRUE(false) << "un expected pixel format";
-                    return 1;
-                }
-
-                mapper.mMapper->unlock(
-                        buff,
-                        [&](Error _e, const android::hardware::hidl_handle& _n1) {
-                            error = _e;
-                            fence = _n1;
-                        });
-                EXPECT_EQ(error, Error::NONE);
-                if (error != Error::NONE)
-                    return 1;
-            }
-
-            return 0;
-        }, mapperVar);
+    return 0;
 }
 
 int fillGraphicBuffer(BufferInfo* buffer, PixelFormat format,
                       std::ifstream& eleStream) {
-    MapperVar mapperVar;
-    if (!initialize(mapperVar)) {
-        EXPECT_TRUE(false) << "failed to obtain mapper service";
+    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
+        android::hardware::graphics::mapper::V2_0::IMapper::getService();
+    EXPECT_NE(mapper.get(), nullptr);
+    if (mapper.get() == nullptr) return 1;
+
+    void* buff = nullptr;
+    android::hardware::graphics::mapper::V2_0::Error error;
+    mapper->importBuffer(
+        buffer->omxBuffer.nativeHandle,
+        [&](android::hardware::graphics::mapper::V2_0::Error _e, void* _n1) {
+            error = _e;
+            buff = _n1;
+        });
+    EXPECT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE);
+    if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
         return 1;
-    }
 
-    return std::visit([buffer, format, &eleStream](auto&& mapper) -> int {
-            using Gralloc = std::remove_reference_t<decltype(mapper)>;
-            using Error = typename Gralloc::Error;
+    if (colorFormatConversion(buffer, buff, format, eleStream)) return 1;
 
-            void* buff = nullptr;
-            Error error;
-            mapper.mMapper->importBuffer(
-                buffer->omxBuffer.nativeHandle,
-                [&](Error _e, void* _n1) {
-                    error = _e;
-                    buff = _n1;
-                });
-            EXPECT_EQ(error, Error::NONE);
-            if (error != Error::NONE)
-                return 1;
+    error = mapper->freeBuffer(buff);
+    EXPECT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE);
+    if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
+        return 1;
 
-            if (colorFormatConversion(buffer, buff, format, eleStream)) return 1;
-
-            error = mapper.mMapper->freeBuffer(buff);
-            EXPECT_EQ(error, Error::NONE);
-            if (error != Error::NONE)
-                return 1;
-
-            return 0;
-        }, mapperVar);
+    return 0;
 }
 
 int dispatchGraphicBuffer(sp<IOmxNode> omxNode,
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/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index a8406de..0af7f79 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -32,12 +32,11 @@
         "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",
     ],
 }
 
@@ -45,6 +44,7 @@
     name: "VtsHalNeuralNetworksV1_0TargetTestDefaults",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
+        "TestAssertions.cpp",
         "ValidateModel.cpp",
         "ValidateRequest.cpp",
         "VtsHalNeuralnetworks.cpp",
@@ -60,13 +60,12 @@
         "android.hidl.memory@1.0",
         "libgmock",
         "libhidlmemory",
+        "libneuralnetworks_generated_test_harness",
         "libneuralnetworks_utils",
         "VtsHalNeuralNetworksV1_0_utils",
     ],
     header_libs: [
         "libneuralnetworks_headers",
-        "libneuralnetworks_generated_test_harness_headers",
-        "libneuralnetworks_generated_tests",
     ],
     test_suites: ["general-tests"],
 }
@@ -76,7 +75,9 @@
     defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"],
     srcs: [
         "BasicTests.cpp",
-        ":VtsHalNeuralNetworksV1_0_all_generated_V1_0_tests",
+    ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
     ],
 }
 
@@ -85,7 +86,9 @@
     defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"],
     srcs: [
         "BasicTests.cpp",
-        ":VtsHalNeuralNetworksV1_0_all_generated_V1_0_tests",
+    ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
     ],
     cflags: [
         "-DPRESUBMIT_NOT_VTS",
diff --git a/neuralnetworks/1.0/vts/functional/BasicTests.cpp b/neuralnetworks/1.0/vts/functional/BasicTests.cpp
index 945c406..5727ca4 100644
--- a/neuralnetworks/1.0/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.0/vts/functional/BasicTests.cpp
@@ -18,12 +18,7 @@
 
 #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) {}
@@ -38,19 +33,14 @@
 // initialization
 TEST_F(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);
-        });
+            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);
+            });
     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/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 40d2f4c..33a6fa5 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -15,10 +15,12 @@
  */
 
 #include "GeneratedTestHarness.h"
+
 #include "1.0/Callbacks.h"
 #include "1.0/Utils.h"
 #include "MemoryUtils.h"
 #include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
 
 #include <android-base/logging.h>
 #include <android/hardware/neuralnetworks/1.0/IDevice.h>
@@ -28,197 +30,169 @@
 #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 V1_0 {
-namespace generated_tests {
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
-using ::android::hardware::neuralnetworks::V1_0::IDevice;
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Model;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
-using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::test_helper::compare;
-using ::test_helper::filter;
-using ::test_helper::for_all;
-using ::test_helper::MixedTyped;
-using ::test_helper::MixedTypedExample;
-using ::test_helper::resize_accordingly;
+using namespace test_helper;
+using hidl::memory::V1_0::IMemory;
+using implementation::ExecutionCallback;
+using 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)};
+}
 
 // Top level driver for models and examples generated by test_generator.py
 // Test driver for those generated from ml/nn/runtime/test/spec
-void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
-                           const std::vector<MixedTypedExample>& examples, float fpAtol,
-                           float fpRtol) {
-    const uint32_t INPUT = 0;
-    const uint32_t OUTPUT = 1;
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& 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;
+    // 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));
 
-        CHECK(inputs.float16Operands.empty()) << "float16 is not supported in 1.0";
+    // Retrieve execution status.
+    executionCallback->wait();
+    ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
 
-        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 results.
+    const std::vector<TestBuffer> outputs = getOutputBuffers(request);
 
-        MixedTyped test;  // holding test results
-
-        // Go through all outputs, initialize RequestArgument descriptors
-        resize_accordingly(golden, test);
-        for_all(golden, [&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)};
-        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};
-
-        // launch execution
-        sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-        ASSERT_NE(nullptr, executionCallback.get());
-        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());
-
-        // 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);
-    }
+    // We want "close-enough" results.
+    checkResults(testModel, outputs);
 }
 
-void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model,
-             std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
-    Model model = create_model();
+// Tag for the generated tests
+class GeneratedTest : public GeneratedTestBase {
+  protected:
+    void Execute(const TestModel& testModel) {
+        Model model = createModel(testModel);
 
-    // 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());
+        // 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));
+        // launch prepare model
+        sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+        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<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+        // retrieve prepared model
+        preparedModelCallback->wait();
+        ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+        sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
 
-    // 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();
+        // 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, testModel);
     }
-    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, fpAtol, fpRtol);
+TEST_P(GeneratedTest, Test) {
+    Execute(*mTestModel);
 }
 
-}  // namespace generated_tests
-}  // namespace V1_0
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+INSTANTIATE_GENERATED_TEST(GeneratedTest,
+                           [](const TestModel& testModel) { return !testModel.expectFailure; });
+
+}  // 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 337eb0f..a42f271 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
@@ -19,22 +19,41 @@
 
 #include <android/hardware/neuralnetworks/1.0/IDevice.h>
 #include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace generated_tests {
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-using ::test_helper::MixedTypedExample;
+class GeneratedTestBase
+    : public NeuralnetworksHidlTest,
+      public ::testing::WithParamInterface<test_helper::TestModelManager::TestParam> {
+  protected:
+    void SetUp() override {
+        NeuralnetworksHidlTest::SetUp();
+        ASSERT_NE(mTestModel, nullptr);
+    }
 
-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);
+    const test_helper::TestModel* mTestModel = GetParam().second;
+};
 
-}  // namespace generated_tests
-}  // namespace V1_0
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                          \
+    INSTANTIATE_TEST_SUITE_P(                                                                  \
+            TestGenerated, TestSuite,                                                          \
+            ::testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \
+            [](const auto& info) { return info.param.first; })
+
+// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp.
+// TODO: Clean up the hierarchy for ValidationTest.
+class ValidationTest : public GeneratedTestBase {
+  protected:
+    void validateEverything(const Model& model, const Request& request);
+
+  private:
+    void validateModel(const Model& model);
+    void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request);
+};
+
+Model createModel(const ::test_helper::TestModel& testModel);
+
+}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
 
 #endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.h b/neuralnetworks/1.0/vts/functional/GeneratedTests.h
deleted file mode 100644
index 5cabf68..0000000
--- a/neuralnetworks/1.0/vts/functional/GeneratedTests.h
+++ /dev/null
@@ -1,35 +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.
- */
-
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-#include "GeneratedTestHarness.h"
-#include "MemoryUtils.h"
-#include "TestHarness.h"
-#include "VtsHalNeuralnetworks.h"
-
-namespace android::hardware::neuralnetworks::V1_0::vts::functional {
-
-std::vector<Request> createRequests(const std::vector<::test_helper::MixedTypedExample>& examples);
-
-}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
-
-namespace android::hardware::neuralnetworks::V1_0::generated_tests {
-
-using namespace android::hardware::neuralnetworks::V1_0::vts::functional;
-
-}  // namespace android::hardware::neuralnetworks::V1_0::generated_tests
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
index 521e524..5de99fd 100644
--- a/neuralnetworks/1.0/vts/functional/Utils.cpp
+++ b/neuralnetworks/1.0/vts/functional/Utils.cpp
@@ -14,47 +14,106 @@
  * limitations under the License.
  */
 
-#include "GeneratedTestHarness.h"
+#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 <cstring>
-#include <map>
+#include <algorithm>
 #include <vector>
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
+namespace android::hardware::neuralnetworks {
 
-using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
-using ::test_helper::for_each;
-using ::test_helper::MixedTyped;
+using namespace test_helper;
+using hidl::memory::V1_0::IMemory;
+using V1_0::DataLocation;
+using V1_0::Request;
+using V1_0::RequestArgument;
 
-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);
-    });
+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)};
 }
 
-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");
+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;
 }
 
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks
diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
index 72c4a2b..9854395 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
@@ -16,19 +16,13 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
+#include "1.0/Callbacks.h"
+#include "GeneratedTestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
-#include "1.0/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_0::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using implementation::PreparedModelCallback;
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
@@ -37,9 +31,9 @@
     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());
 }
 
@@ -48,7 +42,6 @@
     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));
@@ -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,10 +107,10 @@
 ///////////////////////// 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) {
@@ -210,7 +203,7 @@
 static void mutateOperandZeroPointTest(const sp<IDevice>& device, const V1_0::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:
@@ -303,10 +296,10 @@
 ///////////////////////// 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) {
@@ -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);
             });
         }
     }
@@ -470,7 +463,7 @@
 static void addOperationOutputTest(const sp<IDevice>& device, const V1_0::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,9 +491,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 058eb25..d8f3e65 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
@@ -16,27 +16,13 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
 #include "1.0/Callbacks.h"
-#include "MemoryUtils.h"
-#include "TestHarness.h"
+#include "GeneratedTestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-using ::android::hardware::neuralnetworks::V1_0::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 /////////////////////////
 
@@ -50,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));
@@ -102,108 +87,10 @@
 
 ///////////////////////////// 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 ValidationTest::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 95b7ad3..9ee4e37 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
@@ -17,21 +17,18 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include "VtsHalNeuralnetworks.h"
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "GeneratedTestHarness.h"
+#include "TestHarness.h"
 
 #include <android-base/logging.h>
 
-#include "1.0/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_0::implementation::PreparedModelCallback;
-
-static void createPreparedModel(const sp<IDevice>& device, const V1_0::Model& model,
+static void createPreparedModel(const sp<IDevice>& device, const Model& model,
                                 sp<IPreparedModel>* preparedModel) {
     ASSERT_NE(nullptr, preparedModel);
 
@@ -48,7 +45,6 @@
 
     // 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));
@@ -79,10 +75,6 @@
 }
 
 // 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
@@ -95,14 +87,8 @@
 }
 
 // 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 =
@@ -117,29 +103,30 @@
 }
 
 void NeuralnetworksHidlTest::TearDown() {
-    device = nullptr;
     ::testing::VtsHalHidlTargetTestBase::TearDown();
 }
 
-void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
+void ValidationTest::validateEverything(const Model& model, const Request& request) {
     validateModel(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
+TEST_P(ValidationTest, Test) {
+    const Model model = createModel(*mTestModel);
+    const Request request = createRequest(*mTestModel);
+    ASSERT_FALSE(mTestModel->expectFailure);
+    validateEverything(model, request);
+}
+
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+
+}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
 
 namespace android::hardware::neuralnetworks::V1_0 {
 
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
index c32a91d..fa9ad3b 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
@@ -28,20 +28,16 @@
 #include <iostream>
 #include <vector>
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
+#include "TestHarness.h"
+
+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;
+    NeuralnetworksHidlEnvironment() = default;
 
-   public:
+  public:
     static NeuralnetworksHidlEnvironment* getInstance();
     void registerTestServices() override;
 };
@@ -50,36 +46,17 @@
 class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase {
     DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
 
-   public:
-    NeuralnetworksHidlTest();
-    ~NeuralnetworksHidlTest() override;
+  public:
+    NeuralnetworksHidlTest() = default;
     void SetUp() override;
     void TearDown() override;
 
-   protected:
-    sp<IDevice> device;
+  protected:
+    const sp<IDevice> device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
+            NeuralnetworksHidlEnvironment::getInstance());
 };
 
-// Tag for the validation tests
-class ValidationTest : public NeuralnetworksHidlTest {
-   protected:
-     void validateEverything(const Model& model, const std::vector<Request>& request);
-
-   private:
-     void validateModel(const Model& model);
-     void validateRequests(const sp<IPreparedModel>& preparedModel,
-                           const std::vector<Request>& requests);
-};
-
-// Tag for the generated tests
-class GeneratedTest : public NeuralnetworksHidlTest {};
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_0
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
 
 namespace android::hardware::neuralnetworks::V1_0 {
 
diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
index b270c20..274cb58 100644
--- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
@@ -17,40 +17,39 @@
 #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 <vector>
 #include "TestHarness.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
+namespace android::hardware::neuralnetworks {
 
-void copy_back(::test_helper::MixedTyped* dst, const std::vector<V1_0::RequestArgument>& ra,
-               char* src);
+// 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) {
-    if (vec) {
-        std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
-        vec->resize(vec->size() - 1);
-    }
+    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) {
-    // assume vec is valid
+    CHECK(vec != nullptr);
     const uint32_t index = vec->size();
     vec->resize(index + 1);
     (*vec)[index] = value;
     return index;
 }
 
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks
 
 #endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 1b31008..c197e6d 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -18,6 +18,7 @@
     name: "VtsHalNeuralNetworksV1_1TargetTestDefaults",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
+        "TestAssertions.cpp",
         "ValidateModel.cpp",
         "ValidateRequest.cpp",
         "VtsHalNeuralnetworks.cpp",
@@ -34,33 +35,25 @@
         "android.hidl.memory@1.0",
         "libgmock",
         "libhidlmemory",
+        "libneuralnetworks_generated_test_harness",
         "libneuralnetworks_utils",
         "VtsHalNeuralNetworksV1_0_utils",
     ],
     header_libs: [
         "libneuralnetworks_headers",
-        "libneuralnetworks_generated_test_harness_headers",
-        "libneuralnetworks_generated_tests",
     ],
     test_suites: ["general-tests"],
 }
 
-// Tests for V1_0 models using the V1_1 HAL.
-cc_test {
-    name: "VtsHalNeuralnetworksV1_1CompatV1_0TargetTest",
-    defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"],
-    srcs: [
-        ":VtsHalNeuralNetworksV1_1_all_generated_V1_0_tests",
-    ],
-}
-
-// Tests for V1_1 models.
 cc_test {
     name: "VtsHalNeuralnetworksV1_1TargetTest",
     defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"],
     srcs: [
         "BasicTests.cpp",
-        ":VtsHalNeuralNetworksV1_1_all_generated_V1_1_tests",
+    ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+        "neuralnetworks_generated_V1_1_example",
     ],
 }
 
@@ -69,7 +62,10 @@
     defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"],
     srcs: [
         "BasicTests.cpp",
-        ":VtsHalNeuralNetworksV1_1_all_generated_V1_1_tests",
+    ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+        "neuralnetworks_generated_V1_1_example",
     ],
     cflags: [
         "-DPRESUBMIT_NOT_VTS",
diff --git a/neuralnetworks/1.1/vts/functional/BasicTests.cpp b/neuralnetworks/1.1/vts/functional/BasicTests.cpp
index ed59a2d..c239c51 100644
--- a/neuralnetworks/1.1/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.1/vts/functional/BasicTests.cpp
@@ -18,12 +18,10 @@
 
 #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) {}
@@ -38,21 +36,16 @@
 // initialization
 TEST_F(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);
-        });
+            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);
+            });
     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
index e7d59ec..6ed5bc1 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
@@ -24,211 +24,183 @@
 #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 {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace generated_tests {
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
 
-using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
-using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference;
-using ::android::hardware::neuralnetworks::V1_1::IDevice;
-using ::android::hardware::neuralnetworks::V1_1::Model;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::test_helper::compare;
-using ::test_helper::filter;
-using ::test_helper::for_all;
-using ::test_helper::MixedTyped;
-using ::test_helper::MixedTypedExample;
-using ::test_helper::resize_accordingly;
+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 EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
-                           const std::vector<MixedTypedExample>& examples,
-                           bool hasRelaxedFloat32Model, float fpAtol, float fpRtol) {
-    const uint32_t INPUT = 0;
-    const uint32_t OUTPUT = 1;
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& 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;
+    // 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));
 
-        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;
-        }
+    // Retrieve execution status.
+    executionCallback->wait();
+    ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
 
-        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 results.
+    const std::vector<TestBuffer> outputs = getOutputBuffers(request);
 
-        MixedTyped test;  // holding test results
-
-        // Go through all outputs, initialize RequestArgument descriptors
-        resize_accordingly(golden, test);
-        for_all(golden, [&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)};
-        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};
-
-        // launch execution
-        sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-        ASSERT_NE(nullptr, executionCallback.get());
-        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());
-
-        // 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);
-    }
+    // We want "close-enough" results.
+    checkResults(testModel, outputs);
 }
 
-void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model,
-             std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
-    Model model = create_model();
+// Tag for the generated tests
+class GeneratedTest : public GeneratedTestBase {
+  protected:
+    void Execute(const TestModel& testModel) {
+        Model model = createModel(testModel);
 
-    // 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());
+        // 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));
+        // launch prepare model
+        sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+        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<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+        // retrieve prepared model
+        preparedModelCallback->wait();
+        ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+        sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
 
-    // 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();
+        // 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, testModel);
     }
-    EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
-    ASSERT_NE(nullptr, preparedModel.get());
+};
 
-    EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f);
+TEST_P(GeneratedTest, Test) {
+    Execute(*mTestModel);
 }
 
-}  // namespace generated_tests
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+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
index 64b88dd..7cb9bdc 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
@@ -18,25 +18,43 @@
 #define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H
 
 #include <android/hardware/neuralnetworks/1.1/IDevice.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
-#include <functional>
-#include <vector>
 #include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace generated_tests {
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
 
-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<::test_helper::MixedTypedExample>& examples);
+class GeneratedTestBase
+    : public NeuralnetworksHidlTest,
+      public ::testing::WithParamInterface<test_helper::TestModelManager::TestParam> {
+  protected:
+    void SetUp() override {
+        NeuralnetworksHidlTest::SetUp();
+        ASSERT_NE(mTestModel, nullptr);
+    }
 
-}  // namespace generated_tests
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+    const test_helper::TestModel* mTestModel = GetParam().second;
+};
+
+#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                          \
+    INSTANTIATE_TEST_SUITE_P(                                                                  \
+            TestGenerated, TestSuite,                                                          \
+            ::testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \
+            [](const auto& info) { return info.param.first; })
+
+// Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp.
+// TODO: Clean up the hierarchy for ValidationTest.
+class ValidationTest : public GeneratedTestBase {
+  protected:
+    void validateEverything(const Model& model, const V1_0::Request& request);
+
+  private:
+    void validateModel(const Model& model);
+    void validateRequest(const sp<V1_0::IPreparedModel>& preparedModel,
+                         const V1_0::Request& request);
+};
+
+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.h b/neuralnetworks/1.1/vts/functional/GeneratedTests.h
deleted file mode 100644
index 80442bf..0000000
--- a/neuralnetworks/1.1/vts/functional/GeneratedTests.h
+++ /dev/null
@@ -1,38 +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.
- */
-
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-#include "GeneratedTestHarness.h"
-#include "MemoryUtils.h"
-#include "TestHarness.h"
-#include "VtsHalNeuralnetworks.h"
-
-namespace android::hardware::neuralnetworks::V1_1::vts::functional {
-
-std::vector<Request> createRequests(const std::vector<::test_helper::MixedTypedExample>& examples);
-
-}  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
-
-namespace android::hardware::neuralnetworks::V1_1::generated_tests {
-
-using namespace android::hardware::neuralnetworks::V1_1::vts::functional;
-
-using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-
-}  // namespace android::hardware::neuralnetworks::V1_1::generated_tests
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 fb80d13..e617219 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
@@ -18,20 +18,17 @@
 
 #include "1.0/Callbacks.h"
 #include "1.0/Utils.h"
+#include "GeneratedTestHarness.h"
 #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 ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Operand;
-using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
-using ::android::hardware::neuralnetworks::V1_0::OperandType;
-using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using V1_0::ErrorStatus;
+using V1_0::IPreparedModel;
+using V1_0::Operand;
+using V1_0::OperandLifeTime;
+using V1_0::OperandType;
+using V1_0::implementation::PreparedModelCallback;
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
@@ -51,7 +48,6 @@
     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);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
@@ -483,8 +479,9 @@
     for (int32_t preference : invalidExecutionPreferences) {
         const std::string message =
                 "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
-        validate(device, message, model, [](Model*) {},
-                 static_cast<ExecutionPreference>(preference));
+        validate(
+                device, message, model, [](Model*) {},
+                static_cast<ExecutionPreference>(preference));
     }
 }
 
@@ -508,9 +505,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 c549728..a4e4ade 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
@@ -16,32 +16,17 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
 #include "1.0/Callbacks.h"
 #include "1.0/Utils.h"
-#include "MemoryUtils.h"
-#include "TestHarness.h"
+#include "GeneratedTestHarness.h"
 #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 ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
-using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_1::IPreparedModel;
-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 /////////////////////////
 
@@ -55,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));
@@ -87,108 +71,10 @@
 
 ///////////////////////////// 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 ValidationTest::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 12bdd3f..2c1a839 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
@@ -17,21 +17,21 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include "VtsHalNeuralnetworks.h"
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "GeneratedTestHarness.h"
+#include "TestHarness.h"
 
 #include <android-base/logging.h>
 
-#include "1.0/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_0::implementation::PreparedModelCallback;
-
-static void createPreparedModel(const sp<IDevice>& device, const V1_1::Model& model,
+static void createPreparedModel(const sp<IDevice>& device, const Model& model,
                                 sp<IPreparedModel>* preparedModel) {
     ASSERT_NE(nullptr, preparedModel);
 
@@ -48,7 +48,6 @@
 
     // 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());
@@ -80,10 +79,6 @@
 }
 
 // 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
@@ -96,14 +91,8 @@
 }
 
 // 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 =
@@ -118,11 +107,10 @@
 }
 
 void NeuralnetworksHidlTest::TearDown() {
-    device = nullptr;
     ::testing::VtsHalHidlTargetTestBase::TearDown();
 }
 
-void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
+void ValidationTest::validateEverything(const Model& model, const Request& request) {
     validateModel(model);
 
     // create IPreparedModel
@@ -132,15 +120,19 @@
         return;
     }
 
-    validateRequests(preparedModel, requests);
+    validateRequest(preparedModel, request);
 }
 
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+TEST_P(ValidationTest, Test) {
+    const Model model = createModel(*mTestModel);
+    const Request request = createRequest(*mTestModel);
+    ASSERT_FALSE(mTestModel->expectFailure);
+    validateEverything(model, request);
+}
+
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+
+}  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
 
 namespace android::hardware::neuralnetworks::V1_0 {
 
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index 3156784..3d6f2ea 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
@@ -29,28 +29,16 @@
 #include <iostream>
 #include <vector>
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
+#include "TestHarness.h"
 
-using V1_0::DeviceStatus;
-using V1_0::ErrorStatus;
-using V1_0::IPreparedModel;
-using V1_0::Operand;
-using V1_0::OperandType;
-using V1_0::Request;
-
-namespace vts {
-namespace functional {
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
 
 // A class for test environment setup
 class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
     DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
-    NeuralnetworksHidlEnvironment();
-    ~NeuralnetworksHidlEnvironment() override;
+    NeuralnetworksHidlEnvironment() = default;
 
-   public:
+  public:
     static NeuralnetworksHidlEnvironment* getInstance();
     void registerTestServices() override;
 };
@@ -59,36 +47,17 @@
 class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase {
     DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
 
-   public:
-    NeuralnetworksHidlTest();
-    ~NeuralnetworksHidlTest() override;
+  public:
+    NeuralnetworksHidlTest() = default;
     void SetUp() override;
     void TearDown() override;
 
-   protected:
-    sp<IDevice> device;
+  protected:
+    const sp<IDevice> device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
+            NeuralnetworksHidlEnvironment::getInstance());
 };
 
-// Tag for the validation tests
-class ValidationTest : public NeuralnetworksHidlTest {
-   protected:
-     void validateEverything(const Model& model, const std::vector<Request>& request);
-
-   private:
-     void validateModel(const Model& model);
-     void validateRequests(const sp<IPreparedModel>& preparedModel,
-                           const std::vector<Request>& requests);
-};
-
-// Tag for the generated tests
-class GeneratedTest : public NeuralnetworksHidlTest {};
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
 
 namespace android::hardware::neuralnetworks::V1_0 {
 
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/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 301ca5d..40ca809 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -18,6 +18,7 @@
     name: "VtsHalNeuralNetworksV1_2TargetTestDefaults",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
+        "TestAssertions.cpp",
         "ValidateModel.cpp",
         "ValidateRequest.cpp",
         "VtsHalNeuralnetworks.cpp",
@@ -37,48 +38,29 @@
         "android.hidl.memory@1.0",
         "libgmock",
         "libhidlmemory",
+        "libneuralnetworks_generated_test_harness",
         "libneuralnetworks_utils",
         "VtsHalNeuralNetworksV1_0_utils",
     ],
     header_libs: [
         "libneuralnetworks_headers",
-        "libneuralnetworks_generated_test_harness_headers",
-        "libneuralnetworks_generated_tests",
     ],
     test_suites: ["general-tests"],
 }
 
-// Tests for V1_0 models using the V1_2 HAL.
-cc_test {
-    name: "VtsHalNeuralnetworksV1_2CompatV1_0TargetTest",
-    defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"],
-    srcs: [
-        ":VtsHalNeuralNetworksV1_2_all_generated_V1_0_tests",
-        "ValidateBurst.cpp",
-    ],
-}
-
-// Tests for V1_1 models using the V1_2 HAL.
-cc_test {
-    name: "VtsHalNeuralnetworksV1_2CompatV1_1TargetTest",
-    defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"],
-    srcs: [
-        ":VtsHalNeuralNetworksV1_2_all_generated_V1_1_tests",
-        "ValidateBurst.cpp",
-    ],
-}
-
-// Tests for V1_2 models.
 cc_test {
     name: "VtsHalNeuralnetworksV1_2TargetTest",
     defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"],
     srcs: [
         "BasicTests.cpp",
-        ":VtsHalNeuralNetworksV1_2_all_generated_V1_2_tests",
         "CompilationCachingTests.cpp",
-        ":VtsHalNeuralNetworksV1_2_mobilenets", // CompilationCachingTests depend on MobileNets.
         "ValidateBurst.cpp",
     ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+        "neuralnetworks_generated_V1_1_example",
+        "neuralnetworks_generated_V1_2_example",
+    ],
 }
 
 cc_test {
@@ -86,9 +68,14 @@
     defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"],
     srcs: [
         "BasicTests.cpp",
-        ":VtsHalNeuralNetworksV1_2_all_generated_V1_2_tests",
+        "CompilationCachingTests.cpp",
         "ValidateBurst.cpp",
     ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+        "neuralnetworks_generated_V1_1_example",
+        "neuralnetworks_generated_V1_2_example",
+    ],
     cflags: [
         "-DPRESUBMIT_NOT_VTS",
     ],
diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
index 5c269df..86849d5 100644
--- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
@@ -18,13 +18,10 @@
 
 #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
@@ -113,9 +110,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
index a607a08..3972ad6 100644
--- a/neuralnetworks/1.2/vts/functional/Callbacks.cpp
+++ b/neuralnetworks/1.2/vts/functional/Callbacks.cpp
@@ -24,6 +24,8 @@
 
 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()};
 
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 5907646..90872d4 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -17,7 +17,6 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
 #include <ftw.h>
 #include <gtest/gtest.h>
 #include <hidlmemory/mapping.h>
@@ -35,74 +34,32 @@
 #include "Utils.h"
 #include "VtsHalNeuralnetworks.h"
 
-namespace android::hardware::neuralnetworks::V1_2 {
+// Forward declaration of the mobilenet generated test models in
+// frameworks/ml/nn/runtime/test/generated/.
 namespace generated_tests::mobilenet_224_gender_basic_fixed {
-Model createTestModel();
+const ::test_helper::TestModel& get_test_model();
 }  // namespace generated_tests::mobilenet_224_gender_basic_fixed
-}  // namespace android::hardware::neuralnetworks::V1_2
-
-namespace generated_tests::mobilenet_224_gender_basic_fixed {
-std::vector<test_helper::MixedTypedExample>& get_examples();
-}  // namespace generated_tests::mobilenet_224_gender_basic_fixed
-
-namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_quantized {
-Model createTestModel();
-}  // namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_quantized
 
 namespace generated_tests::mobilenet_quantized {
-std::vector<test_helper::MixedTypedExample>& get_examples();
+const ::test_helper::TestModel& get_test_model();
 }  // namespace generated_tests::mobilenet_quantized
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
-using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
-using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference;
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
+using namespace test_helper;
+using implementation::PreparedModelCallback;
+using V1_0::ErrorStatus;
+using V1_1::ExecutionPreference;
 
 namespace float32_model {
 
-constexpr auto createTestModel = ::android::hardware::neuralnetworks::V1_2::generated_tests::
-        mobilenet_224_gender_basic_fixed::createTestModel;
-constexpr auto get_examples = ::generated_tests::mobilenet_224_gender_basic_fixed::get_examples;
-
-// 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 {
 
-constexpr auto createTestModel = ::android::hardware::neuralnetworks::V1_2::generated_tests::
-        mobilenet_quantized::createTestModel;
-constexpr auto get_examples = ::generated_tests::mobilenet_quantized::get_examples;
-
-// 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
 
@@ -155,39 +112,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;
@@ -211,9 +163,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.
@@ -223,13 +175,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
@@ -242,6 +190,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,
@@ -249,21 +201,16 @@
             .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,
     };
 }
 
@@ -332,40 +279,26 @@
 
     // 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(
                 model,
@@ -379,14 +312,13 @@
         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,
@@ -398,9 +330,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);
         }
     }
 
@@ -416,7 +347,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.";
@@ -433,7 +364,6 @@
                                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(
                 modelCache, dataCache, cacheToken, preparedModelCallback);
@@ -447,7 +377,7 @@
         // Retrieve prepared model.
         preparedModelCallback->wait();
         *status = preparedModelCallback->getStatus();
-        *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
+        *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
                                  .withDefault(nullptr);
     }
 
@@ -482,8 +412,9 @@
 
 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.
@@ -491,7 +422,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.
@@ -516,15 +447,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.
@@ -545,7 +476,7 @@
                     write(dataCache[i].getNativeHandle()->data[0], &dummyBytes, sizeof(dummyBytes)),
                     sizeof(dummyBytes));
         }
-        saveModelToCache(testModel, modelCache, dataCache);
+        saveModelToCache(model, modelCache, dataCache);
     }
 
     // Retrieve preparedModel from cache.
@@ -579,15 +510,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.
     {
@@ -598,13 +529,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;
@@ -625,13 +554,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;
@@ -651,13 +578,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;
@@ -678,13 +603,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;
@@ -698,15 +621,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.
@@ -778,8 +702,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++) {
@@ -790,13 +715,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;
@@ -817,13 +740,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;
@@ -843,13 +764,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;
@@ -870,13 +789,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;
@@ -890,15 +807,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.
@@ -970,8 +888,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);
 
@@ -983,13 +902,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;
@@ -1008,13 +925,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;
@@ -1028,8 +943,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);
 
@@ -1038,7 +954,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.
@@ -1106,12 +1022,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");
@@ -1120,15 +1038,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);
@@ -1136,7 +1054,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();
         }
 
@@ -1155,11 +1073,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);
             }
         }
     }
@@ -1169,12 +1084,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");
@@ -1183,20 +1100,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.
@@ -1218,11 +1135,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);
             }
         }
     }
@@ -1232,12 +1146,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");
@@ -1246,21 +1162,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.
@@ -1336,15 +1252,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;
@@ -1424,9 +1341,4 @@
 INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest,
                         ::testing::Combine(kOperandTypeChoices, ::testing::Range(0U, 10U)));
 
-}  // 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/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index 82cc73d..b8ca080 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -31,7 +31,10 @@
 #include <android/hidl/memory/1.0/IMemory.h>
 #include <hidlmemory/mapping.h>
 
+#include <gtest/gtest.h>
+#include <algorithm>
 #include <iostream>
+#include <numeric>
 
 #include "1.0/Utils.h"
 #include "1.2/Callbacks.h"
@@ -39,50 +42,135 @@
 #include "MemoryUtils.h"
 #include "TestHarness.h"
 #include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace generated_tests {
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
-using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
-using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference;
-using ::android::hardware::neuralnetworks::V1_2::Constant;
-using ::android::hardware::neuralnetworks::V1_2::IDevice;
-using ::android::hardware::neuralnetworks::V1_2::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_2::MeasureTiming;
-using ::android::hardware::neuralnetworks::V1_2::Model;
-using ::android::hardware::neuralnetworks::V1_2::OutputShape;
-using ::android::hardware::neuralnetworks::V1_2::Timing;
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::hidl::memory::V1_0::IMemory;
-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 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)>;
 
-static bool isZeroSized(const MixedTyped& example, uint32_t index) {
-    for (auto i : example.operandDimensions.at(index)) {
-        if (i == 0) return true;
+enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
+
+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)};
     }
-    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),
+            .relaxComputationFloat32toFloat16 = testModel.isRelaxed};
 }
 
-static Return<ErrorStatus> ExecutePreparedModel(sp<IPreparedModel>& preparedModel,
+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(sp<IPreparedModel>& preparedModel,
+static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
                                                 const Request& request, MeasureTiming measure,
                                                 hidl_vec<OutputShape>* outputShapes,
                                                 Timing* timing) {
@@ -105,294 +193,168 @@
     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;
-void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
-                           const std::vector<MixedTypedExample>& examples,
-                           bool hasRelaxedFloat32Model, float fpAtol, float fpRtol,
+
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
                            Executor executor, MeasureTiming measure, OutputType outputType) {
-    const uint32_t INPUT = 0;
-    const uint32_t OUTPUT = 1;
+    // If output0 does not have size larger than one byte, we can not test with insufficient buffer.
+    if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) {
+        return;
+    }
 
-    int example_no = 1;
-    for (auto& example : examples) {
-        SCOPED_TRACE(example_no++);
-        const MixedTyped& inputs = example.operands.first;
-        const MixedTyped& golden = example.operands.second;
+    Request request = createRequest(testModel);
+    if (outputType == OutputType::INSUFFICIENT) {
+        makeOutputInsufficientSize(/*outputIndex=*/0, &request);
+    }
 
-        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;
+    ErrorStatus executionStatus;
+    hidl_vec<OutputShape> outputShapes;
+    Timing timing;
+    switch (executor) {
+        case Executor::ASYNC: {
+            SCOPED_TRACE("asynchronous");
+
+            // launch execution
+            sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+            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");
 
-        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;
+            // 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]);
             }
-        }
 
-        MixedTyped test;  // holding test results
+            // execute burst
+            std::tie(executionStatus, outputShapes, timing) =
+                    controller->compute(request, measure, keys);
 
-        // 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);
+            break;
         }
     }
-}
-void EvaluatePreparedModel(sp<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);
+
+    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() == 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(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
-                           const std::vector<MixedTypedExample>& examples,
-                           bool hasRelaxedFloat32Model, bool testDynamicOutputShape) {
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
+                           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);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
+                              OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
+                              OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
+                              OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
+                              OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
+                              OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
+                              OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
+                              OutputType::INSUFFICIENT);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
+                              OutputType::INSUFFICIENT);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
+                              OutputType::INSUFFICIENT);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
+                              OutputType::INSUFFICIENT);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
+                              OutputType::INSUFFICIENT);
+        EvaluatePreparedModel(preparedModel, testModel, 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);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
+                              OutputType::FULLY_SPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
+                              OutputType::FULLY_SPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
+                              OutputType::FULLY_SPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
+                              OutputType::FULLY_SPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
+                              OutputType::FULLY_SPECIFIED);
+        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
+                              OutputType::FULLY_SPECIFIED);
     }
 }
 
@@ -411,7 +373,6 @@
 
     // 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);
@@ -438,21 +399,39 @@
     ASSERT_NE(nullptr, preparedModel->get());
 }
 
-void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model,
-             std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples,
-             bool testDynamicOutputShape) {
-    Model model = create_model();
-    sp<IPreparedModel> preparedModel = nullptr;
-    PrepareModel(device, model, &preparedModel);
-    if (preparedModel == nullptr) {
-        GTEST_SKIP();
+// Tag for the generated tests
+class GeneratedTest : public GeneratedTestBase {
+  protected:
+    void Execute(const TestModel& testModel, bool testDynamicOutputShape) {
+        Model model = createModel(testModel);
+        if (testDynamicOutputShape) {
+            makeOutputDimensionsUnspecified(&model);
+        }
+
+        sp<IPreparedModel> preparedModel = nullptr;
+        PrepareModel(device, model, &preparedModel);
+        if (preparedModel == nullptr) {
+            GTEST_SKIP();
+        }
+        EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape);
     }
-    EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          model.relaxComputationFloat32toFloat16, testDynamicOutputShape);
+};
+
+// Tag for the dynamic output shape tests
+class DynamicOutputShapeTest : public GeneratedTest {};
+
+TEST_P(GeneratedTest, Test) {
+    Execute(*mTestModel, /*testDynamicOutputShape=*/false);
 }
 
-}  // namespace generated_tests
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+TEST_P(DynamicOutputShapeTest, Test) {
+    Execute(*mTestModel, /*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
index 0ecbe7e..cb01b91 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
@@ -23,31 +23,50 @@
 #include <functional>
 #include <vector>
 #include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace generated_tests {
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
-using ::test_helper::MixedTypedExample;
+class GeneratedTestBase
+    : public NeuralnetworksHidlTest,
+      public ::testing::WithParamInterface<test_helper::TestModelManager::TestParam> {
+  protected:
+    void SetUp() override {
+        NeuralnetworksHidlTest::SetUp();
+        ASSERT_NE(mTestModel, nullptr);
+    }
 
-void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model,
-                  sp<V1_2::IPreparedModel>* preparedModel);
+    const test_helper::TestModel* mTestModel = GetParam().second;
+};
 
-void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
-                           std::function<bool(int)> is_ignored,
-                           const std::vector<MixedTypedExample>& examples,
-                           bool hasRelaxedFloat32Model, bool testDynamicOutputShape);
+#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                          \
+    INSTANTIATE_TEST_SUITE_P(                                                                  \
+            TestGenerated, TestSuite,                                                          \
+            ::testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \
+            [](const auto& info) { return info.param.first; })
 
-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 {
+  protected:
+    void validateEverything(const Model& model, const V1_0::Request& request);
+    void validateFailure(const Model& model, const V1_0::Request& request);
 
-}  // namespace generated_tests
-}  // namespace V1_2
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
+  private:
+    void validateModel(const Model& model);
+    void validateRequest(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+    void validateRequestFailure(const sp<IPreparedModel>& preparedModel,
+                                const V1_0::Request& request);
+    void validateBurst(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+};
+
+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.h b/neuralnetworks/1.2/vts/functional/GeneratedTests.h
deleted file mode 100644
index 9842036..0000000
--- a/neuralnetworks/1.2/vts/functional/GeneratedTests.h
+++ /dev/null
@@ -1,39 +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.
- */
-
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-#include "GeneratedTestHarness.h"
-#include "MemoryUtils.h"
-#include "TestHarness.h"
-#include "Utils.h"
-#include "VtsHalNeuralnetworks.h"
-
-namespace android::hardware::neuralnetworks::V1_2::vts::functional {
-
-std::vector<Request> createRequests(const std::vector<::test_helper::MixedTypedExample>& examples);
-
-}  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
-
-namespace android::hardware::neuralnetworks::V1_2::generated_tests {
-
-using namespace ::android::hardware::neuralnetworks::V1_2::vts::functional;
-
-using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-
-}  // namespace android::hardware::neuralnetworks::V1_2::generated_tests
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 4d6bdbb..844e879 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
@@ -21,23 +21,21 @@
 #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 <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.
@@ -239,7 +237,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 +248,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 +286,32 @@
             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 [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) {
+        return;
+    }
+
+    // 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));
 }
 
 static bool isSanitized(const FmqResultDatum& datum) {
@@ -367,7 +359,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 +370,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);
 
-        // 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));
+                                   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 9e52c44..ea9aa4f 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -18,21 +18,15 @@
 
 #include "1.0/Utils.h"
 #include "1.2/Callbacks.h"
+#include "GeneratedTestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
+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 /////////////////////////
@@ -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);
@@ -691,8 +684,9 @@
     for (int32_t preference : invalidExecutionPreferences) {
         const std::string message =
                 "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
-        validate(device, message, model, [](Model*) {},
-                 static_cast<ExecutionPreference>(preference));
+        validate(
+                device, message, model, [](Model*) {},
+                static_cast<ExecutionPreference>(preference));
     }
 }
 
@@ -716,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 cf5905f..684b433 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -16,31 +16,19 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
 #include "1.0/Utils.h"
 #include "1.2/Callbacks.h"
 #include "ExecutionBurstController.h"
-#include "MemoryUtils.h"
+#include "GeneratedTestHarness.h"
 #include "TestHarness.h"
 #include "Utils.h"
 #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 ::android::hardware::neuralnetworks::V1_0::RequestArgument;
-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 /////////////////////////
 
@@ -71,7 +59,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());
@@ -161,124 +148,23 @@
 
 ///////////////////////////// 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 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 ValidationTest::validateRequest(const sp<IPreparedModel>& preparedModel,
+                                     const Request& request) {
+    removeInputTest(preparedModel, request);
+    removeOutputTest(preparedModel, request);
 }
 
 void ValidationTest::validateRequestFailure(const sp<IPreparedModel>& preparedModel,
-                                            const std::vector<Request>& requests) {
-    for (const Request& request : requests) {
-        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());
-    }
+                                            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 bd24edc..ea9d684 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
@@ -17,20 +17,19 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include "VtsHalNeuralnetworks.h"
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "GeneratedTestHarness.h"
+#include "TestHarness.h"
 
 #include <android-base/logging.h>
 
-#include "1.2/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
@@ -51,7 +50,6 @@
 
     // 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);
@@ -84,10 +82,6 @@
 }
 
 // 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
@@ -100,14 +94,8 @@
 }
 
 // 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 =
@@ -122,11 +110,10 @@
 }
 
 void NeuralnetworksHidlTest::TearDown() {
-    device = nullptr;
     ::testing::VtsHalHidlTargetTestBase::TearDown();
 }
 
-void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
+void ValidationTest::validateEverything(const Model& model, const Request& request) {
     validateModel(model);
 
     // create IPreparedModel
@@ -136,11 +123,11 @@
         return;
     }
 
-    validateRequests(preparedModel, requests);
-    validateBurst(preparedModel, requests);
+    validateRequest(preparedModel, request);
+    validateBurst(preparedModel, request);
 }
 
-void ValidationTest::validateFailure(const Model& model, const std::vector<Request>& requests) {
+void ValidationTest::validateFailure(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(model);
@@ -151,21 +138,27 @@
         return;
     }
 
-    validateRequestFailure(preparedModel, requests);
+    validateRequestFailure(preparedModel, request);
 }
 
-sp<IPreparedModel> getPreparedModel_1_2(
-    const sp<V1_2::implementation::PreparedModelCallback>& callback) {
+TEST_P(ValidationTest, Test) {
+    const Model model = createModel(*mTestModel);
+    const Request request = createRequest(*mTestModel);
+    if (mTestModel->expectFailure) {
+        validateFailure(model, request);
+    } else {
+        validateEverything(model, request);
+    }
+}
+
+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_2::vts::functional
 
 namespace android::hardware::neuralnetworks::V1_0 {
 
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
index 90dfe25..4a6d33b 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
@@ -30,24 +30,14 @@
 #include <vector>
 
 #include "1.2/Callbacks.h"
+#include "TestHarness.h"
 
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-
-using V1_0::DeviceStatus;
-using V1_0::ErrorStatus;
-using V1_0::Request;
-
-namespace vts {
-namespace functional {
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
 // A class for test environment setup
 class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
     DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
-    NeuralnetworksHidlEnvironment();
-    ~NeuralnetworksHidlEnvironment() override;
+    NeuralnetworksHidlEnvironment() = default;
 
   public:
     static NeuralnetworksHidlEnvironment* getInstance();
@@ -59,47 +49,19 @@
     DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
 
   public:
-    NeuralnetworksHidlTest();
-    ~NeuralnetworksHidlTest() override;
+    NeuralnetworksHidlTest() = default;
     void SetUp() override;
     void TearDown() override;
 
   protected:
-    sp<IDevice> device;
+    const sp<IDevice> device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
+            NeuralnetworksHidlEnvironment::getInstance());
 };
 
-// Tag for the validation tests
-class ValidationTest : public NeuralnetworksHidlTest {
-  protected:
-    void validateEverything(const Model& model, const std::vector<Request>& requests);
-    void validateFailure(const Model& model, const std::vector<Request>& requests);
-
-  private:
-    void validateModel(const Model& model);
-    void validateRequests(const sp<IPreparedModel>& preparedModel,
-                          const std::vector<Request>& requests);
-    void validateRequestFailure(const sp<IPreparedModel>& preparedModel,
-                                const std::vector<Request>& requests);
-    void validateBurst(const sp<IPreparedModel>& preparedModel,
-                       const std::vector<Request>& requests);
-};
-
-// Tag for the generated tests
-class GeneratedTest : public NeuralnetworksHidlTest {};
-
-// Tag for the dynamic output shape tests
-class DynamicOutputShapeTest : public NeuralnetworksHidlTest {};
-
 // 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 {
 
diff --git a/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h
index 2992c0c..bf4792c 100644
--- a/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h
+++ b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h
@@ -46,8 +46,6 @@
 
 namespace android::hardware::neuralnetworks::V1_2::implementation {
 
-using V1_0::ErrorStatus;
-
 /**
  * The PreparedModelCallback class is used to receive the error status of
  * preparing a model as well as the prepared model from a task executing
@@ -87,7 +85,8 @@
      * @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(V1_0::ErrorStatus status,
+                        const sp<V1_0::IPreparedModel>& preparedModel) override;
 
     /**
      * IPreparedModelCallback::notify_1_2 marks the callback object with the
@@ -112,7 +111,7 @@
      * @param preparedModel Returned model that has been prepared for execution,
      *     nullptr if the model was unable to be prepared.
      */
-    Return<void> notify_1_2(ErrorStatus status,
+    Return<void> notify_1_2(V1_0::ErrorStatus status,
                             const sp<V1_2::IPreparedModel>& preparedModel) override;
 
     /**
@@ -134,7 +133,7 @@
      *     - GENERAL_FAILURE if there is an unspecified error
      *     - INVALID_ARGUMENT if the input model is invalid
      */
-    ErrorStatus getStatus() const;
+    V1_0::ErrorStatus getStatus() const;
 
     /**
      * Retrieves the model that has been prepared for execution from the
@@ -152,7 +151,7 @@
     mutable std::mutex mMutex;
     mutable std::condition_variable mCondition;
     bool mNotified GUARDED_BY(mMutex) = false;
-    ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
+    V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE;
     sp<V1_0::IPreparedModel> mPreparedModel;
 };
 
@@ -195,7 +194,7 @@
      *         enough to store the resultant values
      *     - INVALID_ARGUMENT if the input request is invalid
      */
-    Return<void> notify(ErrorStatus status) override;
+    Return<void> notify(V1_0::ErrorStatus status) override;
 
     /**
      * IExecutionCallback::notify_1_2 marks the callback object with the results
@@ -230,11 +229,11 @@
      *     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,
+    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(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+    Return<void> notify(V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
                         const Timing& timing) {
         return notify_1_2(status, outputShapes, timing);
     }
@@ -264,7 +263,7 @@
      *     - INVALID_ARGUMENT if one of the input arguments to prepareModel is
      *         invalid
      */
-    ErrorStatus getStatus() const;
+    V1_0::ErrorStatus getStatus() const;
 
     /**
      * Retrieves the output shapes returned from the asynchronous task launched
@@ -309,14 +308,14 @@
      * 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(ErrorStatus errorStatus, const hidl_vec<OutputShape>& outputShapes,
+    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;
-    ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
+    V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE;
     std::vector<OutputShape> mOutputShapes = {};
     Timing mTiming = {};
 };
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/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/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/vts/functional/Android.bp b/power/stats/1.0/vts/functional/Android.bp
index 4f0b325..f564cbe 100644
--- a/power/stats/1.0/vts/functional/Android.bp
+++ b/power/stats/1.0/vts/functional/Android.bp
@@ -31,8 +31,6 @@
         "liblog",
         "libhidlbase",
         "libfmq",
-        "libhidltransport",
-        "libhwbinder",
         "libutils",
     ],
 }
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.4/vts/functional/radio_response.cpp b/radio/1.4/vts/functional/radio_response.cpp
index a849926..d0aae47 100644
--- a/radio/1.4/vts/functional/radio_response.cpp
+++ b/radio/1.4/vts/functional/radio_response.cpp
@@ -733,8 +733,8 @@
         const RadioResponseInfo& info,
         const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls) {
     rspInfo = info;
-    parent_v1_4.notify(info.serial);
     currentCalls = calls;
+    parent_v1_4.notify(info.serial);
     return Void();
 }
 
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/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/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/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/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.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.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/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/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/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/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/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/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/default/Android.bp b/tests/libhwbinder/1.0/default/Android.bp
index aad1e31..81022b8 100644
--- a/tests/libhwbinder/1.0/default/Android.bp
+++ b/tests/libhwbinder/1.0/default/Android.bp
@@ -9,8 +9,6 @@
     shared_libs: [
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
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/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/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/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/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/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/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/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/tv/cec/1.0/default/Android.bp b/tv/cec/1.0/default/Android.bp
index 5fe731b..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,7 +33,6 @@
         "libhardware_legacy",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.tv.cec@1.0",
     ],
 
@@ -58,7 +56,6 @@
         "libutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "android.hardware.tv.cec@1.0",
     ],
 }
diff --git a/tv/cec/1.0/default/HdmiCecMock.cpp b/tv/cec/1.0/default/HdmiCecMock.cpp
index eba8f95..219be86 100644
--- a/tv/cec/1.0/default/HdmiCecMock.cpp
+++ b/tv/cec/1.0/default/HdmiCecMock.cpp
@@ -77,6 +77,7 @@
     if (message.body.size() == 0) {
         return SendMessageResult::NACK;
     }
+    sendMessageToFifo(message);
     return SendMessageResult::SUCCESS;
 }
 
@@ -88,6 +89,11 @@
     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();
 }
@@ -102,17 +108,8 @@
 }
 
 Return<void> HdmiCecMock::getPortInfo(getPortInfo_cb _hidl_cb) {
-    vector<HdmiPortInfo> portInfos;
     // TODO ready port info from device specific config
-    portInfos.resize(mTotalPorts);
-    for (int i = 0; i < mTotalPorts; ++i) {
-        portInfos[i] = {.type = HdmiPortType::INPUT,
-                        .portId = static_cast<uint32_t>(i),
-                        .cecSupported = true,
-                        .arcSupported = (i == 0),
-                        .physicalAddress = static_cast<uint16_t>(i << 12)};
-    }
-    _hidl_cb(portInfos);
+    _hidl_cb(mPortInfo);
     return Void();
 }
 
@@ -140,13 +137,177 @@
     return Void();
 }
 
-Return<bool> HdmiCecMock::isConnected(int32_t portId __unused) {
+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("Opening a virtual HAL for testing and virtual machine.");
+    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
diff --git a/tv/cec/1.0/default/HdmiCecMock.h b/tv/cec/1.0/default/HdmiCecMock.h
index b2f1113..0a708fa 100644
--- a/tv/cec/1.0/default/HdmiCecMock.h
+++ b/tv/cec/1.0/default/HdmiCecMock.h
@@ -49,6 +49,9 @@
 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.
@@ -71,21 +74,43 @@
     }
 
     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 = 4;
+    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
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/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/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp
new file mode 100644
index 0000000..986518b
--- /dev/null
+++ b/tv/tuner/1.0/Android.bp
@@ -0,0 +1,23 @@
+// 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",
+        "IDemuxCallback.hal",
+        "IDescrambler.hal",
+        "IFrontend.hal",
+        "IFrontendCallback.hal",
+        "ITuner.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@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..2d7b275
--- /dev/null
+++ b/tv/tuner/1.0/IDemux.hal
@@ -0,0 +1,184 @@
+package android.hardware.tv.tuner@1.0;
+
+import IDemuxCallback;
+
+/**
+ * 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);
+
+    /**
+     * Add a filter to the demux
+     *
+     * It is used by the client to add a filter to the demux.
+     *
+     * @param type the type of the filter to be added.
+     * @param bufferSize the buffer size of the filter to be added. 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 filterId the ID of the newly added filter.
+     */
+    addFilter(DemuxFilterType type, uint32_t bufferSize, IDemuxCallback cb)
+        generates (Result result, DemuxFilterId filterId);
+
+    /**
+     * 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 MPEG transport
+     * stream. 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 throught DemuxFilterEvent.
+     *
+     * @param filterId the ID of the filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if failed for wrong filter ID.
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return queue the descriptor of the filter's FMQ
+     */
+    getFilterQueueDesc(DemuxFilterId filterId)
+        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 filterId the ID of the filter.
+     * @param settings the settings of the filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if failed for wrong filter ID.
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    configureFilter(DemuxFilterId filterId, DemuxFilterSettings settings)
+        generates(Result result);
+
+    /**
+     * Start the filter.
+     *
+     * It is used by the client to ask the filter to start filterring data.
+     *
+     * @param filterId the ID of the filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if failed for wrong filter ID.
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    startFilter(DemuxFilterId filterId) 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.
+     *
+     * @param filterId the ID of the filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if failed for wrong filter ID.
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    stopFilter(DemuxFilterId filterId) 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.
+     *
+     * @param filterId the ID of the filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if failed for wrong filter ID.
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    flushFilter(DemuxFilterId filterId) generates (Result result);
+
+    /**
+     * Remove a filter from the demux
+     *
+     * It is used by the client to remove a filter from the demux.
+     *
+     * @param filterId the ID of the removed filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if failed for wrong filter ID.
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    removeFilter(DemuxFilterId filterId) generates (Result result);
+
+    /**
+     * 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 filterId the ID of the filter.
+     * @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(DemuxFilterId filterId)
+        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);
+};
+
diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal
new file mode 100644
index 0000000..7efd2c3
--- /dev/null
+++ b/tv/tuner/1.0/IDemuxCallback.hal
@@ -0,0 +1,19 @@
+package android.hardware.tv.tuner@1.0;
+
+interface IDemuxCallback {
+    /**
+     * Notify the client that a new filter event happened.
+     *
+     * @param filterEvent a demux filter event.
+     */
+    oneway onFilterEvent(DemuxFilterEvent filterEvent);
+
+    /**
+     * Notify the client a new status of a demux filter.
+     *
+     * @param filterId the demux filter ID.
+     * @param status a new status of the demux filter.
+     */
+    oneway onFilterStatus(DemuxFilterId filterId, DemuxFilterStatus status);
+};
+
diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal
new file mode 100644
index 0000000..d078657
--- /dev/null
+++ b/tv/tuner/1.0/IDescrambler.hal
@@ -0,0 +1,79 @@
+package android.hardware.tv.tuner@1.0;
+/**
+ * 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.
+     * @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(DemuxTpid pid) 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.
+     * @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(DemuxTpid pid) 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/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
new file mode 100644
index 0000000..05cee91
--- /dev/null
+++ b/tv/tuner/1.0/IFrontend.hal
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+/**
+ * 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);
+};
diff --git a/tv/tuner/1.0/IFrontendCallback.hal b/tv/tuner/1.0/IFrontendCallback.hal
new file mode 100644
index 0000000..e907049
--- /dev/null
+++ b/tv/tuner/1.0/IFrontendCallback.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.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 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/ITuner.hal b/tv/tuner/1.0/ITuner.hal
new file mode 100644
index 0000000..a0f3e8e
--- /dev/null
+++ b/tv/tuner/1.0/ITuner.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.tv.tuner@1.0;
+
+import IDemux;
+import IDescrambler;
+import IFrontend;
+
+/**
+ * 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,
+     *         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);
+
+    /**
+     * 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);
+};
diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp
new file mode 100644
index 0000000..b211dd2
--- /dev/null
+++ b/tv/tuner/1.0/default/Android.bp
@@ -0,0 +1,46 @@
+cc_defaults {
+    name: "tuner_service_defaults",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "Frontend.cpp",
+        "Descrambler.cpp",
+        "Demux.cpp",
+        "Tuner.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..4016c5a
--- /dev/null
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -0,0 +1,405 @@
+/*
+ * 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
+
+const std::vector<uint8_t> fakeDataInputBuffer{
+        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,
+};
+
+Demux::Demux(uint32_t demuxId) {
+    mDemuxId = demuxId;
+}
+
+Demux::~Demux() {}
+
+bool Demux::createAndSaveMQ(uint32_t bufferSize, uint32_t filterId) {
+    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(bufferSize, true));
+    if (!tmpFilterMQ->isValid()) {
+        ALOGW("Failed to create FMQ of filter with id: %d", filterId);
+        return false;
+    }
+
+    mFilterMQs.resize(filterId + 1);
+    mFilterMQs[filterId] = std::move(tmpFilterMQ);
+
+    EventFlag* mFilterEventFlag;
+    if (EventFlag::createEventFlag(mFilterMQs[filterId]->getEventFlagWord(), &mFilterEventFlag) !=
+        OK) {
+        return false;
+    }
+    mFilterEventFlags.resize(filterId + 1);
+    mFilterEventFlags[filterId] = mFilterEventFlag;
+    mFilterWriteCount.resize(filterId + 1);
+    mFilterWriteCount[filterId] = 0;
+    mThreadRunning.resize(filterId + 1);
+
+    return true;
+}
+
+Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
+    ALOGV("%s", __FUNCTION__);
+
+    mSourceFrontendId = frontendId;
+
+    return Result::SUCCESS;
+}
+
+Return<void> Demux::addFilter(DemuxFilterType type, uint32_t bufferSize,
+                              const sp<IDemuxCallback>& cb, addFilter_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint32_t filterId = mLastUsedFilterId + 1;
+    mLastUsedFilterId += 1;
+
+    if ((type != DemuxFilterType::PCR || type != DemuxFilterType::TS) && cb == nullptr) {
+        ALOGW("callback can't be null");
+        _hidl_cb(Result::INVALID_ARGUMENT, filterId);
+        return Void();
+    }
+    // Add callback
+    mDemuxCallbacks.resize(filterId + 1);
+    mDemuxCallbacks[filterId] = cb;
+
+    // Mapping from the filter ID to the filter type
+    mFilterTypes.resize(filterId + 1);
+    mFilterTypes[filterId] = type;
+
+    if (!createAndSaveMQ(bufferSize, filterId)) {
+        _hidl_cb(Result::UNKNOWN_ERROR, -1);
+        return Void();
+    }
+
+    _hidl_cb(Result::SUCCESS, filterId);
+    return Void();
+}
+
+Return<void> Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (filterId < 0 || filterId > mLastUsedFilterId) {
+        ALOGW("No filter with id: %d exists", filterId);
+        _hidl_cb(Result::INVALID_ARGUMENT, FilterMQ::Descriptor());
+        return Void();
+    }
+
+    _hidl_cb(Result::SUCCESS, *mFilterMQs[filterId]->getDesc());
+    return Void();
+}
+
+Return<Result> Demux::configureFilter(uint32_t /* filterId */,
+                                      const DemuxFilterSettings& /* settings */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Demux::startFilter(uint32_t filterId) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (filterId < 0 || filterId > mLastUsedFilterId) {
+        ALOGW("No filter with id: %d exists", filterId);
+        return Result::INVALID_ARGUMENT;
+    }
+
+    DemuxFilterType filterType = mFilterTypes[filterId];
+    Result result;
+    DemuxFilterEvent event{
+            .filterId = filterId,
+            .filterType = filterType,
+    };
+
+    switch (filterType) {
+        case DemuxFilterType::SECTION:
+            result = startSectionFilterHandler(event);
+            break;
+        case DemuxFilterType::PES:
+            result = startPesFilterHandler(event);
+            break;
+        case DemuxFilterType::TS:
+            result = startTsFilterHandler();
+            return Result::SUCCESS;
+        case DemuxFilterType::AUDIO:
+        case DemuxFilterType::VIDEO:
+            result = startMediaFilterHandler(event);
+            break;
+        case DemuxFilterType::RECORD:
+            result = startRecordFilterHandler(event);
+            break;
+        case DemuxFilterType::PCR:
+            result = startPcrFilterHandler();
+            return Result::SUCCESS;
+        default:
+            return Result::UNKNOWN_ERROR;
+    }
+
+    return result;
+}
+
+Return<Result> Demux::stopFilter(uint32_t /* filterId */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Demux::flushFilter(uint32_t /* filterId */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Demux::removeFilter(uint32_t /* filterId */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<void> Demux::getAvSyncHwId(uint32_t /* filterId */, 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__);
+
+    return Result::SUCCESS;
+}
+
+bool Demux::writeSectionsAndCreateEvent(DemuxFilterEvent& event, uint32_t sectionNum) {
+    event.events.resize(sectionNum);
+    for (int i = 0; i < sectionNum; i++) {
+        DemuxFilterSectionEvent secEvent;
+        secEvent = {
+                // temp dump meta data
+                .tableId = 0,
+                .version = 1,
+                .sectionNum = 1,
+                .dataLength = 530,
+        };
+        event.events[i].section(secEvent);
+        if (!writeDataToFilterMQ(fakeDataInputBuffer, event.filterId)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool Demux::writeDataToFilterMQ(const std::vector<uint8_t>& data, uint32_t filterId) {
+    std::lock_guard<std::mutex> lock(mWriteLock);
+    if (mFilterMQs[filterId]->write(data.data(), data.size())) {
+        return true;
+    }
+    return false;
+}
+
+Result Demux::startSectionFilterHandler(DemuxFilterEvent event) {
+    struct ThreadArgs* threadArgs = (struct ThreadArgs*)malloc(sizeof(struct ThreadArgs));
+    threadArgs->user = this;
+    threadArgs->event = &event;
+
+    pthread_create(&mThreadId, NULL, __threadLoop, (void*)threadArgs);
+    pthread_setname_np(mThreadId, "demux_filter_waiting_loop");
+
+    return Result::SUCCESS;
+}
+
+Result Demux::startPesFilterHandler(DemuxFilterEvent& event) {
+    // TODO generate multiple events in one event callback
+    DemuxFilterPesEvent pesEvent;
+    pesEvent = {
+            // temp dump meta data
+            .streamId = 0,
+            .dataLength = 530,
+    };
+    event.events.resize(1);
+    event.events[0].pes(pesEvent);
+    /*pthread_create(&mThreadId, NULL, __threadLoop, this);
+    pthread_setname_np(mThreadId, "demux_section_filter_waiting_loop");*/
+    if (!writeDataToFilterMQ(fakeDataInputBuffer, event.filterId)) {
+        return Result::INVALID_STATE;
+    }
+
+    if (mDemuxCallbacks[event.filterId] == nullptr) {
+        return Result::NOT_INITIALIZED;
+    }
+
+    mDemuxCallbacks[event.filterId]->onFilterEvent(event);
+    return Result::SUCCESS;
+}
+
+Result Demux::startTsFilterHandler() {
+    // TODO handle starting TS filter
+    return Result::SUCCESS;
+}
+
+Result Demux::startMediaFilterHandler(DemuxFilterEvent& event) {
+    DemuxFilterMediaEvent mediaEvent;
+    mediaEvent = {
+            // temp dump meta data
+            .pts = 0,
+            .dataLength = 530,
+            .secureMemory = nullptr,
+    };
+    event.events.resize(1);
+    event.events[0].media() = mediaEvent;
+    // TODO handle write FQM for media stream
+    return Result::SUCCESS;
+}
+
+Result Demux::startRecordFilterHandler(DemuxFilterEvent& event) {
+    DemuxFilterRecordEvent recordEvent;
+    recordEvent = {
+            // temp dump meta data
+            .tpid = 0,
+            .packetNum = 0,
+    };
+    recordEvent.indexMask.tsIndexMask() = 0x01;
+    event.events.resize(1);
+    event.events[0].ts() = recordEvent;
+    return Result::SUCCESS;
+}
+
+Result Demux::startPcrFilterHandler() {
+    // TODO handle starting PCR filter
+    return Result::SUCCESS;
+}
+
+void* Demux::__threadLoop(void* threadArg) {
+    Demux* const self = static_cast<Demux*>(((struct ThreadArgs*)threadArg)->user);
+    self->filterThreadLoop(((struct ThreadArgs*)threadArg)->event);
+    return 0;
+}
+
+void Demux::filterThreadLoop(DemuxFilterEvent* event) {
+    uint32_t filterId = event->filterId;
+    ALOGD("[Demux] filter %d threadLoop start.", filterId);
+    mThreadRunning[filterId] = true;
+
+    while (mThreadRunning[filterId]) {
+        uint32_t efState = 0;
+        // We do not wait for the last round of writen 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++) {
+            DemuxFilterEvent filterEvent{
+                    .filterId = filterId,
+                    .filterType = event->filterType,
+            };
+            if (!writeSectionsAndCreateEvent(filterEvent, 2)) {
+                ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId);
+                break;
+            }
+            mFilterWriteCount[filterId]++;
+            if (mDemuxCallbacks[filterId] == nullptr) {
+                ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId);
+                break;
+            }
+            // After successfully write, send a callback and wait for the read to be done
+            mDemuxCallbacks[filterId]->onFilterEvent(filterEvent);
+            // 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("[Demux] filter %d writing done. Ending thread", filterId);
+                break;
+            }
+            while (mThreadRunning[filterId]) {
+                status_t status = mFilterEventFlags[filterId]->wait(
+                        static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
+                        WAIT_TIMEOUT, true /* retry on spurious wake */);
+                if (status != OK) {
+                    ALOGD("[Demux] wait for data consumed");
+                    continue;
+                }
+                break;
+            }
+        }
+
+        mFilterWriteCount[filterId] = 0;
+        mThreadRunning[filterId] = false;
+    }
+
+    ALOGD("[Demux] filter thread ended.");
+}
+
+}  // 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..8b00266
--- /dev/null
+++ b/tv/tuner/1.0/default/Demux.h
@@ -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.
+ */
+
+#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>
+
+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::IDemuxCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Demux : public IDemux {
+  public:
+    Demux(uint32_t demuxId);
+
+    virtual Return<Result> setFrontendDataSource(uint32_t frontendId) override;
+
+    virtual Return<Result> close() override;
+
+    virtual Return<void> addFilter(DemuxFilterType type, uint32_t bufferSize,
+                                   const sp<IDemuxCallback>& cb, addFilter_cb _hidl_cb) override;
+
+    virtual Return<void> getFilterQueueDesc(uint32_t filterId,
+                                            getFilterQueueDesc_cb _hidl_cb) override;
+
+    virtual Return<Result> configureFilter(uint32_t filterId,
+                                           const DemuxFilterSettings& settings) override;
+
+    virtual Return<Result> startFilter(uint32_t filterId) override;
+
+    virtual Return<Result> stopFilter(uint32_t filterId) override;
+
+    virtual Return<Result> flushFilter(uint32_t filterId) override;
+
+    virtual Return<Result> removeFilter(uint32_t filterId) override;
+
+    virtual Return<void> getAvSyncHwId(uint32_t filterId, getAvSyncHwId_cb _hidl_cb) override;
+
+    virtual Return<void> getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) override;
+
+  private:
+    virtual ~Demux();
+    /**
+     * 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.
+     */
+    bool createAndSaveMQ(uint32_t bufferSize, uint32_t filterId);
+    void deleteEventFlag();
+    bool writeDataToFilterMQ(const std::vector<uint8_t>& data, uint32_t filterId);
+    Result startSectionFilterHandler(DemuxFilterEvent event);
+    Result startPesFilterHandler(DemuxFilterEvent& event);
+    Result startTsFilterHandler();
+    Result startMediaFilterHandler(DemuxFilterEvent& event);
+    Result startRecordFilterHandler(DemuxFilterEvent& event);
+    Result startPcrFilterHandler();
+    bool writeSectionsAndCreateEvent(DemuxFilterEvent& event, uint32_t sectionNum);
+    void filterThreadLoop(DemuxFilterEvent* event);
+    static void* __threadLoop(void* data);
+
+    uint32_t mDemuxId;
+    uint32_t mSourceFrontendId;
+    /**
+     * Record the last used filer id. Initial value is -1.
+     * Filter Id starts with 0.
+     */
+    uint32_t mLastUsedFilterId = -1;
+    /**
+     * A list of created FilterMQ ptrs.
+     * The array number is the filter ID.
+     */
+    vector<unique_ptr<FilterMQ>> mFilterMQs;
+    vector<DemuxFilterType> mFilterTypes;
+    vector<EventFlag*> mFilterEventFlags;
+    /**
+     * Demux callbacks used on filter events or IO buffer status
+     */
+    vector<sp<IDemuxCallback>> mDemuxCallbacks;
+    /**
+     * How many times a specific filter has written since started
+     */
+    vector<uint16_t> mFilterWriteCount;
+    pthread_t mThreadId = 0;
+    /**
+     * If a specific filter's writing loop is still running
+     */
+    vector<bool> mThreadRunning;
+    /**
+     * Lock to protect writes to the FMQs
+     */
+    std::mutex mWriteLock;
+    /**
+     * How many times a filter should write
+     * TODO make this dynamic/random/can take as a parameter
+     */
+    const uint16_t SECTION_WRITE_COUNT = 10;
+    // A struct that passes the arguments to a newly created filter thread
+    struct ThreadArgs {
+        Demux* user;
+        DemuxFilterEvent* event;
+    };
+};
+
+}  // 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..085f2c8
--- /dev/null
+++ b/tv/tuner/1.0/default/Descrambler.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.
+ */
+
+#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(uint16_t /* pid */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::removePid(uint16_t /* pid */) {
+    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..436adcf
--- /dev/null
+++ b/tv/tuner/1.0/default/Descrambler.h
@@ -0,0 +1,62 @@
+/*
+ * 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(uint16_t pid) override;
+
+    virtual Return<Result> removePid(uint16_t pid) 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/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
new file mode 100644
index 0000000..3dcc2b1
--- /dev/null
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -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.
+ */
+
+#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() {
+    // Init callback to nullptr
+    mCallback = nullptr;
+}
+
+Frontend::Frontend(FrontendType type, FrontendId id) {
+    mType = type;
+    mId = id;
+    // 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;
+    }
+
+    mCallback->onEvent(FrontendEventType::NO_SIGNAL);
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::stopTune() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+FrontendType Frontend::getFrontendType() {
+    return mType;
+}
+
+FrontendId Frontend::getFrontendId() {
+    return mId;
+}
+
+}  // 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..f77a0d8
--- /dev/null
+++ b/tv/tuner/1.0/default/Frontend.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_FRONTEND_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_
+
+#include <android/hardware/tv/tuner/1.0/IFrontend.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::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 Frontend : public IFrontend {
+  public:
+    Frontend();
+    Frontend(FrontendType type, FrontendId id);
+
+    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;
+
+    FrontendType getFrontendType();
+
+    FrontendId getFrontendId();
+
+  private:
+    virtual ~Frontend();
+    sp<IFrontendCallback> mCallback;
+    FrontendType mType = FrontendType::UNDEFINED;
+    FrontendId mId = 0;
+};
+
+}  // 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/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/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
new file mode 100644
index 0000000..68b3436
--- /dev/null
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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"
+
+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();
+    mFrontends[1] = new Frontend(FrontendType::ATSC, 1);
+    mFrontends[2] = new Frontend(FrontendType::DVBC, 2);
+    mFrontends[3] = new Frontend(FrontendType::DVBS, 3);
+    mFrontends[4] = new Frontend(FrontendType::DVBT, 4);
+    mFrontends[5] = new Frontend(FrontendType::ISDBT, 5);
+    mFrontends[6] = new Frontend(FrontendType::ANALOG, 6);
+    mFrontends[7] = new Frontend(FrontendType::ATSC, 7);
+}
+
+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<IDemux> demux = new Demux(demuxId);
+
+    _hidl_cb(Result::SUCCESS, demuxId, demux);
+    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();
+}
+
+}  // 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..12e9594
--- /dev/null
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -0,0 +1,62 @@
+/*
+ * 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 "Frontend.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+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> openDescrambler(openDescrambler_cb _hidl_cb) override;
+
+  private:
+    virtual ~Tuner();
+    // Static mFrontends array to maintain local frontends information
+    vector<sp<Frontend>> mFrontends;
+    // 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..4522db2
--- /dev/null
+++ b/tv/tuner/1.0/types.hal
@@ -0,0 +1,481 @@
+/*
+ * 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;
+
+@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,
+    ATSC,
+    DVBC,
+    DVBS,
+    DVBT,
+    ISDBT,
+};
+
+/**
+ *  Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1
+ *  It's a 4-bit field specifying the inner FEC scheme used according to the
+ *  table 35 in the spec.
+ */
+@export
+enum FrontendInnerFec : uint32_t {
+    /* Not defined */
+    FEC_UNDEFINED = 0,
+    /* 1/2 conv. code rate */
+    FEC_1_2 = 1 << 0,
+    /* 2/3 conv. code rate */
+    FEC_2_3 = 1 << 1,
+    /* 3/4 conv. code rate */
+    FEC_3_4 = 1 << 2,
+    /* 5/6 conv. code rate */
+    FEC_5_6 = 1 << 3,
+    /* 7/8 conv. code rate */
+    FEC_7_8 = 1 << 4,
+    /* 8/9 conv. code rate */
+    FEC_8_9 = 1 << 5,
+    /* 3/5 conv. code rate */
+    FEC_3_5 = 1 << 6,
+    /* 4/5 conv. code rate */
+    FEC_4_5 = 1 << 7,
+    /* 9/10 conv. code rate */
+    FEC_9_10 = 1 << 8,
+    /* hardware is able to detect and set FEC automatically */
+    FEC_AUTO = 1 << 9,
+};
+
+/**
+ *  Modulation Type for ATSC.
+ */
+@export
+enum FrontendAtscModulation : uint32_t {
+    UNDEFINED = 0,
+    MOD_8VSB = 1 << 0,
+    MOD_16VSB = 1 << 1,
+};
+
+/**
+ *  Signal Setting for ATSC Frontend.
+ */
+struct FrontendAtscSettings {
+    /** Signal frequencey in Herhz */
+    uint32_t frequency;
+    FrontendAtscModulation modulation;
+};
+
+/**
+ *  Signal Setting for DVBT Frontend.
+ */
+struct FrontendDvbtSettings {
+    /** Signal frequencey in Herhz */
+    uint32_t frequency;
+    FrontendAtscModulation modulation;
+    FrontendInnerFec fec;
+};
+
+/**
+ *  Modulation Type for ATSC.
+ */
+safe_union FrontendSettings {
+    FrontendAtscSettings atsc;
+    FrontendDvbtSettings dvbt;
+};
+
+/**
+ * Frontend Event Type.
+ */
+@export
+enum FrontendEventType : uint32_t {
+    /**
+     * If frontend locked the signal which is specified by tune method, HAL sent
+     * Locked event.
+     */
+    LOCKED,
+    /**
+     * If frontend can't locked the signal which is specified by tune method,
+     * HAL sent NO_SIGNAL event.
+     */
+    NO_SIGNAL,
+    /**
+     * If frontend detect that the locked signal get lost, HAL sent LOST_LOCK
+     * event.
+     */
+    LOST_LOCK,
+};
+
+/* Demux ID is used to associate with a hardware demux resource. */
+typedef uint32_t DemuxId;
+
+/* Filter ID is used to associate with a hardware filter resource. */
+typedef uint32_t DemuxFilterId;
+
+/**
+ * Filter Type according to ISO/IEC 13818-1
+ */
+@export
+enum DemuxFilterType : uint32_t {
+    /**
+     * A filter to filter section data out from input stream.
+     */
+    SECTION,
+    /**
+     * A filter to filter PES data out from input stream.
+     */
+    PES,
+    /**
+     * A filter to filter TS payload out from input stream.
+     */
+    TS,
+    /**
+     * A filter to filter Audio Metadata out from input stream.
+     */
+    AUDIO,
+    /**
+     * A filter to filter Vidoe Metadata out from input stream.
+     */
+    VIDEO,
+    /**
+     * A filter to set PCR (Program Clock Reference) channel from input stream.
+     */
+    PCR,
+    /**
+     * A filter to filter data directly to output buffer for record.
+     */
+    RECORD,
+};
+
+/* Packet ID is used to specify packets in transport stream. */
+typedef uint16_t DemuxTpid;
+
+@export
+enum Constant : uint16_t {
+    /**
+     * An invalid packet ID in transport stream according to ISO/IEC 13818-1.
+     */
+    INVALID_TPID = 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,
+};
+
+/**
+ *  Bits Setting 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 {
+    DemuxTpid tpid;
+    DemuxFilterSectionBits bits;
+    /* Table ID for Section Filter */
+    uint16_t tableId;
+    /* Version number for Section Filter */
+    uint16_t version;
+    /* true if the filter checks CRC and discards data with wrong CRC */
+    bool checkCrc;
+    /* true if the filter repeats the data with the same version */
+    bool isRepeat;
+    /* true if the filter output raw data */
+    bool isRaw;
+};
+
+/* Stream ID is used to specify one elementary stream */
+typedef uint16_t DemuxStreamId;
+
+/**
+ *  Filter Settings for a PES Data.
+ */
+struct DemuxFilterPesDataSettings {
+    DemuxTpid tpid;
+    DemuxStreamId streamId;
+    /* true if the filter output raw data */
+    bool bIsRaw;
+};
+
+/**
+ *  Filter Settings for a TS Data.
+ */
+struct DemuxFilterTsSettings {
+    DemuxTpid tpid;
+};
+
+/**
+ *  Filter Settings for a Audio.
+ */
+struct DemuxFilterAudioSettings {
+    DemuxTpid tpid;
+    /**
+     * true if the filter output goes to decoder directly in pass through mode.
+     */
+    bool bPassthrough;
+};
+
+/**
+ *  Filter Settings for a Video.
+ */
+struct DemuxFilterVideoSettings {
+    DemuxTpid tpid;
+    /**
+     * true if the filter output goes to decoder directly in pass through mode.
+     */
+    bool bPassthrough;
+};
+
+/**
+ *  Filter Settings for a PCR (Program Clock Reference).
+ */
+struct DemuxFilterPcrSettings {
+    DemuxTpid tpid;
+};
+
+/**
+ * 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,
+};
+
+/**
+ * A mask of TS indexes
+ *
+ * It's a combination of TS indexes.
+ */
+typedef bitfield<DemuxTsIndex> DemuxTsIndexMask;
+
+/**
+ * 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,
+};
+
+/**
+ * A mask of Start Code Indexes
+ *
+ * It's a combination of Start Code Indexes.
+ */
+typedef bitfield<DemuxScIndex> DemuxScIndexMask;
+
+/* 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,
+};
+
+/**
+ *  Filter Settings for Record data.
+ */
+struct DemuxFilterRecordSettings {
+    DemuxTpid tpid;
+    DemuxRecordIndexType indexType;
+    safe_union IndexMask {
+        DemuxTsIndexMask tsIndexMask;
+        DemuxScIndexMask scIndexMask;
+    } indexMask;
+};
+
+/**
+ *  Filter Settings.
+ */
+safe_union DemuxFilterSettings {
+    DemuxFilterSectionSettings section;
+    DemuxFilterPesDataSettings pesData;
+    DemuxFilterTsSettings ts;
+    DemuxFilterAudioSettings audio;
+    DemuxFilterVideoSettings video;
+    DemuxFilterPcrSettings pcr;
+    DemuxFilterRecordSettings record;
+};
+
+/**
+ * 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;
+};
+
+/**
+ *  Filter Event for Audio or Video Filter.
+ */
+struct DemuxFilterMediaEvent {
+    /* 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 */
+    uint16_t dataLength;
+    /* A handle associated to the memory where audio or video data stays. */
+    handle secureMemory;
+};
+
+/**
+ *  Filter Event for PES data.
+ */
+struct DemuxFilterPesEvent {
+    DemuxStreamId streamId;
+    /* Data size in bytes of PES data */
+    uint16_t dataLength;
+};
+
+/**
+ *  Filter Event for Record data.
+ */
+struct DemuxFilterRecordEvent {
+    DemuxTpid tpid;
+    /* Indexes of record output */
+    safe_union IndexMask {
+        DemuxTsIndexMask tsIndexMask;
+        DemuxScIndexMask scIndexMask;
+    } indexMask;
+    /* Packet number from beginning of the filter's output */
+    uint64_t packetNum;
+};
+
+/**
+ * Filter Event.
+ */
+struct DemuxFilterEvent {
+    DemuxFilterId filterId;
+    DemuxFilterType filterType;
+    safe_union Event {
+        DemuxFilterSectionEvent section;
+        DemuxFilterMediaEvent media;
+        DemuxFilterPesEvent pes;
+        DemuxFilterRecordEvent ts;
+    };
+    /* An array of events */
+    vec<Event> events;
+};
+
+/**
+ *  A hardware resource ID to be used for audio and video hardware sync.
+ */
+typedef uint32_t AvSyncHwId;
+
+/**
+ *  A token to be used to link descrambler and key slot. It's opaque to
+ *  framework and apps.
+ */
+typedef vec<uint8_t> TunerKeyToken;
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..faf566c
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/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_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",
+    ],
+    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..c652944
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -0,0 +1,437 @@
+/*
+ * 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/IDemuxCallback.h>
+#include <android/hardware/tv/tuner/1.0/IDescrambler.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 <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#define WAIT_TIMEOUT 3000000000
+
+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::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::FrontendSettings;
+using android::hardware::tv::tuner::V1_0::IDemux;
+using android::hardware::tv::tuner::V1_0::IDemuxCallback;
+using android::hardware::tv::tuner::V1_0::IDescrambler;
+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::Result;
+
+namespace {
+
+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> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mDiseqcMessageReceived = true;
+        mEventMessage = diseqcMessage;
+        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;
+    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;
+        }
+    }
+}
+
+// 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;
+    uint32_t mDemuxId;
+
+    ::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);
+    ::testing::AssertionResult closeDemux();
+    ::testing::AssertionResult createDescrambler();
+    ::testing::AssertionResult closeDescrambler();
+};
+
+::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,
+            .modulation = FrontendAtscModulation::UNDEFINED,
+            .fec = FrontendInnerFec::FEC_UNDEFINED,
+    };
+    frontendSettings.dvbt(frontendDvbtSettings);
+    mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
+
+    return ::testing::AssertionResult(true);
+}
+
+::testing::AssertionResult TunerHidlTest::stopTuneFrontend(int32_t frontendId) {
+    Result status;
+    if (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 (createFrontend(frontendId) == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mFrontend->close();
+    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) {
+    Result status;
+
+    if (createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mDemux->setFrontendDataSource(frontendId);
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::closeDemux() {
+    Result status;
+    if (createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mDemux->close();
+    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 (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 (createDescrambler() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mDescrambler->close();
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+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, CreateDemux) {
+    description("Create Demux");
+
+    ASSERT_TRUE(createDemux());
+}
+
+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;
+    }
+
+    for (size_t i = 0; i < feIds.size(); i++) {
+        ASSERT_TRUE(createDemuxWithFrontend(feIds[i]));
+    }
+}
+
+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());
+}
+
+}  // 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/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/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.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/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/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 \