Merge "Align NFCEE ID range with NCI 1.0 in VtsNfcv1.2 test"
diff --git a/atrace/1.0/Android.bp b/atrace/1.0/Android.bp
index 4d73cfd..c7e8d04 100644
--- a/atrace/1.0/Android.bp
+++ b/atrace/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/atrace/1.0/default/AtraceDevice.cpp b/atrace/1.0/default/AtraceDevice.cpp
index 43bcd9a..4e82b0a 100644
--- a/atrace/1.0/default/AtraceDevice.cpp
+++ b/atrace/1.0/default/AtraceDevice.cpp
@@ -30,24 +30,25 @@
 
 struct TracingConfig {
     std::string description;
+    // path and if error on failure
     std::vector<std::pair<std::string, bool>> paths;
 };
 
 // This is a map stores categories and their sysfs paths with required flags
 const std::map<std::string, TracingConfig> kTracingMap = {
-    // gfx
-    {
-        "gfx",
-        {"Graphics",
-         {{"/sys/kernel/debug/tracing/events/mdss/enable", false},
-          {"/sys/kernel/debug/tracing/events/sde/enable", false},
-          {"/sys/kernel/debug/tracing/events/mali_systrace/enable", false}}},
-    },
-    {
-        "ion",
-        {"ION allocation",
-         {{"/sys/kernel/debug/tracing/events/kmem/ion_alloc_buffer_start/enable", true}}},
-    },
+        // gfx
+        {
+                "gfx",
+                {"Graphics",
+                 {{"/sys/kernel/debug/tracing/events/mdss/enable", false},
+                  {"/sys/kernel/debug/tracing/events/sde/enable", false},
+                  {"/sys/kernel/debug/tracing/events/mali_systrace/enable", false}}},
+        },
+        {
+                "ion",
+                {"ION allocation",
+                 {{"/sys/kernel/debug/tracing/events/kmem/ion_alloc_buffer_start/enable", false}}},
+        },
 };
 
 // Methods from ::android::hardware::atrace::V1_0::IAtraceDevice follow.
@@ -93,7 +94,7 @@
     for (auto& c : kTracingMap) {
         for (auto& p : c.second.paths) {
             if (!android::base::WriteStringToFile("0", p.first)) {
-                LOG(ERROR) << "Failed to enable tracing on: " << p.first;
+                LOG(ERROR) << "Failed to disable tracing on: " << p.first;
                 if (p.second) {
                     ret = Status::ERROR_TRACING_POINT;
                 }
diff --git a/audio/2.0/Android.bp b/audio/2.0/Android.bp
index 3495b1a..02f8b40 100644
--- a/audio/2.0/Android.bp
+++ b/audio/2.0/Android.bp
@@ -24,4 +24,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/4.0/Android.bp b/audio/4.0/Android.bp
index b97fe01..862c711 100644
--- a/audio/4.0/Android.bp
+++ b/audio/4.0/Android.bp
@@ -24,4 +24,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/5.0/Android.bp b/audio/5.0/Android.bp
index f6ac2eb..9b28497 100644
--- a/audio/5.0/Android.bp
+++ b/audio/5.0/Android.bp
@@ -25,4 +25,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/common/2.0/Android.bp b/audio/common/2.0/Android.bp
index a64548f..475b309 100644
--- a/audio/common/2.0/Android.bp
+++ b/audio/common/2.0/Android.bp
@@ -12,4 +12,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/common/4.0/Android.bp b/audio/common/4.0/Android.bp
index cd504e5..83f5aad 100644
--- a/audio/common/4.0/Android.bp
+++ b/audio/common/4.0/Android.bp
@@ -12,4 +12,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/common/5.0/Android.bp b/audio/common/5.0/Android.bp
index 66c6fe8..be0f59e 100644
--- a/audio/common/5.0/Android.bp
+++ b/audio/common/5.0/Android.bp
@@ -15,4 +15,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/effect/2.0/Android.bp b/audio/effect/2.0/Android.bp
index 2dd1a0c..d4482c2 100644
--- a/audio/effect/2.0/Android.bp
+++ b/audio/effect/2.0/Android.bp
@@ -30,4 +30,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/effect/4.0/Android.bp b/audio/effect/4.0/Android.bp
index 2c32bcb..8c1900f 100644
--- a/audio/effect/4.0/Android.bp
+++ b/audio/effect/4.0/Android.bp
@@ -30,4 +30,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/audio/effect/5.0/Android.bp b/audio/effect/5.0/Android.bp
index 32fe652..b7dad8d 100644
--- a/audio/effect/5.0/Android.bp
+++ b/audio/effect/5.0/Android.bp
@@ -31,4 +31,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/authsecret/1.0/Android.bp b/authsecret/1.0/Android.bp
index 9cde99a..3b84c3b 100644
--- a/authsecret/1.0/Android.bp
+++ b/authsecret/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/automotive/audiocontrol/1.0/Android.bp b/automotive/audiocontrol/1.0/Android.bp
index 7c51cf7..7ef7909 100644
--- a/automotive/audiocontrol/1.0/Android.bp
+++ b/automotive/audiocontrol/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/automotive/evs/1.0/Android.bp b/automotive/evs/1.0/Android.bp
index 3ac67ea..51f8e20 100644
--- a/automotive/evs/1.0/Android.bp
+++ b/automotive/evs/1.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp
index 4163879..0e73d85 100644
--- a/automotive/vehicle/2.0/Android.bp
+++ b/automotive/vehicle/2.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 57179df..69b7628 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -2215,7 +2215,7 @@
     ERROR = 4,
 };
 
-enum VehicleApPowerStateConfigFlag : int32_t /* NOTE: type is guessed */ {
+enum VehicleApPowerStateConfigFlag : int32_t {
     /**
      * AP can enter deep sleep state. If not set, AP will always shutdown from
      * VehicleApPowerState#SHUTDOWN_PREPARE power state.
diff --git a/biometrics/fingerprint/2.1/Android.bp b/biometrics/fingerprint/2.1/Android.bp
index cff43c4..c8cc0f1 100644
--- a/biometrics/fingerprint/2.1/Android.bp
+++ b/biometrics/fingerprint/2.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/bluetooth/1.0/Android.bp b/bluetooth/1.0/Android.bp
index 67f1a4f..7036d6e 100644
--- a/bluetooth/1.0/Android.bp
+++ b/bluetooth/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/bluetooth/a2dp/1.0/Android.bp b/bluetooth/a2dp/1.0/Android.bp
index fa46a1c..02f224a 100644
--- a/bluetooth/a2dp/1.0/Android.bp
+++ b/bluetooth/a2dp/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/bluetooth/audio/2.0/Android.bp b/bluetooth/audio/2.0/Android.bp
index a020f22..6bf0070 100644
--- a/bluetooth/audio/2.0/Android.bp
+++ b/bluetooth/audio/2.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/boot/1.0/Android.bp b/boot/1.0/Android.bp
index b580cac..5568436 100644
--- a/boot/1.0/Android.bp
+++ b/boot/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/boot/1.0/default/Android.mk b/boot/1.0/default/Android.mk
deleted file mode 100644
index 7ccc4c8..0000000
--- a/boot/1.0/default/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# TODO(connoro): Remove this file once we eliminate existing usage of
-# PRODUCT_STATIC_BOOT_CONTROL_HAL
-
-LOCAL_PATH := $(call my-dir)
-
-ifneq ($(strip $(PRODUCT_STATIC_BOOT_CONTROL_HAL)),)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.hardware.boot@1.0-impl-wrapper.recovery
-LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_MULTILIB := first
-ifeq ($(TARGET_IS_64_BIT),true)
-LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/lib64/hw
-else
-LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/lib/hw
-endif
-LOCAL_SRC_FILES := BootControl.cpp
-LOCAL_CFLAGS := -DBOOT_CONTROL_RECOVERY
-LOCAL_SHARED_LIBRARIES := \
-    libbase.recovery \
-    liblog.recovery \
-    libhidlbase.recovery \
-    libhidltransport.recovery \
-    libhardware.recovery \
-    libutils.recovery \
-    android.hardware.boot@1.0.recovery
-LOCAL_STATIC_LIBRARIES := $(PRODUCT_STATIC_BOOT_CONTROL_HAL)
-include $(BUILD_SHARED_LIBRARY)
-
-endif
diff --git a/broadcastradio/1.0/Android.bp b/broadcastradio/1.0/Android.bp
index 76e580e..8239d74 100644
--- a/broadcastradio/1.0/Android.bp
+++ b/broadcastradio/1.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/broadcastradio/1.1/Android.bp b/broadcastradio/1.1/Android.bp
index 2186b9a..1cc9b62 100644
--- a/broadcastradio/1.1/Android.bp
+++ b/broadcastradio/1.1/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/broadcastradio/2.0/Android.bp b/broadcastradio/2.0/Android.bp
index 93afc02..1040ba1 100644
--- a/broadcastradio/2.0/Android.bp
+++ b/broadcastradio/2.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/common/1.0/Android.bp b/camera/common/1.0/Android.bp
index fe29774..ed64060 100644
--- a/camera/common/1.0/Android.bp
+++ b/camera/common/1.0/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/device/1.0/Android.bp b/camera/device/1.0/Android.bp
index a8df1ec..668884d 100644
--- a/camera/device/1.0/Android.bp
+++ b/camera/device/1.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/device/3.2/Android.bp b/camera/device/3.2/Android.bp
index e7546de..2e5349f 100644
--- a/camera/device/3.2/Android.bp
+++ b/camera/device/3.2/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/camera/device/3.3/Android.bp b/camera/device/3.3/Android.bp
index e21824f..679fad6 100644
--- a/camera/device/3.3/Android.bp
+++ b/camera/device/3.3/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/camera/device/3.4/Android.bp b/camera/device/3.4/Android.bp
index 6a2eac5..e6f42d6 100644
--- a/camera/device/3.4/Android.bp
+++ b/camera/device/3.4/Android.bp
@@ -20,4 +20,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index e7361dd..38a78e0 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -38,9 +38,8 @@
 // Other formats to consider in the future:
 // * V4L2_PIX_FMT_YVU420 (== YV12)
 // * V4L2_PIX_FMT_YVYU (YVYU: can be converted to YV12 or other YUV420_888 formats)
-const std::array<uint32_t, /*size*/1> kSupportedFourCCs {{
-    V4L2_PIX_FMT_MJPEG
-}}; // double braces required in C++11
+const std::array<uint32_t, /*size*/ 2> kSupportedFourCCs{
+    {V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_Z16}};  // double braces required in C++11
 
 constexpr int MAX_RETRY = 5; // Allow retry v4l2 open failures a few times.
 constexpr int OPEN_RETRY_SLEEP_US = 100000; // 100ms * MAX_RETRY = 0.5 seconds
@@ -224,6 +223,13 @@
             mCameraCharacteristics.clear();
             return ret;
         }
+
+        ret = initAvailableCapabilities(&mCameraCharacteristics);
+        if (ret != OK) {
+            ALOGE("%s: init available capabilities key failed: errorno %d", __FUNCTION__, ret);
+            mCameraCharacteristics.clear();
+            return ret;
+        }
     }
     return OK;
 }
@@ -237,6 +243,39 @@
   }                                                \
 } while (0)
 
+status_t ExternalCameraDevice::initAvailableCapabilities(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+
+    if (mSupportedFormats.empty()) {
+        ALOGE("%s: Supported formats list is empty", __FUNCTION__);
+        return UNKNOWN_ERROR;
+    }
+
+    bool hasDepth = false;
+    bool hasColor = false;
+    for (const auto& fmt : mSupportedFormats) {
+        switch (fmt.fourcc) {
+            case V4L2_PIX_FMT_Z16: hasDepth = true; break;
+            case V4L2_PIX_FMT_MJPEG: hasColor = true; break;
+            default: ALOGW("%s: Unsupported format found", __FUNCTION__);
+        }
+    }
+
+    std::vector<uint8_t> availableCapabilities;
+    if (hasDepth) {
+        availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT);
+    }
+    if (hasColor) {
+        availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
+    }
+    if(!availableCapabilities.empty()) {
+        UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, availableCapabilities.data(),
+            availableCapabilities.size());
+    }
+
+    return OK;
+}
+
 status_t ExternalCameraDevice::initDefaultCharsKeys(
         ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
     const uint8_t hardware_level = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
@@ -323,12 +362,6 @@
            &noiseReductionMode, 1);
     UPDATE(ANDROID_NOISE_REDUCTION_MODE, &noiseReductionMode, 1);
 
-    // android.request
-    const uint8_t availableCapabilities[] = {
-        ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE};
-    UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, availableCapabilities,
-           ARRAY_SIZE(availableCapabilities));
-
     const int32_t partialResultCount = 1;
     UPDATE(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &partialResultCount, 1);
 
@@ -576,9 +609,11 @@
     return OK;
 }
 
-status_t ExternalCameraDevice::initOutputCharsKeys(int fd,
-        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
-    initSupportedFormatsLocked(fd);
+template <size_t SIZE>
+status_t ExternalCameraDevice::initOutputCharskeysByFormat(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata,
+        uint32_t fourcc, const std::array<int, SIZE>& halFormats,
+        int streamConfigTag, int streamConfiguration, int minFrameDuration, int stallDuration) {
     if (mSupportedFormats.empty()) {
         ALOGE("%s: Init supported format list failed", __FUNCTION__);
         return UNKNOWN_ERROR;
@@ -587,22 +622,17 @@
     std::vector<int32_t> streamConfigurations;
     std::vector<int64_t> minFrameDurations;
     std::vector<int64_t> stallDurations;
-    int32_t maxFps = std::numeric_limits<int32_t>::min();
-    int32_t minFps = std::numeric_limits<int32_t>::max();
-    std::set<int32_t> framerates;
-
-    std::array<int, /*size*/3> halFormats{{
-        HAL_PIXEL_FORMAT_BLOB,
-        HAL_PIXEL_FORMAT_YCbCr_420_888,
-        HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}};
 
     for (const auto& supportedFormat : mSupportedFormats) {
+        if (supportedFormat.fourcc != fourcc) {
+            // Skip 4CCs not meant for the halFormats
+            continue;
+        }
         for (const auto& format : halFormats) {
             streamConfigurations.push_back(format);
             streamConfigurations.push_back(supportedFormat.width);
             streamConfigurations.push_back(supportedFormat.height);
-            streamConfigurations.push_back(
-                    ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
+            streamConfigurations.push_back(streamConfigTag);
         }
 
         int64_t minFrameDuration = std::numeric_limits<int64_t>::max();
@@ -614,14 +644,6 @@
             if (frameDuration < minFrameDuration) {
                 minFrameDuration = frameDuration;
             }
-            int32_t frameRateInt = static_cast<int32_t>(fr.getDouble());
-            if (minFps > frameRateInt) {
-                minFps = frameRateInt;
-            }
-            if (maxFps < frameRateInt) {
-                maxFps = frameRateInt;
-            }
-            framerates.insert(frameRateInt);
         }
 
         for (const auto& format : halFormats) {
@@ -645,6 +667,30 @@
         }
     }
 
+    UPDATE(streamConfiguration, streamConfigurations.data(), streamConfigurations.size());
+
+    UPDATE(minFrameDuration, minFrameDurations.data(), minFrameDurations.size());
+
+    UPDATE(stallDuration, stallDurations.data(), stallDurations.size());
+
+    return true;
+}
+
+bool ExternalCameraDevice::calculateMinFps(
+    ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    std::set<int32_t> framerates;
+    int32_t minFps = std::numeric_limits<int32_t>::max();
+
+    for (const auto& supportedFormat : mSupportedFormats) {
+        for (const auto& fr : supportedFormat.frameRates) {
+            int32_t frameRateInt = static_cast<int32_t>(fr.getDouble());
+            if (minFps > frameRateInt) {
+                minFps = frameRateInt;
+            }
+            framerates.insert(frameRateInt);
+        }
+    }
+
     std::vector<int32_t> fpsRanges;
     // FPS ranges
     for (const auto& framerate : framerates) {
@@ -658,17 +704,60 @@
     UPDATE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, fpsRanges.data(),
            fpsRanges.size());
 
-    UPDATE(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
-           streamConfigurations.data(), streamConfigurations.size());
-
-    UPDATE(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
-           minFrameDurations.data(), minFrameDurations.size());
-
-    UPDATE(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, stallDurations.data(),
-           stallDurations.size());
-
     UPDATE(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, &maxFrameDuration, 1);
 
+    return true;
+}
+
+status_t ExternalCameraDevice::initOutputCharsKeys(
+    int fd, ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    initSupportedFormatsLocked(fd);
+    if (mSupportedFormats.empty()) {
+        ALOGE("%s: Init supported format list failed", __FUNCTION__);
+        return UNKNOWN_ERROR;
+    }
+
+    bool hasDepth = false;
+    bool hasColor = false;
+
+    // For V4L2_PIX_FMT_Z16
+    std::array<int, /*size*/ 1> halDepthFormats{{HAL_PIXEL_FORMAT_Y16}};
+    // For V4L2_PIX_FMT_MJPEG
+    std::array<int, /*size*/ 3> halFormats{{HAL_PIXEL_FORMAT_BLOB, HAL_PIXEL_FORMAT_YCbCr_420_888,
+                                            HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}};
+
+    for (const auto& supportedFormat : mSupportedFormats) {
+        switch (supportedFormat.fourcc) {
+            case V4L2_PIX_FMT_Z16:
+                hasDepth = true;
+                break;
+            case V4L2_PIX_FMT_MJPEG:
+                hasColor = true;
+                break;
+            default:
+                ALOGW("%s: format %c%c%c%c is not supported!", __FUNCTION__,
+                      supportedFormat.fourcc & 0xFF, (supportedFormat.fourcc >> 8) & 0xFF,
+                      (supportedFormat.fourcc >> 16) & 0xFF, (supportedFormat.fourcc >> 24) & 0xFF);
+        }
+    }
+
+    if (hasDepth) {
+        initOutputCharskeysByFormat(metadata, V4L2_PIX_FMT_Z16, halDepthFormats,
+                ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT,
+                ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
+                ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS,
+                ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
+    }
+    if (hasColor) {
+        initOutputCharskeysByFormat(metadata, V4L2_PIX_FMT_MJPEG, halFormats,
+                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+                ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
+    }
+
+    calculateMinFps(metadata);
+
     SupportedV4L2Format maximumFormat {.width = 0, .height = 0};
     for (const auto& supportedFormat : mSupportedFormats) {
         if (supportedFormat.width >= maximumFormat.width &&
@@ -790,11 +879,12 @@
     sortedFmts = out;
 }
 
-std::vector<SupportedV4L2Format>
-ExternalCameraDevice::getCandidateSupportedFormatsLocked(
-        int fd, CroppingType cropType,
-        const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
-        const Size& minStreamSize) {
+std::vector<SupportedV4L2Format> ExternalCameraDevice::getCandidateSupportedFormatsLocked(
+    int fd, CroppingType cropType,
+    const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
+    const std::vector<ExternalCameraConfig::FpsLimitation>& depthFpsLimits,
+    const Size& minStreamSize,
+    bool depthEnabled) {
     std::vector<SupportedV4L2Format> outFmts;
     struct v4l2_fmtdesc fmtdesc {
         .index = 0,
@@ -840,28 +930,10 @@
                             .fourcc = fmtdesc.pixelformat
                         };
 
-                        double fpsUpperBound = -1.0;
-                        for (const auto& limit : fpsLimits) {
-                            if (cropType == VERTICAL) {
-                                if (format.width <= limit.size.width) {
-                                    fpsUpperBound = limit.fpsUpperBound;
-                                    break;
-                                }
-                            } else { // HORIZONTAL
-                                if (format.height <= limit.size.height) {
-                                    fpsUpperBound = limit.fpsUpperBound;
-                                    break;
-                                }
-                            }
-
-                        }
-                        if (fpsUpperBound < 0.f) {
-                            continue;
-                        }
-
-                        getFrameRateList(fd, fpsUpperBound, &format);
-                        if (!format.frameRates.empty()) {
-                            outFmts.push_back(format);
+                        if (format.fourcc == V4L2_PIX_FMT_Z16 && depthEnabled) {
+                            updateFpsBounds(fd, cropType, depthFpsLimits, format, outFmts);
+                        } else {
+                            updateFpsBounds(fd, cropType, fpsLimits, format, outFmts);
                         }
                     }
                 }
@@ -873,12 +945,39 @@
     return outFmts;
 }
 
-void ExternalCameraDevice::initSupportedFormatsLocked(int fd) {
+void ExternalCameraDevice::updateFpsBounds(
+    int fd, CroppingType cropType,
+    const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits, SupportedV4L2Format format,
+    std::vector<SupportedV4L2Format>& outFmts) {
+    double fpsUpperBound = -1.0;
+    for (const auto& limit : fpsLimits) {
+        if (cropType == VERTICAL) {
+            if (format.width <= limit.size.width) {
+                fpsUpperBound = limit.fpsUpperBound;
+                break;
+            }
+        } else {  // HORIZONTAL
+            if (format.height <= limit.size.height) {
+                fpsUpperBound = limit.fpsUpperBound;
+                break;
+            }
+        }
+    }
+    if (fpsUpperBound < 0.f) {
+        return;
+    }
 
-    std::vector<SupportedV4L2Format> horizontalFmts =
-            getCandidateSupportedFormatsLocked(fd, HORIZONTAL, mCfg.fpsLimits, mCfg.minStreamSize);
-    std::vector<SupportedV4L2Format> verticalFmts =
-            getCandidateSupportedFormatsLocked(fd, VERTICAL, mCfg.fpsLimits, mCfg.minStreamSize);
+    getFrameRateList(fd, fpsUpperBound, &format);
+    if (!format.frameRates.empty()) {
+        outFmts.push_back(format);
+    }
+}
+
+void ExternalCameraDevice::initSupportedFormatsLocked(int fd) {
+    std::vector<SupportedV4L2Format> horizontalFmts = getCandidateSupportedFormatsLocked(
+        fd, HORIZONTAL, mCfg.fpsLimits, mCfg.depthFpsLimits, mCfg.minStreamSize, mCfg.depthEnabled);
+    std::vector<SupportedV4L2Format> verticalFmts = getCandidateSupportedFormatsLocked(
+        fd, VERTICAL, mCfg.fpsLimits, mCfg.depthFpsLimits, mCfg.minStreamSize, mCfg.depthEnabled);
 
     size_t horiSize = horizontalFmts.size();
     size_t vertSize = verticalFmts.size();
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index dce40ff..a12d8e4 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -1724,7 +1724,7 @@
         return false;
     };
 
-    if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG) {
+    if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
         return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
                 req->frameIn->mFourcc & 0xFF,
                 (req->frameIn->mFourcc >> 8) & 0xFF,
@@ -1743,29 +1743,26 @@
     }
 
     // TODO: in some special case maybe we can decode jpg directly to gralloc output?
-    ATRACE_BEGIN("MJPGtoI420");
-    int res = libyuv::MJPGToI420(
-            inData, inDataSize,
-            static_cast<uint8_t*>(mYu12FrameLayout.y),
-            mYu12FrameLayout.yStride,
-            static_cast<uint8_t*>(mYu12FrameLayout.cb),
-            mYu12FrameLayout.cStride,
-            static_cast<uint8_t*>(mYu12FrameLayout.cr),
-            mYu12FrameLayout.cStride,
-            mYu12Frame->mWidth, mYu12Frame->mHeight,
-            mYu12Frame->mWidth, mYu12Frame->mHeight);
-    ATRACE_END();
+    if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+        ATRACE_BEGIN("MJPGtoI420");
+        int res = libyuv::MJPGToI420(
+            inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y), mYu12FrameLayout.yStride,
+            static_cast<uint8_t*>(mYu12FrameLayout.cb), mYu12FrameLayout.cStride,
+            static_cast<uint8_t*>(mYu12FrameLayout.cr), mYu12FrameLayout.cStride,
+            mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth, mYu12Frame->mHeight);
+        ATRACE_END();
 
-    if (res != 0) {
-        // For some webcam, the first few V4L2 frames might be malformed...
-        ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
-        lk.unlock();
-        Status st = parent->processCaptureRequestError(req);
-        if (st != Status::OK) {
-            return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+        if (res != 0) {
+            // For some webcam, the first few V4L2 frames might be malformed...
+            ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
+            lk.unlock();
+            Status st = parent->processCaptureRequestError(req);
+            if (st != Status::OK) {
+                return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+            }
+            signalRequestDone();
+            return true;
         }
-        signalRequestDone();
-        return true;
     }
 
     ALOGV("%s processing new request", __FUNCTION__);
@@ -1796,6 +1793,16 @@
                           __FUNCTION__, ret);
                 }
             } break;
+            case PixelFormat::Y16: {
+                void* outLayout = sHandleImporter.lock(*(halBuf.bufPtr), halBuf.usage, inDataSize);
+
+                std::memcpy(outLayout, inData, inDataSize);
+
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
                 IMapper::Rect outRect {0, 0,
@@ -2063,11 +2070,6 @@
         return false;
     }
 
-    if (ds & Dataspace::DEPTH) {
-        ALOGI("%s: does not support depth output", __FUNCTION__);
-        return false;
-    }
-
     switch (fmt) {
         case PixelFormat::BLOB:
             if (ds != static_cast<int32_t>(Dataspace::V0_JFIF)) {
@@ -2081,6 +2083,16 @@
             // TODO: check what dataspace we can support here.
             // intentional no-ops.
             break;
+        case PixelFormat::Y16:
+            if (!mCfg.depthEnabled) {
+                ALOGI("%s: Depth is not Enabled", __FUNCTION__);
+                return false;
+            }
+            if (!(ds & Dataspace::DEPTH)) {
+                ALOGI("%s: Y16 supports only dataSpace DEPTH", __FUNCTION__);
+                return false;
+            }
+            break;
         default:
             ALOGI("%s: does not support format %x", __FUNCTION__, fmt);
             return false;
@@ -2609,6 +2621,7 @@
             case PixelFormat::BLOB:
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: // Used by SurfaceTexture
+            case PixelFormat::Y16:
                 // No override
                 out->streams[i].v3_2.overrideFormat = config.streams[i].format;
                 break;
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index 680c95a..a07c629 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -21,7 +21,6 @@
 #include <sys/mman.h>
 #include <linux/videodev2.h>
 #include "ExternalCameraUtils.h"
-#include "tinyxml2.h" // XML parsing
 
 namespace android {
 namespace hardware {
@@ -243,28 +242,28 @@
     if (fpsList == nullptr) {
         ALOGI("%s: no fps list specified", __FUNCTION__);
     } else {
-        std::vector<FpsLimitation> limits;
-        XMLElement *row = fpsList->FirstChildElement("Limit");
-        while (row != nullptr) {
-            FpsLimitation prevLimit {{0, 0}, 1000.0};
-            FpsLimitation limit;
-            limit.size = {
-                row->UnsignedAttribute("width", /*Default*/0),
-                row->UnsignedAttribute("height", /*Default*/0)};
-            limit.fpsUpperBound = row->DoubleAttribute("fpsBound", /*Default*/1000.0);
-            if (limit.size.width <= prevLimit.size.width ||
-                    limit.size.height <= prevLimit.size.height ||
-                    limit.fpsUpperBound >= prevLimit.fpsUpperBound) {
-                ALOGE("%s: FPS limit list must have increasing size and decreasing fps!"
-                        " Prev %dx%d@%f, Current %dx%d@%f", __FUNCTION__,
-                        prevLimit.size.width, prevLimit.size.height, prevLimit.fpsUpperBound,
-                        limit.size.width, limit.size.height, limit.fpsUpperBound);
+        if (!updateFpsList(fpsList, ret.fpsLimits)) {
+            return ret;
+        }
+    }
+
+    XMLElement *depth = deviceCfg->FirstChildElement("Depth16Supported");
+    if (depth == nullptr) {
+        ret.depthEnabled = false;
+        ALOGI("%s: depth output is not enabled", __FUNCTION__);
+    } else {
+        ret.depthEnabled = depth->BoolAttribute("enabled", false);
+    }
+
+    if(ret.depthEnabled) {
+        XMLElement *depthFpsList = deviceCfg->FirstChildElement("DepthFpsList");
+        if (depthFpsList == nullptr) {
+            ALOGW("%s: no depth fps list specified", __FUNCTION__);
+        } else {
+            if(!updateFpsList(depthFpsList, ret.depthFpsLimits)) {
                 return ret;
             }
-            limits.push_back(limit);
-            row = row->NextSiblingElement("Limit");
         }
-        ret.fpsLimits = limits;
     }
 
     XMLElement *minStreamSize = deviceCfg->FirstChildElement("MinimumStreamSize");
@@ -284,15 +283,48 @@
         ALOGI("%s: fpsLimitList: %dx%d@%f", __FUNCTION__,
                 limit.size.width, limit.size.height, limit.fpsUpperBound);
     }
+    for (const auto& limit : ret.depthFpsLimits) {
+        ALOGI("%s: depthFpsLimitList: %dx%d@%f", __FUNCTION__, limit.size.width, limit.size.height,
+              limit.fpsUpperBound);
+    }
     ALOGI("%s: minStreamSize: %dx%d" , __FUNCTION__,
          ret.minStreamSize.width, ret.minStreamSize.height);
     return ret;
 }
 
+bool ExternalCameraConfig::updateFpsList(tinyxml2::XMLElement* fpsList,
+        std::vector<FpsLimitation>& fpsLimits) {
+    using namespace tinyxml2;
+    std::vector<FpsLimitation> limits;
+    XMLElement* row = fpsList->FirstChildElement("Limit");
+    while (row != nullptr) {
+        FpsLimitation prevLimit{{0, 0}, 1000.0};
+        FpsLimitation limit;
+        limit.size = {row->UnsignedAttribute("width", /*Default*/ 0),
+                      row->UnsignedAttribute("height", /*Default*/ 0)};
+        limit.fpsUpperBound = row->DoubleAttribute("fpsBound", /*Default*/ 1000.0);
+        if (limit.size.width <= prevLimit.size.width ||
+            limit.size.height <= prevLimit.size.height ||
+            limit.fpsUpperBound >= prevLimit.fpsUpperBound) {
+            ALOGE(
+                "%s: FPS limit list must have increasing size and decreasing fps!"
+                " Prev %dx%d@%f, Current %dx%d@%f",
+                __FUNCTION__, prevLimit.size.width, prevLimit.size.height, prevLimit.fpsUpperBound,
+                limit.size.width, limit.size.height, limit.fpsUpperBound);
+            return false;
+        }
+        limits.push_back(limit);
+        row = row->NextSiblingElement("Limit");
+    }
+    fpsLimits = limits;
+    return true;
+}
+
 ExternalCameraConfig::ExternalCameraConfig() :
         maxJpegBufSize(kDefaultJpegBufSize),
         numVideoBuffers(kDefaultNumVideoBuffer),
-        numStillBuffers(kDefaultNumStillBuffer) {
+        numStillBuffers(kDefaultNumStillBuffer),
+        depthEnabled(false) {
     fpsLimits.push_back({/*Size*/{ 640,  480}, /*FPS upper bound*/30.0});
     fpsLimits.push_back({/*Size*/{1280,  720}, /*FPS upper bound*/7.5});
     fpsLimits.push_back({/*Size*/{1920, 1080}, /*FPS upper bound*/5.0});
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index ff0cfb3..28b9cef 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -82,6 +82,9 @@
     void initSupportedFormatsLocked(int fd);
 
     status_t initCameraCharacteristics();
+    // Init available capabilities keys
+    status_t initAvailableCapabilities(
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
     // Init non-device dependent keys
     status_t initDefaultCharsKeys(::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
     // Init camera control chars keys. Caller still owns fd
@@ -91,13 +94,30 @@
     status_t initOutputCharsKeys(int fd,
             ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
 
+    // Helper function for initOutputCharskeys
+    template <size_t SIZE>
+    status_t initOutputCharskeysByFormat(
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*,
+            uint32_t fourcc, const std::array<int, SIZE>& formats,
+            int scaler_stream_config_tag,
+            int stream_configuration, int min_frame_duration, int stall_duration);
+
+    bool calculateMinFps(::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+
     static void getFrameRateList(int fd, double fpsUpperBound, SupportedV4L2Format* format);
 
+    static void updateFpsBounds(int fd, CroppingType cropType,
+            const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
+            SupportedV4L2Format format,
+            std::vector<SupportedV4L2Format>& outFmts);
+
     // Get candidate supported formats list of input cropping type.
     static std::vector<SupportedV4L2Format> getCandidateSupportedFormatsLocked(
             int fd, CroppingType cropType,
             const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
-            const Size& minStreamSize);
+            const std::vector<ExternalCameraConfig::FpsLimitation>& depthFpsLimits,
+            const Size& minStreamSize,
+            bool depthEnabled);
     // Trim supported format list by the cropping type. Also sort output formats by width/height
     static void trimSupportedFormats(CroppingType cropType,
             /*inout*/std::vector<SupportedV4L2Format>* pFmts);
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 5754ccb..f696057 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -17,12 +17,13 @@
 #ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
 #define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
 
-#include <inttypes.h>
-#include "utils/LightRefBase.h"
-#include <mutex>
-#include <vector>
-#include <unordered_set>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <inttypes.h>
+#include <mutex>
+#include <unordered_set>
+#include <vector>
+#include "tinyxml2.h"  // XML parsing
+#include "utils/LightRefBase.h"
 
 using android::hardware::graphics::mapper::V2_0::IMapper;
 using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
@@ -71,17 +72,22 @@
     // Size of v4l2 buffer queue when streaming > kMaxVideoSize
     uint32_t numStillBuffers;
 
+    // Indication that the device connected supports depth output
+    bool depthEnabled;
+
     struct FpsLimitation {
         Size size;
         double fpsUpperBound;
     };
     std::vector<FpsLimitation> fpsLimits;
+    std::vector<FpsLimitation> depthFpsLimits;
 
     // Minimum output stream size
     Size minStreamSize;
 
 private:
     ExternalCameraConfig();
+    static bool updateFpsList(tinyxml2::XMLElement* fpsList, std::vector<FpsLimitation>& fpsLimits);
 };
 
 } // common
diff --git a/camera/metadata/3.2/Android.bp b/camera/metadata/3.2/Android.bp
index 3271d91..f58fb28 100644
--- a/camera/metadata/3.2/Android.bp
+++ b/camera/metadata/3.2/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/metadata/3.3/Android.bp b/camera/metadata/3.3/Android.bp
index 4dddfad..885f4f9 100644
--- a/camera/metadata/3.3/Android.bp
+++ b/camera/metadata/3.3/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal
index 27d82b9..539ae68 100644
--- a/camera/metadata/3.3/types.hal
+++ b/camera/metadata/3.3/types.hal
@@ -22,7 +22,6 @@
 
 package android.hardware.camera.metadata@3.3;
 
-/* Include definitions from all prior minor HAL metadata revisions */
 import android.hardware.camera.metadata@3.2;
 
 /**
diff --git a/camera/provider/2.4/Android.bp b/camera/provider/2.4/Android.bp
index 63d7fd5..876814d 100644
--- a/camera/provider/2.4/Android.bp
+++ b/camera/provider/2.4/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/cas/1.0/Android.bp b/cas/1.0/Android.bp
index 8d8e946..4982e20 100644
--- a/cas/1.0/Android.bp
+++ b/cas/1.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/cas/native/1.0/Android.bp b/cas/native/1.0/Android.bp
index 880eccd..633ceb9 100644
--- a/cas/native/1.0/Android.bp
+++ b/cas/native/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 5f56ee9..799ab07 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -64,6 +64,19 @@
 }
 
 vintf_compatibility_matrix {
+    name: "framework_compatibility_matrix.4.xml",
+    stem: "compatibility_matrix.4.xml",
+    srcs: [
+        "compatibility_matrix.4.xml",
+    ],
+    kernel_configs: [
+        "kernel_config_q_4.9",
+        "kernel_config_q_4.14",
+        "kernel_config_q_4.19",
+    ]
+}
+
+vintf_compatibility_matrix {
     name: "framework_compatibility_matrix.current.xml",
     stem: "compatibility_matrix.current.xml",
     srcs: [
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index 425e376..7c7f87f 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -96,6 +96,7 @@
     framework_compatibility_matrix.1.xml \
     framework_compatibility_matrix.2.xml \
     framework_compatibility_matrix.3.xml \
+    framework_compatibility_matrix.4.xml \
     framework_compatibility_matrix.current.xml \
     framework_compatibility_matrix.device.xml \
 
diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml
new file mode 100644
index 0000000..3a2fd48
--- /dev/null
+++ b/compatibility_matrices/compatibility_matrix.4.xml
@@ -0,0 +1,483 @@
+<compatibility-matrix version="1.0" type="framework" level="4">
+    <hal format="hidl" optional="true">
+        <name>android.hardware.atrace</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAtraceDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.audio</name>
+        <version>4.0</version>
+        <interface>
+            <name>IDevicesFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.audio.effect</name>
+        <version>4.0</version>
+        <interface>
+            <name>IEffectsFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.authsecret</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAuthSecret</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.audiocontrol</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAudioControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.evs</name>
+        <version>1.0</version>
+        <interface>
+            <name>IEvsEnumerator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.vehicle</name>
+        <version>2.0</version>
+        <interface>
+            <name>IVehicle</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.biometrics.fingerprint</name>
+        <version>2.1</version>
+        <interface>
+            <name>IBiometricsFingerprint</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.bluetooth</name>
+        <version>1.0</version>
+        <interface>
+            <name>IBluetoothHci</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.bluetooth.audio</name>
+        <version>2.0</version>
+        <interface>
+            <name>IBluetoothAudioProvidersFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.boot</name>
+        <version>1.0</version>
+        <interface>
+            <name>IBootControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.broadcastradio</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IBroadcastRadioFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.camera.provider</name>
+        <version>2.4</version>
+        <interface>
+            <name>ICameraProvider</name>
+            <regex-instance>[^/]+/[0-9]+</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.cas</name>
+        <version>1.0</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.configstore</name>
+        <version>1.1</version>
+        <interface>
+            <name>ISurfaceFlingerConfigs</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.confirmationui</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfirmationUI</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.contexthub</name>
+        <version>1.0</version>
+        <interface>
+            <name>IContexthub</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.drm</name>
+        <version>1.0</version>
+        <interface>
+            <name>ICryptoFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+        <interface>
+            <name>IDrmFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.drm</name>
+        <version>1.1</version>
+        <interface>
+            <name>ICryptoFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+        <interface>
+            <name>IDrmFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.dumpstate</name>
+        <version>1.0</version>
+        <interface>
+            <name>IDumpstateDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.gatekeeper</name>
+        <version>1.0</version>
+        <interface>
+            <name>IGatekeeper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.gnss</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IGnss</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.graphics.allocator</name>
+        <version>2.0</version>
+        <interface>
+            <name>IAllocator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.graphics.composer</name>
+        <version>2.1</version>
+        <interface>
+            <name>IComposer</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.graphics.mapper</name>
+        <version>2.0</version>
+        <interface>
+            <name>IMapper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.health</name>
+        <version>2.0</version>
+        <interface>
+            <name>IHealth</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.health.filesystem</name>
+        <version>1.0</version>
+        <interface>
+            <name>IFileSystem</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.ir</name>
+        <version>1.0</version>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.keymaster</name>
+        <version>3.0</version>
+        <version>4.0</version>
+        <interface>
+            <name>IKeymasterDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.keymaster</name>
+        <version>4.0</version>
+        <interface>
+            <name>IKeymasterDevice</name>
+            <instance>strongbox</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.light</name>
+        <version>2.0</version>
+        <interface>
+            <name>ILight</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hardware.media.omx</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOmx</name>
+            <instance>default</instance>
+        </interface>
+        <interface>
+            <name>IOmxStore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.memtrack</name>
+        <version>1.0</version>
+        <interface>
+            <name>IMemtrack</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.neuralnetworks</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>IDevice</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.nfc</name>
+        <version>1.2</version>
+        <interface>
+            <name>INfc</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.oemlock</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOemLock</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.power</name>
+        <version>1.0-3</version>
+        <interface>
+            <name>IPower</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.power.stats</name>
+        <version>1.0</version>
+        <interface>
+            <name>IPowerStats</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.radio</name>
+        <!-- Todo<b/123249760> Allow only 1.4 for Q-->
+        <version>1.3-4</version>
+        <interface>
+            <name>IRadio</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+        <interface>
+            <name>ISap</name>
+            <instance>slot1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.radio.config</name>
+        <version>1.2</version>
+        <interface>
+            <name>IRadioConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.renderscript</name>
+        <version>1.0</version>
+        <interface>
+            <name>IDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.secure_element</name>
+        <version>1.0</version>
+        <interface>
+            <name>ISecureElement</name>
+            <regex-instance>eSE[1-9][0-9]*</regex-instance>
+            <regex-instance>SIM[1-9][0-9]*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.sensors</name>
+        <version>1.0</version>
+        <interface>
+            <name>ISensors</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.soundtrigger</name>
+        <version>2.0-1</version>
+        <interface>
+            <name>ISoundTriggerHw</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tetheroffload.config</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOffloadConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tetheroffload.control</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOffloadControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.thermal</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IThermal</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tv.cec</name>
+        <version>1.0</version>
+        <interface>
+            <name>IHdmiCec</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.tv.input</name>
+        <version>1.0</version>
+        <interface>
+            <name>ITvInput</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.usb</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>IUsb</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.usb.gadget</name>
+        <version>1.0</version>
+        <interface>
+            <name>IUsbGadget</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.vibrator</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>IVibrator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.vr</name>
+        <version>1.0</version>
+        <interface>
+            <name>IVr</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.weaver</name>
+        <version>1.0</version>
+        <interface>
+            <name>IWeaver</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>IWifi</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi.hostapd</name>
+        <version>1.0</version>
+        <interface>
+            <name>IHostapd</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi.offload</name>
+        <version>1.0</version>
+        <interface>
+            <name>IOffload</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.wifi.supplicant</name>
+        <version>1.0-1</version>
+        <interface>
+            <name>ISupplicant</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</compatibility-matrix>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 32e1695..c3f1870 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -1,4 +1,4 @@
-<compatibility-matrix version="1.0" type="framework" level="4">
+<compatibility-matrix version="1.0" type="framework" level="5">
     <hal format="hidl" optional="true">
         <name>android.hardware.atrace</name>
         <version>1.0</version>
@@ -72,14 +72,6 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
-        <name>android.hardware.bluetooth.a2dp</name>
-        <version>1.0</version>
-        <interface>
-            <name>IBluetoothAudioOffload</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
         <name>android.hardware.bluetooth.audio</name>
         <version>2.0</version>
         <interface>
diff --git a/configstore/1.0/Android.bp b/configstore/1.0/Android.bp
index a6fd656..d92f252 100644
--- a/configstore/1.0/Android.bp
+++ b/configstore/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/configstore/1.1/Android.bp b/configstore/1.1/Android.bp
index 3900d9b..7c5f3f7 100644
--- a/configstore/1.1/Android.bp
+++ b/configstore/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/confirmationui/1.0/Android.bp b/confirmationui/1.0/Android.bp
index e6b0414..a22067a 100644
--- a/confirmationui/1.0/Android.bp
+++ b/confirmationui/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/contexthub/1.0/Android.bp b/contexthub/1.0/Android.bp
index 730adcb..71dd978 100644
--- a/contexthub/1.0/Android.bp
+++ b/contexthub/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/current.txt b/current.txt
index e1b3356..f4aa57e 100644
--- a/current.txt
+++ b/current.txt
@@ -390,19 +390,22 @@
 684702a60deef03a1e8093961dc0a18c555c857ad5a77ba7340b0635ae01eb70 android.hardware.camera.device@3.4::ICameraDeviceSession
 f8a19622cb0cc890913b1ef3e32b675ffb26089a09e02fef4056ebad324d2b5d android.hardware.camera.device@3.4::types
 291638a1b6d4e63283e9e722ab5049d9351717ffa2b66162124f84d1aa7c2835 android.hardware.camera.metadata@3.2::types
-8a075cf3a17fe99c6d23415a3e9a65612f1fee73ee052a3a8a0ca5b8877395a4 android.hardware.camera.metadata@3.3::types
+f4aca082ad436f00b3bed8b9b9dfdc01f6460afdbee7ca10fedb5e34bddcc96f android.hardware.camera.metadata@3.3::types
 da33234403ff5d60f3473711917b9948e6484a4260b5247acdafb111193a9de2 android.hardware.configstore@1.0::ISurfaceFlingerConfigs
 21165b8e30c4b2d52980e4728f661420adc16e38bbe73476c06b2085be908f4c android.hardware.gnss@1.0::IGnssCallback
 d702fb01dc2a0733aa820b7eb65435ee3334f75632ef880bafd2fb8803a20a58 android.hardware.gnss@1.0::IGnssMeasurementCallback
+7c7721c0f773fcf422b71a4f558545e9e36acc973e58ca51e5bd53905cf46bc0 android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer
 d4fea995378bb4f421b4e24ccf68cad2734ab07fe4f874a126ba558b99df5766 android.hardware.graphics.composer@2.1::IComposerClient
+65a021fa89085b62fc96b2b6d3bef2f9103cf4d63379c68bc154fd9eef672852 android.hardware.health@1.0::types
 b7ecf29927055ec422ec44bf776223f07d79ad9f92ccf9becf167e62c2607e7a android.hardware.keymaster@4.0::IKeymasterDevice
 574e8f1499436fb4075894dcae0b36682427956ecb114f17f1fe22d116a83c6b android.hardware.neuralnetworks@1.0::IPreparedModel
-417ab60fe1ef786778047e4486f3d868ebce570d91addd8fe4251515213072de android.hardware.neuralnetworks@1.0::types
-e22e8135d061d0e9c4c1a70c25c19fdba10f4d3cda9795ef25b6392fc520317c android.hardware.neuralnetworks@1.1::types
+1e3576c07006d82ba5bc6ddbf87c101414d361c41afe7a82713750844c488725 android.hardware.neuralnetworks@1.0::types
+eb754b58c93e5591613208b4c972811288b0fa16a82430d602f107c91a908b22 android.hardware.neuralnetworks@1.1::types
 1d4a5776614c08b5d794a5ec5ab04697260cbd4b3441d5935cd53ee71d19da02 android.hardware.radio@1.0::IRadioResponse
 ed9da80ec0c96991fd03f0a46107815d0e50f764656e49dba4980fa5c31d5bc3 android.hardware.radio@1.0::types
 1d19720d4fd38b1095f0f555a4bd92b3b12c9b1d0f560b0e9a474cd6dcc20db6 android.hardware.radio@1.2::IRadio
 cd1757867a5e3a3faa362e785239515870d1a3c9ce756c6f0cf0f0fd8aac2547 android.hardware.radio@1.2::types
+722b3595548ed7f1953b6e0143dc842d4d6e290ff009a134eb518d7c17a09347 android.hardware.radio@1.2::types # b/112486807
 e78cf871f9fd1c072874e481e06e18e2681763cf2aa38c1fd777d53bab4eb69b android.hardware.sensors@1.0::types
 1722ad002317b1fae1400de709e90f442d94ef22864e05f7a12af48c32e8edc8 android.hardware.usb@1.1::types
 29c8da7a13c40d488f569c812441d5754ee45bdcdb8ce6564f524b708d10a057 android.hardware.vibrator@1.1::types
@@ -443,13 +446,13 @@
 c3f831a66d5815baf74f5b82fe79cf099542ddae4dfab3f388e1d41828e794fc android.hardware.health.storage@1.0::IGarbageCollectCallback
 dd1ec219f5d2e2b33c6c0bcb92e63bbedb36f7c716413462848f6b6ae74fc864 android.hardware.health.storage@1.0::IStorage
 2b4a14661e6a38617b7dd0c6ebb66a56a90e564674ac7697a14cb8a0cab92b2f android.hardware.health.storage@1.0::types
-4880af120fc1640225abdc2c60bda6d79617d73484d5124913c7278af3b11e2d android.hardware.neuralnetworks@1.2::IBurstCallback
+5f6b6b99ffd0d51a5713174a3030a2a69273bcd476fc1b5ce814491437685857 android.hardware.neuralnetworks@1.2::IBurstCallback
 19877e466ad8c6ed42b38050b77bd010cf7800ff365fdc8574f45bbfda03a758 android.hardware.neuralnetworks@1.2::IBurstContext
-96249c852dabeefa3a9496ecdfc44681a071c665bfbf88527bf775c88bf1ab1b android.hardware.neuralnetworks@1.2::IDevice
+b83317b66721241887d2770b5ae95fd5af1e77c5daa7530ecb08fae8892f2b43 android.hardware.neuralnetworks@1.2::IDevice
 92714960d1a53fc2ec557302b41c7cc93d2636d8364a44bd0f85be0c92927ff8 android.hardware.neuralnetworks@1.2::IExecutionCallback
-83885d366f22ada42c00d8854f0b7e7ba4cf73ddf80bb0d8e168ce132cec57ea android.hardware.neuralnetworks@1.2::IPreparedModel
+36e1064c869965dee533c537cefbe87e54db8bd8cd45be7e0e93e00e8a43863a android.hardware.neuralnetworks@1.2::IPreparedModel
 e1c734d1545e1a4ae749ff1dd9704a8e594c59aea7c8363159dc258e93e0df3b android.hardware.neuralnetworks@1.2::IPreparedModelCallback
-896d1827541d620996720a79c6476edb902a58d515bf908f67a5bdef4d2c318c android.hardware.neuralnetworks@1.2::types
+d18bba0b6c8d2d1da3cfb52b14f556d2e04eb91551d97ee60a3524cf993a3e0e android.hardware.neuralnetworks@1.2::types
 cf7a4ba516a638f9b82a249c91fb603042c2d9ca43fd5aad9cf6c0401ed2a5d7 android.hardware.nfc@1.2::INfc
 abf98c2ae08bf765db54edc8068e36d52eb558cff6706b6fd7c18c65a1f3fc18 android.hardware.nfc@1.2::types
 4cb252dc6372a874aef666b92a6e9529915aa187521a700f0789065c3c702ead android.hardware.power.stats@1.0::IPowerStats
@@ -457,6 +460,7 @@
 a1c6b0761bcb89d6bf15a156f9306b8090b3a916a15fea1689b4b0c1738e382f android.hardware.radio@1.3::IRadio
 e9d0f11a52715f5a29d89e2d8e2e21db1e16a43174af6b9d51a62d705cda1455 android.hardware.radio@1.3::IRadioIndication
 d233f0da44f55fdef0a95db5229231412787bb67695cd1ea197ce89a3c2908b9 android.hardware.radio@1.3::IRadioResponse
+f5fbe4f28a9e346be36063eca4e6c864114a1a6fb64884db03fdd825791ad9b8 android.hardware.radio@1.3::IRadioResponse # b/132818184 for Android Q
 750a363c8cec70baa1aac19e275c15233c5898e93c6bb5155fa2ca7f365490dc android.hardware.radio@1.3::types
 ef4ab741f7e7762fb45e2e24ca83871f72006ce05f57aa9addc574893dd29872 android.hardware.radio@1.4::IRadio
 33d9e6895cca98aa56296bb01720d18b8acd0e4de4960beb712e63ad147438a5 android.hardware.radio@1.4::IRadioIndication
@@ -471,3 +475,7 @@
 93b8102078e25057ae347ac9704e87529eb26121c2a1b419b362dd36eccefc4d android.hardware.radio.config@1.2::types
 08d439c463e4044fa78874037d8e8379aa3cabecde32f08a775897eea5a538af android.hardware.secure_element@1.1::ISecureElement
 b53ac9d61c24efb16a2d63a861cef20680f6d57adb244a03b9778c675550628b android.hardware.secure_element@1.1::ISecureElementHalCallback
+
+# ABI preserving changes to HALs during Android R
+b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
+1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
diff --git a/drm/1.0/Android.bp b/drm/1.0/Android.bp
index fea851f..a950c57 100644
--- a/drm/1.0/Android.bp
+++ b/drm/1.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/drm/1.1/Android.bp b/drm/1.1/Android.bp
index 739b470..16010a6 100644
--- a/drm/1.1/Android.bp
+++ b/drm/1.1/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/dumpstate/1.0/Android.bp b/dumpstate/1.0/Android.bp
index 29be116..3d47550 100644
--- a/dumpstate/1.0/Android.bp
+++ b/dumpstate/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/fastboot/1.0/Android.bp b/fastboot/1.0/Android.bp
index ea3566f..ec447b8 100644
--- a/fastboot/1.0/Android.bp
+++ b/fastboot/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/gatekeeper/1.0/Android.bp b/gatekeeper/1.0/Android.bp
index 7eff2e8..5d63eaf 100644
--- a/gatekeeper/1.0/Android.bp
+++ b/gatekeeper/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/gnss/1.0/Android.bp b/gnss/1.0/Android.bp
index 2e3e6fd..d97588c 100644
--- a/gnss/1.0/Android.bp
+++ b/gnss/1.0/Android.bp
@@ -35,4 +35,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/gnss/1.1/Android.bp b/gnss/1.1/Android.bp
index 4ae4439..5294a6b 100644
--- a/gnss/1.1/Android.bp
+++ b/gnss/1.1/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/graphics/allocator/2.0/Android.bp b/graphics/allocator/2.0/Android.bp
index 50b474e..37d9dfc 100644
--- a/graphics/allocator/2.0/Android.bp
+++ b/graphics/allocator/2.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/bufferqueue/1.0/Android.bp b/graphics/bufferqueue/1.0/Android.bp
index e23ca59..7fca354 100644
--- a/graphics/bufferqueue/1.0/Android.bp
+++ b/graphics/bufferqueue/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal b/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal
index c59a16c..21cbc2e 100644
--- a/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal
+++ b/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal
@@ -546,7 +546,7 @@
      */
     disconnect(
             int32_t api,
-            DisconnectMode mode /* = DisconnectMode::API */
+            DisconnectMode mode
         ) generates (
             Status status
         );
diff --git a/graphics/common/1.0/Android.bp b/graphics/common/1.0/Android.bp
index 175166d..089fe14 100644
--- a/graphics/common/1.0/Android.bp
+++ b/graphics/common/1.0/Android.bp
@@ -13,4 +13,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/graphics/common/1.1/Android.bp b/graphics/common/1.1/Android.bp
index 0647d12d..899fe03 100644
--- a/graphics/common/1.1/Android.bp
+++ b/graphics/common/1.1/Android.bp
@@ -16,4 +16,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/graphics/composer/2.1/Android.bp b/graphics/composer/2.1/Android.bp
index 38786fd..4e4b81c 100644
--- a/graphics/composer/2.1/Android.bp
+++ b/graphics/composer/2.1/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
index 420a1f6..062f2e5 100644
--- a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
@@ -20,7 +20,6 @@
     cflags: [
         "-Wall",
         "-Werror",
-        "-Wno-user-defined-warnings",
     ],
     cppflags: [
         "-Weverything",
diff --git a/graphics/composer/2.2/Android.bp b/graphics/composer/2.2/Android.bp
index fe71e9e..930cadc 100644
--- a/graphics/composer/2.2/Android.bp
+++ b/graphics/composer/2.2/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/mapper/2.0/Android.bp b/graphics/mapper/2.0/Android.bp
index 96e812b..4459bdc 100644
--- a/graphics/mapper/2.0/Android.bp
+++ b/graphics/mapper/2.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/graphics/mapper/2.1/Android.bp b/graphics/mapper/2.1/Android.bp
index 8527d3d..e5a5ae4 100644
--- a/graphics/mapper/2.1/Android.bp
+++ b/graphics/mapper/2.1/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/health/1.0/Android.bp b/health/1.0/Android.bp
index e03b142..ea6b0c8 100644
--- a/health/1.0/Android.bp
+++ b/health/1.0/Android.bp
@@ -16,4 +16,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/health/1.0/types.hal b/health/1.0/types.hal
index 377d1bd..90b8bb1 100644
--- a/health/1.0/types.hal
+++ b/health/1.0/types.hal
@@ -190,7 +190,13 @@
     /** Remaining battery capacity in percent */
     int32_t batteryLevel;
 
-    /** Instantaneous battery voltage in uV */
+    /**
+     * Instantaneous battery voltage in millivolts (mV).
+     *
+     * Historically, the unit of this field is microvolts (uV), but all
+     * clients and implementations uses millivolts in practice, making it
+     * the de-facto standard.
+     */
     int32_t batteryVoltage;
 
     /** Instantaneous battery temperature in tenths of degree celcius */
diff --git a/health/2.0/Android.bp b/health/2.0/Android.bp
index f472b27..b8323b6 100644
--- a/health/2.0/Android.bp
+++ b/health/2.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/health/storage/1.0/Android.bp b/health/storage/1.0/Android.bp
index 45fa01f..e4620f8 100644
--- a/health/storage/1.0/Android.bp
+++ b/health/storage/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/ir/1.0/Android.bp b/ir/1.0/Android.bp
index 5f25172..5fca96d 100644
--- a/ir/1.0/Android.bp
+++ b/ir/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/keymaster/3.0/Android.bp b/keymaster/3.0/Android.bp
index ca17a9b..0fdc32c 100644
--- a/keymaster/3.0/Android.bp
+++ b/keymaster/3.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/keymaster/4.0/Android.bp b/keymaster/4.0/Android.bp
index cd46fd9..ea328f4 100644
--- a/keymaster/4.0/Android.bp
+++ b/keymaster/4.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/keymaster/4.0/IKeymasterDevice.hal b/keymaster/4.0/IKeymasterDevice.hal
index c867ab0..3475f79 100644
--- a/keymaster/4.0/IKeymasterDevice.hal
+++ b/keymaster/4.0/IKeymasterDevice.hal
@@ -624,7 +624,7 @@
     /**
      * Exports a public key, returning the key in the specified format.
      *
-     * @parm keyFormat The format used for export.  See KeyFormat in types.hal.
+     * @parm keyFormat The format used for export.  Must be KeyFormat::X509.
      *
      * @param keyBlob The opaque descriptor returned by generateKey() or importKey().  The
      *        referenced key must be asymmetric.
@@ -639,7 +639,7 @@
      *        value, it must be computationally infeasible for the secure hardware to obtain the key
      *        material.
      *
-     * @return keyMaterial The public key material in PKCS#8 format.
+     * @return keyMaterial The public key material in X.509 format.
      */
     exportKey(KeyFormat keyFormat, vec<uint8_t> keyBlob, vec<uint8_t> clientId,
               vec<uint8_t> appData) generates (ErrorCode error, vec<uint8_t> keyMaterial);
@@ -1005,13 +1005,11 @@
      *
      * -- EC Keys --
      *
-     * EC key operations must specify exactly one padding mode in inParams.  If unspecified or
-     * specified more than once, begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE.
-     *
-     * Private key operations (KeyPurpose::SIGN) need authorization of digest and padding, which
-     * means that the key authorizations must contain the specified values.  If not, begin() must
-     * return ErrorCode::INCOMPATIBLE_DIGEST.  Public key operations (KeyPurpose::VERIFY) are
-     * permitted with unauthorized digest or padding.
+     * EC private key operations must specify exactly one digest in inParams.  If unspecified or
+     * specified more than once, begin() must return ErrorCode::UNSUPPORTED_DIGEST.  For private key
+     * operations, (KeyPurpose::SIGN), if the specified digest is not in the key's authorization
+     * list, begin() must return ErrorCode::INCOMPATIBLE_DIGEST.  Public key operations
+     * (KeyPurpose::VERIFY) are permitted with unauthorized digest.
      *
      * -- AES Keys --
      *
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp
index 9325cc0..1eb9a68 100644
--- a/keymaster/4.0/support/Keymaster.cpp
+++ b/keymaster/4.0/support/Keymaster.cpp
@@ -19,7 +19,7 @@
 #include <iomanip>
 
 #include <android-base/logging.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <keymasterV4_0/Keymaster3.h>
 #include <keymasterV4_0/Keymaster4.h>
 #include <keymasterV4_0/key_param_output.h>
@@ -69,7 +69,7 @@
 namespace support {
 
 using ::android::sp;
-using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hidl::manager::V1_2::IServiceManager;
 
 std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster) {
     auto& version = keymaster.halVersion();
@@ -86,7 +86,7 @@
 
     bool foundDefault = false;
     auto& descriptor = Wrapper::WrappedIKeymasterDevice::descriptor;
-    serviceManager->listByInterface(descriptor, [&](const hidl_vec<hidl_string>& names) {
+    serviceManager->listManifestByInterface(descriptor, [&](const hidl_vec<hidl_string>& names) {
         for (auto& name : names) {
             if (name == "default") foundDefault = true;
             auto device = Wrapper::WrappedIKeymasterDevice::getService(name);
@@ -97,7 +97,7 @@
     });
 
     if (!foundDefault) {
-        // "default" wasn't provided by listByInterface.  Maybe there's a passthrough
+        // "default" wasn't provided by listManifestByInterface.  Maybe there's a passthrough
         // implementation.
         auto device = Wrapper::WrappedIKeymasterDevice::getService("default");
         if (device) result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, "default")));
@@ -106,6 +106,19 @@
     return result;
 }
 
+void Keymaster::logIfKeymasterVendorError(ErrorCode ec) const {
+    static constexpr int32_t k_keymaster_vendor_error_code_range_max = -10000;
+    if (static_cast<int32_t>(ec) <= k_keymaster_vendor_error_code_range_max) {
+        const auto& versionInfo = halVersion();
+        LOG(ERROR) << "Keymaster reported error: " << static_cast<int32_t>(ec) << "\n"
+                   << "NOTE: This is an error in the vendor specific error range.\n"
+                   << "      Refer to the vendor of the implementation for details.\n"
+                   << "      Implementation name: " << versionInfo.keymasterName << "\n"
+                   << "      Vendor name:         " << versionInfo.authorName << "\n"
+                   << "      MajorVersion:        " << versionInfo.majorVersion;
+    }
+}
+
 Keymaster::KeymasterSet Keymaster::enumerateAvailableDevices() {
     auto serviceManager = IServiceManager::getService();
     CHECK(serviceManager) << "Could not retrieve ServiceManager";
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
index 458053a..43a34b0 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
@@ -65,6 +65,12 @@
     const hidl_string& instanceName() const { return instanceName_; }
 
     /**
+     * If ec is in the vendor error code range (<-10000), logs the fact to logcat.
+     * There are no side effects otherwise.
+     */
+    void logIfKeymasterVendorError(ErrorCode ec) const;
+
+    /**
      * Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least
      * secure (as defined by VersionResult::operator<).
      */
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
index 729e1c1..e35fdd3 100644
--- a/keymaster/4.0/support/keymaster_utils.cpp
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -21,7 +21,9 @@
 namespace hardware {
 
 inline static bool operator<(const hidl_vec<uint8_t>& a, const hidl_vec<uint8_t>& b) {
-    return memcmp(a.data(), b.data(), std::min(a.size(), b.size())) == -1;
+    auto result = memcmp(a.data(), b.data(), std::min(a.size(), b.size()));
+    if (!result) return a.size() < b.size();
+    return result < 0;
 }
 
 template <size_t SIZE>
diff --git a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
index 3876b16..de28683 100644
--- a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
+++ b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
@@ -124,6 +124,65 @@
     // report if times aren't nearly always <1ms apart.
     EXPECT_LE(host_time_delta, km_time_delta + 2);
     EXPECT_LE(km_time_delta, host_time_delta + 2);
+    ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
+    ASSERT_NE(0,
+              memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
+}
+
+/*
+ * Test that the mac changes when the time stamp changes. This is does not guarantee that the time
+ * stamp is included in the mac but on failure we know that it is not. Other than in the test
+ * case above we call verifyAuthorization with the exact same set of parameters.
+ */
+TEST_F(VerificationTokenTest, MacChangesOnChangingTimestamp) {
+    auto result1 =
+            verifyAuthorization(0 /* operation handle */,
+                                AuthorizationSet() /* paramtersToVerify */, HardwareAuthToken());
+    ASSERT_TRUE(result1.callSuccessful);
+    auto result1_time = getTime();
+
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        // StrongBox should not implement verifyAuthorization.
+        EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error);
+        return;
+    }
+
+    EXPECT_EQ(ErrorCode::OK, result1.error);
+    EXPECT_EQ(0U, result1.token.challenge);
+    EXPECT_EQ(SecLevel(), result1.token.securityLevel);
+    EXPECT_EQ(0U, result1.token.parametersVerified.size())
+            << "We didn't supply any parameters to verify";
+    EXPECT_GT(result1.token.timestamp, 0U);
+
+    constexpr uint32_t time_to_sleep = 200;
+    sleep_ms(time_to_sleep);
+
+    auto result2 =
+            verifyAuthorization(0 /* operation handle */,
+                                AuthorizationSet() /* paramtersToVerify */, HardwareAuthToken());
+    ASSERT_TRUE(result2.callSuccessful);
+    auto result2_time = getTime();
+    EXPECT_EQ(ErrorCode::OK, result2.error);
+    EXPECT_EQ(0U, result2.token.challenge);
+    EXPECT_EQ(SecLevel(), result2.token.securityLevel);
+    EXPECT_EQ(0U, result2.token.parametersVerified.size())
+            << "We didn't supply any parameters to verify";
+
+    auto host_time_delta = result2_time - result1_time;
+
+    EXPECT_GE(host_time_delta, time_to_sleep)
+            << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
+    EXPECT_LE(host_time_delta, time_to_sleep + 20)
+            << "The verifyAuthorization call took " << (host_time_delta - time_to_sleep)
+            << " ms?  That's awful!";
+
+    auto km_time_delta = result2.token.timestamp - result1.token.timestamp;
+
+    EXPECT_LE(host_time_delta, km_time_delta + 2);
+    EXPECT_LE(km_time_delta, host_time_delta + 2);
+    ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
+    ASSERT_NE(0,
+              memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
 }
 
 }  // namespace test
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 784ae30..a6bd29a 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -172,6 +172,20 @@
     "E78E70BEFE930DB34818EE4D5C26259F5C6B8E28A652950F9F88D7B4B2C9"
     "D9");
 
+string ec_256_key_rfc5915 =
+        hex2str("308193020100301306072a8648ce3d020106082a8648ce3d030107047930"
+                "770201010420782370a8c8ce5537baadd04dcff079c8158cfa9c67b818b3"
+                "8e8d21c9fa750c1da00a06082a8648ce3d030107a14403420004e2cc561e"
+                "e701da0ad0ef0d176bb0c919d42e79c393fdc1bd6c4010d85cf2cf8e68c9"
+                "05464666f98dad4f01573ba81078b3428570a439ba3229fbc026c550682f");
+
+string ec_256_key_sec1 =
+        hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
+                "6b0201010420782370a8c8ce5537baadd04dcff079c8158cfa9c67b818b3"
+                "8e8d21c9fa750c1da14403420004e2cc561ee701da0ad0ef0d176bb0c919"
+                "d42e79c393fdc1bd6c4010d85cf2cf8e68c905464666f98dad4f01573ba8"
+                "1078b3428570a439ba3229fbc026c550682f");
+
 struct RSA_Delete {
     void operator()(RSA* p) { RSA_free(p); }
 };
@@ -1750,6 +1764,56 @@
 }
 
 /*
+ * ImportKeyTest.EcdsaP256RFC5915Success
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair encoded using RFC5915 works correctly.
+ */
+TEST_F(ImportKeyTest, EcdsaP256RFC5915Success) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaSigningKey(256)
+                                               .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_256_key_rfc5915));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_KEY_SIZE, 256U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaP256SEC1Success
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair encoded using SEC1 works correctly.
+ */
+TEST_F(ImportKeyTest, EcdsaP256SEC1Success) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaSigningKey(256)
+                                               .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_256_key_sec1));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_KEY_SIZE, 256U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
  * ImportKeyTest.Ecdsa521Success
  *
  * Verifies that importing and using an ECDSA P-521 key pair works correctly.
@@ -1854,26 +1918,26 @@
 }
 
 auto wrapped_key = hex2str(
-    "3082017902010004820100A0E69B1395D382354FC0E7F74AC068C5818279D76D46745C7274997D045BAA8B9763B3F3"
-    "09E5E59ECA99273AAAE0A37449DA9B1E67B66EC4E42BB62C25346683A43A9F2ACBCA6D350B25551CC53CE0721D29BE"
-    "90F60686877478F82B3BB111C5EAC0BAE9310D7AD11F5A82948B31C322820F24E20DDB0FBD07D1566DAEAA058D4645"
-    "2607352699E1F631D2ABAF60B13E41ED5EDBB90D252331BDB9CDB1B672E871F37CAC009FE9028B3B1E0ACE8F6F0678"
-    "3F581B860620BDD478969EDE3101AAEFF65C6DB03E143E586167DC87D0CCE39E9119782F7B60A7A1CF2B7EE234E013"
-    "E3DE6C56F0D51F30C389D31FA37C5F2875ACB44434E82EF40B316C93DE129BA0040CD796B02C370F1FA4CC0124F130"
-    "2E0201033029A1083106020100020101A203020120A30402020100A4053103020101A6053103020140BF8377020500"
-    "0420CCD540855F833A5E1480BFD2D36FAF3AEEE15DF5BEABE2691BC82DDE2A7AA910041064C9F689C60FF6223AB6E6"
-    "999E0EB6E5");
+    "3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac84b59b30b"
+    "455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e097474febc981195b"
+    "1d13a69086c0863f66a7b7fdb48792227b1ac5e2489febdf087ab5486483033a6f001ca5d1ec1e27f5c30f4cec2642"
+    "074a39ae68aee552e196627a8e3d867e67a8c01b11e75f13cca0a97ab668b50cda07a8ecb7cd8e3dd7009c9636534f"
+    "6f239cffe1fc8daa466f78b676c7119efb96bce4e69ca2a25d0b34ed9c3ff999b801597d5220e307eaa5bee507fb94"
+    "d1fa69f9e519b2de315bac92c36f2ea1fa1df4478c0ddedeae8c70e0233cd098040cd796b02c370f1fa4cc0124f130"
+    "2e0201033029a1083106020100020101a203020120a30402020100a4053103020101a6053103020140bf8377020500"
+    "0420ccd540855f833a5e1480bfd2d36faf3aeee15df5beabe2691bc82dde2a7aa910041064c9f689c60ff6223ab6e6"
+    "999e0eb6e5");
 
 auto wrapped_key_masked = hex2str(
-    "30820179020100048201001EF5320D3C920D7614688A439409ACE4318C48395ABB7247A68671BD4B7156A7773B31A4"
-    "4459B73858625988A312E4D8855138F555678F525E4C52D91444FDC936BE6AEB63FD73FD84201EF46F88A0B622F528"
-    "956C92C9C731EB65BCBC6A03BEAB45959B54A768E2842D2CE174EE542EF2A15DCAA7542F3574BEEB1A991F95439466"
-    "E1960A9CE9E4CBC77DB23765191E4758C850908BCC74E158B77AB774141F171262C1AC771FDFA2E942F2F7633E97E8"
-    "0BD492C3E821361AC6B4F568DE351C816C8C997212C707F728FB3BCAAA796EA6B8E7A80BE010970B380122940277E9"
-    "4C5E9288F7CB6878A4C4CC1E83AB85A81FD68E43B14F1F81AD21E0D3545D70EE040C6D9721D08589581AB49204A330"
-    "2E0201033029A1083106020100020101A203020120A30402020100A4053103020101A6053103020140BF8377020500"
-    "0420A61C6E247E25B3E6E69AA78EB03C2D4AC20D1F99A9A024A76F35C8E2CAB9B68D04102560C70109AE67C030F00B"
-    "98B512A670");
+    "3082017902010004820100aad93ed5924f283b4bb5526fbe7a1412f9d9749ec30db9062b29e574a8546f33c8873245"
+    "2f5b8e6a391ee76c39ed1712c61d8df6213dec1cffbc17a8c6d04c7b30893d8daa9b2015213e21946821553207f8f9"
+    "931c4caba23ed3bee28b36947e47f10e0a5c3dc51c988a628daad3e5e1f4005e79c2d5a96c284b4b8d7e4948f331e5"
+    "b85dd5a236f85579f3ea1d1b848487470bdb0ab4f81a12bee42c99fe0df4bee3759453e69ad1d68a809ce06b949f76"
+    "94a990429b2fe81e066ff43e56a21602db70757922a4bcc23ab89f1e35da77586775f423e519c2ea394caf48a28d0c"
+    "8020f1dcf6b3a68ec246f615ae96dae9a079b1f6eb959033c1af5c125fd94168040c6d9721d08589581ab49204a330"
+    "2e0201033029a1083106020100020101a203020120a30402020100a4053103020101a6053103020140bf8377020500"
+    "0420a61c6e247e25b3e6e69aa78eb03c2d4ac20d1f99a9a024a76f35c8e2cab9b68d04102560c70109ae67c030f00b"
+    "98b512a670");
 
 auto wrapping_key = hex2str(
     "308204be020100300d06092a864886f70d0101010500048204a8308204a40201000282010100aec367931d8900ce56"
@@ -1912,14 +1976,16 @@
 TEST_F(ImportWrappedKeyTest, Success) {
     auto wrapping_key_desc = AuthorizationSetBuilder()
                                  .RsaEncryptionKey(2048, 65537)
-                                 .Digest(Digest::SHA1)
+                                 .Digest(Digest::SHA_2_256)
                                  .Padding(PaddingMode::RSA_OAEP)
                                  .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
 
     ASSERT_EQ(ErrorCode::OK,
               ImportWrappedKey(
                   wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key,
-                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+                  AuthorizationSetBuilder()
+                      .Digest(Digest::SHA_2_256)
+                      .Padding(PaddingMode::RSA_OAEP)));
 
     string message = "Hello World!";
     auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
@@ -1931,39 +1997,45 @@
 TEST_F(ImportWrappedKeyTest, SuccessMasked) {
     auto wrapping_key_desc = AuthorizationSetBuilder()
                                  .RsaEncryptionKey(2048, 65537)
-                                 .Digest(Digest::SHA1)
+                                 .Digest(Digest::SHA_2_256)
                                  .Padding(PaddingMode::RSA_OAEP)
                                  .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
 
     ASSERT_EQ(ErrorCode::OK,
               ImportWrappedKey(
                   wrapped_key_masked, wrapping_key, wrapping_key_desc, masking_key,
-                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+                  AuthorizationSetBuilder()
+                      .Digest(Digest::SHA_2_256)
+                      .Padding(PaddingMode::RSA_OAEP)));
 }
 
 TEST_F(ImportWrappedKeyTest, WrongMask) {
     auto wrapping_key_desc = AuthorizationSetBuilder()
                                  .RsaEncryptionKey(2048, 65537)
-                                 .Digest(Digest::SHA1)
+                                 .Digest(Digest::SHA_2_256)
                                  .Padding(PaddingMode::RSA_OAEP)
                                  .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
 
     ASSERT_EQ(ErrorCode::VERIFICATION_FAILED,
               ImportWrappedKey(
                   wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key,
-                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+                  AuthorizationSetBuilder()
+                      .Digest(Digest::SHA_2_256)
+                      .Padding(PaddingMode::RSA_OAEP)));
 }
 
 TEST_F(ImportWrappedKeyTest, WrongPurpose) {
     auto wrapping_key_desc = AuthorizationSetBuilder()
                                  .RsaEncryptionKey(2048, 65537)
-                                 .Digest(Digest::SHA1)
+                                 .Digest(Digest::SHA_2_256)
                                  .Padding(PaddingMode::RSA_OAEP);
 
     ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
               ImportWrappedKey(
                   wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key,
-                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+                  AuthorizationSetBuilder()
+                      .Digest(Digest::SHA_2_256)
+                      .Padding(PaddingMode::RSA_OAEP)));
 }
 
 typedef KeymasterHidlTest EncryptionOperationsTest;
@@ -2197,7 +2269,8 @@
               Begin(KeyPurpose::ENCRYPT,
                     AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::SHA_2_256)));
     string result;
-    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+    auto error = Finish(message, &result);
+    EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT);
     EXPECT_EQ(0U, result.size());
 }
 
@@ -2255,7 +2328,8 @@
     auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
     EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
     string result;
-    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+    auto error = Finish(message, &result);
+    EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT);
     EXPECT_EQ(0U, result.size());
 }
 
@@ -3899,6 +3973,33 @@
 }
 
 /*
+ * AttestationTest.EcAttestationByKeySize
+ *
+ * Verifies that attesting to EC keys works and generates the expected output.
+ */
+TEST_F(AttestationTest, EcAttestationByKeySize) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(256)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    ASSERT_EQ(ErrorCode::OK,
+              AttestKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                            .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+                        &cert_chain));
+    EXPECT_GE(cert_chain.size(), 2U);
+    EXPECT_TRUE(verify_chain(cert_chain));
+
+    EXPECT_TRUE(verify_attestation_record("challenge", "foo",                     //
+                                          key_characteristics_.softwareEnforced,  //
+                                          key_characteristics_.hardwareEnforced,  //
+                                          SecLevel(), cert_chain[0]));
+}
+
+/*
  * AttestationTest.EcAttestationRequiresAttestationAppId
  *
  * Verifies that attesting to EC keys requires app ID
diff --git a/light/2.0/Android.bp b/light/2.0/Android.bp
index 6068752..d51f10d 100644
--- a/light/2.0/Android.bp
+++ b/light/2.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/media/1.0/Android.bp b/media/1.0/Android.bp
index 844cfa2..2dbe466 100644
--- a/media/1.0/Android.bp
+++ b/media/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/media/bufferpool/1.0/Android.bp b/media/bufferpool/1.0/Android.bp
index 86297d3..079e47f 100644
--- a/media/bufferpool/1.0/Android.bp
+++ b/media/bufferpool/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/media/omx/1.0/Android.bp b/media/omx/1.0/Android.bp
index ee51d5d..5fe73ab 100644
--- a/media/omx/1.0/Android.bp
+++ b/media/omx/1.0/Android.bp
@@ -23,4 +23,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/memtrack/1.0/Android.bp b/memtrack/1.0/Android.bp
index 0f24977..a50195e 100644
--- a/memtrack/1.0/Android.bp
+++ b/memtrack/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/neuralnetworks/1.0/Android.bp b/neuralnetworks/1.0/Android.bp
index 63b5b98..3e740c4 100644
--- a/neuralnetworks/1.0/Android.bp
+++ b/neuralnetworks/1.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal
index 89af35a..02db063 100644
--- a/neuralnetworks/1.0/types.hal
+++ b/neuralnetworks/1.0/types.hal
@@ -858,20 +858,21 @@
      *   elements of the input matrices.
      *
      * The operation has the following independently optional inputs:
+     * * The cell-to-input weights (\f$W_{ci}\f$), cell-to-forget weights
+     *   (\f$W_{cf}\f$) and cell-to-output weights (\f$W_{co}\f$) either all
+     *   have values or neither of them have values (i.e., all set to null). If
+     *   they have values, the peephole optimization is used.
      * * The input-to-input weights (\f$W_{xi}\f$), recurrent-to-input weights
-     *   (\f$W_{hi}\f$), cell-to-input (\f$W_{ci}\f$) weights, and input gate
-     *   bias (\f$b_i\f$) either all have values, or none of them have values
-     *   (i.e., all set to null). If they have no values, coupling of input and
-     *   forget gates (CIFG) is used, in which case the input gate (\f$i_t\f$)
-     *   is calculated using the following equation instead.
+     *   (\f$W_{hi}\f$) and input gate bias (\f$b_i\f$) either all have values,
+     *   or none of them have values. If they have no values, coupling of input
+     *   and forget gates (CIFG) is used, in which case the input gate
+     *   (\f$i_t\f$) is calculated using the following equation instead.
      *   \f{eqnarray*}{
      *   i_t = 1 - f_t
      *   \f}
-     * * The cell-to-forget weights (\f$W_{cf}\f$) and cell-to-output weights
-     *   (\f$W_{co}\f$) either both have values or neither of them have values.
-     *   If they have values, the peephole optimization is used. Additionally,
-     *   if CIFG is not used, cell-to-input weights (\f$W_{ci}\f$) is also
-     *   required to have values for peephole optimization.
+     *   In case peephole optimization is used and CIFG is not used
+     *   cell-to-input (\f$W_{ci}\f$) weights must be present. Otherwise, the
+     *   cell-to-input weights must have no value.
      * * The projection weights (\f$W_{proj}\f$) is required only for the
      *   recurrent projection layer, and should otherwise have no value.
      * * The projection bias (\f$b_{proj}\f$) may (but not required to) have a
@@ -984,8 +985,8 @@
      * Outputs:
      * * 0: The scratch buffer.
      *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
-     *      [batch_size, num_units * 4] with CIFG, or
-     *      [batch_size, num_units * 3] without CIFG.
+     *      [batch_size, num_units * 3] with CIFG, or
+     *      [batch_size, num_units * 4] without CIFG.
      * * 1: The output state (out) (\f$h_t\f$).
      *      A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
      *      [batch_size, output_size].
@@ -1197,6 +1198,11 @@
      *      shape of the output tensor. The number of elements implied by shape
      *      must be the same as the number of elements in the input tensor.
      *
+     *      If one component of shape is the special value -1, the size of that
+     *      dimension is computed so that the total size remains constant. In
+     *      particular, a shape of [-1] flattens into 1-D. At most one component
+     *      of shape can be -1.
+     *
      * Outputs:
      * * 0: The output tensor, of shape specified by the input shape.
      *
@@ -1220,9 +1226,9 @@
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
      *      the input.
      * * 1: An {@link OperandType::INT32} scalar, specifying the output
-     *      height of the output tensor.
-     * * 2: An {@link OperandType::INT32} scalar, specifying the output
      *      width of the output tensor.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 9057695..0fb18f1 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -71,15 +71,6 @@
         "libneuralnetworks_generated_test_harness_headers",
         "libneuralnetworks_generated_tests",
     ],
-    // Bug: http://b/74200014 - Disable arm32 asan since it triggers internal
-    // error in ld.gold.
-    arch: {
-        arm: {
-            sanitize: {
-                never: true,
-            },
-        },
-    },
     test_suites: ["general-tests"],
 }
 
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 7eea7fc..c819b52 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -52,6 +52,7 @@
 using ::test_helper::MixedTyped;
 using ::test_helper::MixedTypedExample;
 using ::test_helper::resize_accordingly;
+using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
 
 template <typename T>
 void copy_back_(std::map<int, std::vector<T>>* dst, const std::vector<RequestArgument>& ra,
@@ -77,6 +78,13 @@
                   "Number of types in MixedTyped changed, but copy_back function wasn't updated");
 }
 
+static bool isZeroSized(const MixedTyped& example, uint32_t index) {
+    for (auto i : example.operandDimensions.at(index)) {
+        if (i == 0) return true;
+    }
+    return false;
+}
+
 // Top level driver for models and examples generated by test_generator.py
 // Test driver for those generated from ml/nn/runtime/test/spec
 static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>& preparedModel,
@@ -117,9 +125,9 @@
     ADD_FAILURE() << "asking for burst execution at V1_0";
     return nullptr;
 }
-static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst(
+static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst(
         const sp<V1_2::IPreparedModel>& preparedModel) {
-    return ::android::nn::createExecutionBurstController(preparedModel, /*blocking=*/true);
+    return ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
 }
 enum class Executor { ASYNC, SYNC, BURST };
 enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
@@ -178,17 +186,18 @@
         // Go through all outputs, initialize RequestArgument descriptors
         resize_accordingly(golden, test);
         bool sizeLargerThanOne = true;
-        for_all(golden, [&outputs_info, &outputSize, &outputType, &sizeLargerThanOne](
+        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)
+                    if (s > 1 && !isZeroSized(golden, index)) {
                         s -= 1;
-                    else
+                    } else {
                         sizeLargerThanOne = false;
+                    }
                 }
             }
             RequestArgument arg = {
@@ -277,7 +286,7 @@
                 SCOPED_TRACE("burst");
 
                 // create burst
-                const std::unique_ptr<::android::nn::ExecutionBurstController> controller =
+                const std::shared_ptr<::android::nn::ExecutionBurstController> controller =
                         CreateBurst(preparedModel);
                 ASSERT_NE(nullptr, controller.get());
 
@@ -532,7 +541,8 @@
     sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
     ASSERT_NE(nullptr, preparedModelCallback.get());
     Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2(
-        model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
+            model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(),
+            hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
 
diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
index 72a5007..f0c93b7 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
@@ -34,7 +34,6 @@
 namespace functional {
 
 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::for_all;
 using test_helper::MixedTyped;
@@ -42,53 +41,6 @@
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
-static void createPreparedModel(const sp<IDevice>& device, const V1_0::Model& model,
-                                sp<IPreparedModel>* preparedModel) {
-    ASSERT_NE(nullptr, preparedModel);
-
-    // see if service can handle model
-    bool fullySupportsModel = false;
-    Return<void> supportedOpsLaunchStatus = device->getSupportedOperations(
-        model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
-            ASSERT_EQ(ErrorStatus::NONE, status);
-            ASSERT_NE(0ul, supported.size());
-            fullySupportsModel =
-                std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
-        });
-    ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
-
-    // launch prepare model
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk());
-    ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
-
-    // retrieve prepared model
-    preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
-    *preparedModel = preparedModelCallback->getPreparedModel();
-
-    // The getSupportedOperations call returns a list of operations that are
-    // guaranteed not to fail if prepareModel is called, and
-    // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
-    // If a driver has any doubt that it can prepare an operation, it must
-    // return false. So here, if a driver isn't sure if it can support an
-    // operation, but reports that it successfully prepared the model, the test
-    // can continue.
-    if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
-        ASSERT_EQ(nullptr, preparedModel->get());
-        LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
-                     "prepare model that it does not support.";
-        std::cout << "[          ]   Unable to test Request validation because vendor service "
-                     "cannot prepare model that it does not support."
-                  << std::endl;
-        return;
-    }
-    ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
-    ASSERT_NE(nullptr, preparedModel->get());
-}
-
 // Primary validation function. This function will take a valid request, apply a
 // mutation to it to invalidate the request, then pass it to interface calls
 // that use the request. Note that the request here is passed by value, and any
@@ -237,15 +189,8 @@
     return requests;
 }
 
-void ValidationTest::validateRequests(const V1_0::Model& model,
+void ValidationTest::validateRequests(const sp<IPreparedModel>& preparedModel,
                                       const std::vector<Request>& requests) {
-    // create IPreparedModel
-    sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
-
     // validate each request
     for (const Request& request : requests) {
         removeInputTest(preparedModel, request);
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
index 8883057..aee2f85 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
@@ -18,6 +18,10 @@
 
 #include "VtsHalNeuralnetworks.h"
 
+#include <android-base/logging.h>
+
+#include "Callbacks.h"
+
 namespace android {
 namespace hardware {
 namespace neuralnetworks {
@@ -25,6 +29,55 @@
 namespace vts {
 namespace functional {
 
+using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+
+static void createPreparedModel(const sp<IDevice>& device, const V1_0::Model& model,
+                                sp<IPreparedModel>* preparedModel) {
+    ASSERT_NE(nullptr, preparedModel);
+
+    // see if service can handle model
+    bool fullySupportsModel = false;
+    Return<void> supportedOpsLaunchStatus = device->getSupportedOperations(
+            model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
+                ASSERT_EQ(ErrorStatus::NONE, status);
+                ASSERT_NE(0ul, supported.size());
+                fullySupportsModel = std::all_of(supported.begin(), supported.end(),
+                                                 [](bool valid) { return valid; });
+            });
+    ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
+
+    // launch prepare model
+    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+    ASSERT_NE(nullptr, preparedModelCallback.get());
+    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
+    ASSERT_TRUE(prepareLaunchStatus.isOk());
+    ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+    // retrieve prepared model
+    preparedModelCallback->wait();
+    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    *preparedModel = preparedModelCallback->getPreparedModel();
+
+    // The getSupportedOperations call returns a list of operations that are
+    // guaranteed not to fail if prepareModel is called, and
+    // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
+    // If a driver has any doubt that it can prepare an operation, it must
+    // return false. So here, if a driver isn't sure if it can support an
+    // operation, but reports that it successfully prepared the model, the test
+    // can continue.
+    if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
+        ASSERT_EQ(nullptr, preparedModel->get());
+        LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
+                     "prepare model that it does not support.";
+        std::cout << "[          ]   Unable to test Request validation because vendor service "
+                     "cannot prepare model that it does not support."
+                  << std::endl;
+        return;
+    }
+    ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+    ASSERT_NE(nullptr, preparedModel->get());
+}
+
 // A class for test environment setup
 NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
 
@@ -68,6 +121,19 @@
     ::testing::VtsHalHidlTargetTestBase::TearDown();
 }
 
+void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
+    validateModel(model);
+
+    // create IPreparedModel
+    sp<IPreparedModel> preparedModel;
+    ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
+    if (preparedModel == nullptr) {
+        return;
+    }
+
+    validateRequests(preparedModel, requests);
+}
+
 }  // namespace functional
 }  // namespace vts
 }  // namespace V1_0
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
index d4c114d..22285be 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
@@ -63,8 +63,12 @@
 // Tag for the validation tests
 class ValidationTest : public NeuralnetworksHidlTest {
    protected:
-    void validateModel(const Model& model);
-    void validateRequests(const Model& model, const std::vector<Request>& request);
+     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
diff --git a/neuralnetworks/1.1/Android.bp b/neuralnetworks/1.1/Android.bp
index 1158a90..bef21c0 100644
--- a/neuralnetworks/1.1/Android.bp
+++ b/neuralnetworks/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/neuralnetworks/1.1/types.hal b/neuralnetworks/1.1/types.hal
index c9de76b..73705bb 100644
--- a/neuralnetworks/1.1/types.hal
+++ b/neuralnetworks/1.1/types.hal
@@ -104,9 +104,6 @@
      * in axis. If keep_dims is true, the reduced dimensions are retained with
      * length 1.
      *
-     * If dimensions to reduce have no entries, all dimensions are reduced, and
-     * a tensor with a single element is returned.
-     *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
@@ -116,8 +113,14 @@
      * Inputs:
      * * 0: A tensor, specifying the input.
      * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}. The dimensions
-     *      to reduce. If None (the default), reduces all dimensions. Must be in
-     *      the range [-rank(input_tensor), rank(input_tensor)).
+     *      to reduce. Must be in the range
+     *      [-rank(input_tensor), rank(input_tensor)).
+     *
+     *      NOTE: When the operation was introduced, the documentation
+     *      incorrectly stated that if dimensions were empty, the operation
+     *      would reduce across all dimensions. This behavior was never
+     *      implemented.
+     *
      * * 2: An {@link OperandType::INT32} scalar, keep_dims. If positive,
      *      retains reduced dimensions with length 1.
      *
@@ -135,7 +138,7 @@
      *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (the pad value is undefined)
      *
      * Supported tensor rank: up to 4
      *
@@ -158,6 +161,9 @@
      *          output0.dimension[i] =
      *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
      *
+     *      NOTE: The pad value for {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+     *      is undefined.
+     *
      * Available since API level 28.
      */
     PAD = 32,
@@ -186,7 +192,8 @@
      *      must be >= 1.
      * * 2: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings
      *      for each spatial dimension of the input tensor. All values must be
-     *      >= 0. The shape of the tensor must be {rank(input0), 2}.
+     *      >= 0. The shape of the tensor must be {M, 2}, where M is the number
+     *      of spatial dimensions.
      *      padding[i, 0] specifies the number of element to be padded in the
      *      front of dimension i.
      *      padding[i, 1] specifies the number of element to be padded after the
diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
index 5225bf7..f4adbab 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
@@ -34,7 +34,6 @@
 namespace functional {
 
 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::for_all;
 using test_helper::MixedTyped;
@@ -42,54 +41,6 @@
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
-static void createPreparedModel(const sp<IDevice>& device, const V1_1::Model& model,
-                                sp<IPreparedModel>* preparedModel) {
-    ASSERT_NE(nullptr, preparedModel);
-
-    // see if service can handle model
-    bool fullySupportsModel = false;
-    Return<void> supportedOpsLaunchStatus = device->getSupportedOperations_1_1(
-        model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
-            ASSERT_EQ(ErrorStatus::NONE, status);
-            ASSERT_NE(0ul, supported.size());
-            fullySupportsModel =
-                std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
-        });
-    ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
-
-    // launch prepare model
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
-        model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk());
-    ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
-
-    // retrieve prepared model
-    preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
-    *preparedModel = preparedModelCallback->getPreparedModel();
-
-    // The getSupportedOperations_1_1 call returns a list of operations that are
-    // guaranteed not to fail if prepareModel_1_1 is called, and
-    // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
-    // If a driver has any doubt that it can prepare an operation, it must
-    // return false. So here, if a driver isn't sure if it can support an
-    // operation, but reports that it successfully prepared the model, the test
-    // can continue.
-    if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
-        ASSERT_EQ(nullptr, preparedModel->get());
-        LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
-                     "prepare model that it does not support.";
-        std::cout << "[          ]   Unable to test Request validation because vendor service "
-                     "cannot prepare model that it does not support."
-                  << std::endl;
-        return;
-    }
-    ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
-    ASSERT_NE(nullptr, preparedModel->get());
-}
-
 // Primary validation function. This function will take a valid request, apply a
 // mutation to it to invalidate the request, then pass it to interface calls
 // that use the request. Note that the request here is passed by value, and any
@@ -238,15 +189,8 @@
     return requests;
 }
 
-void ValidationTest::validateRequests(const V1_1::Model& model,
+void ValidationTest::validateRequests(const sp<IPreparedModel>& preparedModel,
                                       const std::vector<Request>& requests) {
-    // create IPreparedModel
-    sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
-
     // validate each request
     for (const Request& request : requests) {
         removeInputTest(preparedModel, request);
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
index 224a51d..08069f2 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
@@ -18,6 +18,10 @@
 
 #include "VtsHalNeuralnetworks.h"
 
+#include <android-base/logging.h>
+
+#include "Callbacks.h"
+
 namespace android {
 namespace hardware {
 namespace neuralnetworks {
@@ -25,6 +29,56 @@
 namespace vts {
 namespace functional {
 
+using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+
+static void createPreparedModel(const sp<IDevice>& device, const V1_1::Model& model,
+                                sp<IPreparedModel>* preparedModel) {
+    ASSERT_NE(nullptr, preparedModel);
+
+    // see if service can handle model
+    bool fullySupportsModel = false;
+    Return<void> supportedOpsLaunchStatus = device->getSupportedOperations_1_1(
+            model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
+                ASSERT_EQ(ErrorStatus::NONE, status);
+                ASSERT_NE(0ul, supported.size());
+                fullySupportsModel = std::all_of(supported.begin(), supported.end(),
+                                                 [](bool valid) { return valid; });
+            });
+    ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
+
+    // launch prepare model
+    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+    ASSERT_NE(nullptr, preparedModelCallback.get());
+    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
+            model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
+    ASSERT_TRUE(prepareLaunchStatus.isOk());
+    ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+    // retrieve prepared model
+    preparedModelCallback->wait();
+    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    *preparedModel = preparedModelCallback->getPreparedModel();
+
+    // The getSupportedOperations_1_1 call returns a list of operations that are
+    // guaranteed not to fail if prepareModel_1_1 is called, and
+    // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
+    // If a driver has any doubt that it can prepare an operation, it must
+    // return false. So here, if a driver isn't sure if it can support an
+    // operation, but reports that it successfully prepared the model, the test
+    // can continue.
+    if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
+        ASSERT_EQ(nullptr, preparedModel->get());
+        LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
+                     "prepare model that it does not support.";
+        std::cout << "[          ]   Unable to test Request validation because vendor service "
+                     "cannot prepare model that it does not support."
+                  << std::endl;
+        return;
+    }
+    ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+    ASSERT_NE(nullptr, preparedModel->get());
+}
+
 // A class for test environment setup
 NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
 
@@ -68,6 +122,19 @@
     ::testing::VtsHalHidlTargetTestBase::TearDown();
 }
 
+void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
+    validateModel(model);
+
+    // create IPreparedModel
+    sp<IPreparedModel> preparedModel;
+    ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
+    if (preparedModel == nullptr) {
+        return;
+    }
+
+    validateRequests(preparedModel, requests);
+}
+
 }  // namespace functional
 }  // namespace vts
 }  // namespace V1_1
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index 1c8c0e1..f3f587b 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
@@ -72,8 +72,12 @@
 // Tag for the validation tests
 class ValidationTest : public NeuralnetworksHidlTest {
    protected:
-    void validateModel(const Model& model);
-    void validateRequests(const Model& model, const std::vector<Request>& request);
+     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
diff --git a/neuralnetworks/1.2/Android.bp b/neuralnetworks/1.2/Android.bp
index 085bda1..4aa90aa 100644
--- a/neuralnetworks/1.2/Android.bp
+++ b/neuralnetworks/1.2/Android.bp
@@ -23,4 +23,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/neuralnetworks/1.2/IBurstCallback.hal b/neuralnetworks/1.2/IBurstCallback.hal
index 3f82e31..cc38d7a 100644
--- a/neuralnetworks/1.2/IBurstCallback.hal
+++ b/neuralnetworks/1.2/IBurstCallback.hal
@@ -24,7 +24,7 @@
  */
 interface IBurstCallback {
     /**
-     * Get the memory regions that correspond to slot ids. The slot ids are are
+     * Get the memory regions that correspond to slot ids. The slot ids are
      * unique to the burst object.
      *
      * @param slots Values uniquely identifying memory regions within a Burst.
diff --git a/neuralnetworks/1.2/IDevice.hal b/neuralnetworks/1.2/IDevice.hal
index b9fa388..d83f9e6 100644
--- a/neuralnetworks/1.2/IDevice.hal
+++ b/neuralnetworks/1.2/IDevice.hal
@@ -76,6 +76,17 @@
     getType() generates (ErrorStatus status, DeviceType type);
 
     /**
+     * Gets the capabilities of a driver.
+     *
+     * @return status Error status of the call, must be:
+     *                - NONE if successful
+     *                - DEVICE_UNAVAILABLE if driver is offline or busy
+     *                - GENERAL_FAILURE if there is an unspecified error
+     * @return capabilities Capabilities of the driver.
+     */
+    getCapabilities_1_2() generates (ErrorStatus status, Capabilities capabilities);
+
+    /**
      * Gets information about extensions supported by the driver implementation.
      *
      * All extension operations and operands must be fully supported for the
@@ -113,44 +124,83 @@
             generates (ErrorStatus status, vec<bool> supportedOperations);
 
     /**
-     * Gets whether the driver supports compilation caching.
+     * Gets the caching requirements of the driver implementation.
      *
-     * isCachingSupported indicates whether the driver supports compilation caching.
-     * Even if so, the driver may still choose not to cache certain compiled models.
+     * There are two types of cache file descriptors provided to the driver: model cache
+     * and data cache.
      *
-     * If the device reports the caching is not supported, the user may avoid calling
-     * IDevice::prepareModelFromCache and IPreparedModel::saveToCache.
+     * The data cache is for caching constant data, possibly including preprocessed
+     * and transformed tensor buffers. Any modification to the data cache should
+     * have no worse effect than generating bad output values at execution time.
+     *
+     * The model cache is for caching security-sensitive data such as compiled
+     * executable machine code in the device's native binary format. A modification
+     * to the model cache may affect the driver's execution behavior, and a malicious
+     * client could make use of this to execute beyond the granted permission. Thus,
+     * the driver must always check whether the model cache is corrupted before
+     * preparing the model from cache.
+     *
+     * getNumberOfCacheFilesNeeded returns how many of each type of cache files the driver
+     * implementation needs to cache a single prepared model. Returning 0 for both types
+     * indicates compilation caching is not supported by this driver. The driver may
+     * still choose not to cache certain compiled models even if it reports that caching
+     * is supported.
+     *
+     * If the device reports that caching is not supported, the user may avoid calling
+     * IDevice::prepareModelFromCache or providing cache file descriptors to
+     * IDevice::prepareModel_1_2.
      *
      * @return status Error status of the call, must be:
      *     - NONE if successful
      *     - DEVICE_UNAVAILABLE if driver is offline or busy
      *     - GENERAL_FAILURE if there is an unspecified error
-     * @return supported A boolean indicating whether the driver supports compilation
-     *                   caching. Even on returning true, the driver may still choose
-     *                   not to cache certain compiled models.
+     * @return numModelCache An unsigned integer indicating how many files for model cache
+     *                       the driver needs to cache a single prepared model. It must
+     *                       be less than or equal to Constant::MAX_NUMBER_OF_CACHE_FILES.
+     * @return numDataCache An unsigned integer indicating how many files for data cache
+     *                      the driver needs to cache a single prepared model. It must
+     *                      be less than or equal to Constant::MAX_NUMBER_OF_CACHE_FILES.
      */
-    isCachingSupported() generates (ErrorStatus status, bool supported);
+    getNumberOfCacheFilesNeeded()
+            generates (ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache);
 
     /**
-     * Creates a prepared model for execution.
+     * Asynchronously creates a prepared model for execution and optionally saves it
+     * into cache files.
      *
-     * prepareModel is used to make any necessary transformations or alternative
+     * prepareModel is used to make any necessary transformations to or alternative
      * representations to a model for execution, possibly including
      * transformations on the constant data, optimization on the model's graph,
      * or compilation into the device's native binary format. The model itself
      * is not changed.
      *
+     * Optionally, caching information may be provided for the driver to save
+     * the prepared model to cache files for faster model compilation time
+     * when the same model preparation is requested in the future. There are
+     * two types of cache file handles provided to the driver: model cache
+     * and data cache. For more information on the two types of cache handles,
+     * refer to getNumberOfCacheFilesNeeded.
+     *
+     * The file descriptors must be opened with read and write permission. A file may
+     * have any size, and the corresponding file descriptor may have any offset. The
+     * driver must truncate a file to zero size before writing to that file. The file
+     * descriptors may be closed by the client once the asynchronous preparation has
+     * finished. The driver must dup a file descriptor if it wants to get access to
+     * the cache file later.
+     *
      * The model is prepared asynchronously with respect to the caller. The
-     * prepareModel function must verify the inputs to the prepareModel function
-     * are correct. If there is an error, prepareModel must immediately invoke
+     * prepareModel function must verify the inputs to the preparedModel function
+     * related to preparing the model (as opposed to saving the prepared model to
+     * cache) are correct. If there is an error, prepareModel must immediately invoke
      * the callback with the appropriate ErrorStatus value and nullptr for the
-     * IPreparedModel, then return with the same ErrorStatus. If the inputs to
-     * the prepareModel function are valid and there is no error, prepareModel
-     * must launch an asynchronous task to prepare the model in the background,
-     * and immediately return from prepareModel with ErrorStatus::NONE. If the
-     * asynchronous task fails to launch, prepareModel must immediately invoke
-     * the callback with ErrorStatus::GENERAL_FAILURE and nullptr for the
-     * IPreparedModel, then return with ErrorStatus::GENERAL_FAILURE.
+     * IPreparedModel, then return with the same ErrorStatus. If the inputs to the
+     * prepareModel function that are related to preparing the model are valid and
+     * there is no error, prepareModel must launch an asynchronous task
+     * to prepare the model in the background, and immediately return from
+     * prepareModel with ErrorStatus::NONE. If the asynchronous task fails to launch,
+     * prepareModel must immediately invoke the callback with
+     * ErrorStatus::GENERAL_FAILURE and nullptr for the IPreparedModel, then return
+     * with ErrorStatus::GENERAL_FAILURE.
      *
      * When the asynchronous task has finished preparing the model, it must
      * immediately invoke the callback function provided as an input to
@@ -160,6 +210,14 @@
      * the callback object must be invoked with the appropriate ErrorStatus
      * value and nullptr for the IPreparedModel.
      *
+     * Optionally, the driver may save the prepared model to cache during the
+     * asynchronous preparation. Any error that occurs when saving to cache must
+     * not affect the status of preparing the model. Even if the input arguments
+     * related to the cache may be invalid, or the driver may fail to save to cache,
+     * the prepareModel function must finish preparing the model. The driver
+     * may choose not to save to cache even if the caching information is
+     * provided and valid.
+     *
      * The only information that may be unknown to the model at this stage is
      * the shape of the tensors, which may only be known at execution time. As
      * such, some driver services may return partially prepared models, where
@@ -173,6 +231,26 @@
      * @param model The model to be prepared for execution.
      * @param preference Indicates the intended execution behavior of a prepared
      *     model.
+     * @param modelCache A vector of handles with each entry holding exactly one
+     *     cache file descriptor for the security-sensitive cache. The length of
+     *     the vector must either be 0 indicating that caching information is not provided,
+     *     or match the numModelCache returned from getNumberOfCacheFilesNeeded. The cache
+     *     handles will be provided in the same order when retrieving the
+     *     preparedModel from cache files with prepareModelFromCache.
+     * @param dataCache A vector of handles with each entry holding exactly one
+     *     cache file descriptor for the constants' cache. The length of
+     *     the vector must either be 0 indicating that caching information is not provided,
+     *     or match the numDataCache returned from getNumberOfCacheFilesNeeded. The cache
+     *     handles will be provided in the same order when retrieving the
+     *     preparedModel from cache files with prepareModelFromCache.
+     * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN
+     *     identifying the prepared model. The same token will be provided when retrieving
+     *     the prepared model from the cache files with prepareModelFromCache.
+     *     Tokens should be chosen to have a low rate of collision for a particular
+     *     application. The driver cannot detect a collision; a collision will result
+     *     in a failed execution or in a successful execution that produces incorrect
+     *     output values. If both modelCache and dataCache are empty indicating that
+     *     caching information is not provided, this token must be ignored.
      * @param callback A callback object used to return the error status of
      *     preparing the model for execution and the prepared model if
      *     successful, nullptr otherwise. The callback object's notify function
@@ -182,9 +260,12 @@
      *     - NONE if preparation task is successfully launched
      *     - DEVICE_UNAVAILABLE if driver is offline or busy
      *     - GENERAL_FAILURE if there is an unspecified error
-     *     - INVALID_ARGUMENT if one of the input arguments is invalid
+     *     - INVALID_ARGUMENT if one of the input arguments related to preparing the
+     *       model is invalid
      */
     prepareModel_1_2(Model model, ExecutionPreference preference,
+                     vec<handle> modelCache, vec<handle> dataCache,
+                     uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token,
                      IPreparedModelCallback callback)
           generates (ErrorStatus status);
 
@@ -192,22 +273,17 @@
      * Creates a prepared model from cache files for execution.
      *
      * prepareModelFromCache is used to retrieve a prepared model directly from
-     * cache files to avoid slow model compilation time. There are exactly two
-     * cache file descriptors provided to the driver: modelCache and dataCache.
+     * cache files to avoid slow model compilation time. There are
+     * two types of cache file handles provided to the driver: model cache
+     * and data cache. For more information on the two types of cache handles,
+     * refer to getNumberOfCacheFilesNeeded.
      *
-     * The dataCache is for caching constant data, possibly including preprocessed
-     * and transformed tensor buffers. Any modification to the dataCache should
-     * have no worse effect than generating bad output values at execution time.
-     *
-     * The modelCache is for caching security-sensitive data such as compiled
-     * executable machine code in the device's native binary format. A modification
-     * to the modelCache may affect the driver's execution behavior, and a malicious
-     * client could make use of this to execute beyond the granted permission. Thus,
-     * the driver must always check whether the modelCache is corrupted before preparing
-     * the model from cache.
-     *
-     * The two file descriptors may be closed by the client once the asynchronous
-     * preparation has finished. The driver has to copy all the data it needs.
+     * The file descriptors must be opened with read and write permission. A file may
+     * have any size, and the corresponding file descriptor may have any offset. The
+     * driver must truncate a file to zero size before writing to that file. The file
+     * descriptors may be closed by the client once the asynchronous preparation has
+     * finished. The driver must dup a file descriptor if it wants to get access to
+     * the cache file later.
      *
      * The model is prepared asynchronously with respect to the caller. The
      * prepareModelFromCache function must verify the inputs to the
@@ -241,13 +317,17 @@
      * used with different shapes of inputs on different (possibly concurrent)
      * executions.
      *
-     * @param modelCache A handle holding exactly one cache file descriptor for the
-     *     security-sensitive cache.
-     * @param dataCache A handle holding exactly one cache file descriptor for the
-     *     constants' cache.
+     * @param modelCache A vector of handles with each entry holding exactly one
+     *     cache file descriptor for the security-sensitive cache. The length of
+     *     the vector must match the numModelCache returned from getNumberOfCacheFilesNeeded.
+     *     The cache handles will be provided in the same order as with prepareModel_1_2.
+     * @param dataCache A vector of handles with each entry holding exactly one
+     *     cache file descriptor for the constants' cache. The length of the vector
+     *     must match the numDataCache returned from getNumberOfCacheFilesNeeded.
+     *     The cache handles will be provided in the same order as with prepareModel_1_2.
      * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN
      *     identifying the prepared model. It is the same token provided when saving
-     *     the cache files with IPreparedModel::saveToCache. Tokens should be chosen
+     *     the cache files with prepareModel_1_2. Tokens should be chosen
      *     to have a low rate of collision for a particular application. The driver
      *     cannot detect a collision; a collision will result in a failed execution
      *     or in a successful execution that produces incorrect output values.
@@ -263,7 +343,7 @@
      *       unspecified error
      *     - INVALID_ARGUMENT if one of the input arguments is invalid
      */
-    prepareModelFromCache(handle modelCache, handle dataCache,
+    prepareModelFromCache(vec<handle> modelCache, vec<handle> dataCache,
                           uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token,
                           IPreparedModelCallback callback)
             generates (ErrorStatus status);
diff --git a/neuralnetworks/1.2/IPreparedModel.hal b/neuralnetworks/1.2/IPreparedModel.hal
index 757d5f1..5d2d80f 100644
--- a/neuralnetworks/1.2/IPreparedModel.hal
+++ b/neuralnetworks/1.2/IPreparedModel.hal
@@ -157,62 +157,4 @@
                             fmq_sync<FmqRequestDatum> requestChannel,
                             fmq_sync<FmqResultDatum> resultChannel)
                  generates (ErrorStatus status, IBurstContext context);
-
-    /*
-     * Saves the prepared model to cache files.
-     *
-     * saveToCache is used to save a prepared model to cache files for faster
-     * model compilation time when the same model preparation is requested in
-     * the future. There are exactly two cache file descriptors provided to the
-     * driver: modelCache and dataCache.
-     *
-     * The dataCache is for caching constant data, possibly including preprocessed
-     * and transformed tensor buffers. Any modification to the dataCache should
-     * have no worse effect than generating bad output values at execution time.
-     *
-     * The modelCache is for caching security-sensitive data such as compiled
-     * executable machine code in the device's native binary format. A modification
-     * to the modelCache may affect the driver's execution behavior, and a malicious
-     * client could make use of this to execute beyond the granted permission. Thus,
-     * the driver must always check whether the modelCache is corrupted before preparing
-     * the model from cache.
-     *
-     * The two file descriptors must point to two zero-length files with offset
-     * positioned at the beginning of the file. The file descriptors may be closed
-     * by the client once the method has returned.
-     *
-     * If the driver decides not to save the prepared model without looking at the
-     * input arguments to the saveToCache function, saveToCache must return with
-     * ErrorStatus::GENERAL_FAILURE. Otherwise, the saveToCache function must verify
-     * the input arguments to the saveToCache function are valid, and return with
-     * ErrorStatus::INVALID_ARGUMENT if not. If the inputs are valid but the driver
-     * could not save the prepared model, saveToCache must return with the appropriate
-     * ErrorStatus. Otherwise, it must write the cache files and return
-     * ErrorStatus::NONE. Unless saveToCache returns ErrorStatus::NONE, the contents
-     * of the cache files are undefined.
-     *
-     * @param modelCache A handle holding exactly one cache file descriptor for the
-     *                   security-sensitive cache.
-     * @param dataCache A handle holding exactly one cache file descriptor for the
-     *                  constants' cache.
-     * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN
-     *              identifying the prepared model. The same token will be provided
-     *              when retrieving the prepared model from cache files with
-     *              IDevice::prepareModelFromCache. Tokens should be chosen to have
-     *              a low rate of collision for a particular application. The driver
-     *              cannot detect a collision; a collision will result in a failed
-     *              execution or in a successful execution that produces incorrect
-     *              output values.
-     * @return status Error status of saveToCache, must be:
-     *                - NONE if saveToCache is performed successfully
-     *                - DEVICE_UNAVAILABLE if driver is offline or busy
-     *                - GENERAL_FAILURE if the driver could not save the
-     *                  prepared model or if there is an unspecified error
-     *                - INVALID_ARGUMENT if one of the input arguments is invalid,
-     *                  unless the driver decides not to save the prepared model
-     *                  without looking at the input arguments
-     */
-    saveToCache(handle modelCache, handle dataCache,
-                uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token)
-        generates (ErrorStatus status);
 };
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index bb14dec..f368ce2 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -30,6 +30,11 @@
      * The byte size of the cache token.
      */
     BYTE_SIZE_OF_CACHE_TOKEN = 32,
+
+    /**
+     * The maximum number of files for each type of cache in compilation caching.
+     */
+    MAX_NUMBER_OF_CACHE_FILES = 32,
 };
 
 enum OperandType : @1.0::OperandType {
@@ -182,6 +187,10 @@
      *     input2.dimension = {5, 4, 3, 1}
      *     output.dimension = {5, 4, 3, 2}
      *
+     * Since API level 29, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
      * * {@link OperandType::TENSOR_FLOAT32}
@@ -231,7 +240,8 @@
      *
      * Inputs (explicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input.
+     *      the input. Since API level 29, zero batches is supported for this
+     *      tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
      *      the left, in the ‘width’ dimension.
      * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -257,7 +267,8 @@
      *
      * Inputs (implicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input.
+     *      the input. Since API level 29, zero batches is supported for this
+     *      tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
      *      padding scheme, has to be one of the
      *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
@@ -304,6 +315,7 @@
      *            Before API level 29, all input tensors of
      *            {@link OperandType::TENSOR_QUANT8_ASYMM}
      *            must have the same scale and zeroPoint as the output tensor.
+     *            Since API level 29, zero-sized tensors are supported.
      * * n: An {@link OperandType::INT32} scalar, specifying the
      *      concatenation axis.
      *
@@ -361,7 +373,8 @@
      *
      * Inputs (explicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
-     *      specifying the input.
+     *      specifying the input. Since API level 29, zero batches is supported
+     *      for this tensor.
      * * 1: A 4-D tensor, of shape
      *      [depth_out, filter_height, filter_width, depth_in], specifying the
      *      filter. For tensor of type
@@ -408,7 +421,8 @@
      *
      * Inputs (implicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
-     *      specifying the input.
+     *      specifying the input. Since API level 29, zero batches is supported
+     *      for this tensor.
      * * 1: A 4-D tensor, of shape
      *      [depth_out, filter_height, filter_width, depth_in], specifying the
      *      filter. For tensor of type
@@ -450,11 +464,10 @@
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
-     *      [batches, out_height, out_width, depth_out]. For output tensor of
-     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition
-     *      must be satisfied: output_scale > input_scale * filter_scale (for
-     *      filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
-     *      this condition must be true for all filter scales).
+     *      [batches, out_height, out_width, depth_out]. Before API level 29,
+     *      for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the
+     *      following condition must be satisfied:
+     *      output_scale > input_scale * filter_scale
      *
      * Available since API level 27.
      */
@@ -600,11 +613,10 @@
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
-     *      [batches, out_height, out_width, depth_out]. For output tensor of
-     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition
-     *      must be satisfied: output_scale > input_scale * filter_scale (for
-     *      filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
-     *      this condition must be true for all filter scales).
+     *      [batches, out_height, out_width, depth_out]. Before API level 29,
+     *      for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the
+     *      following condition must be satisfied:
+     *      output_scale > input_scale * filter_scale
      *
      * Available since API level 27.
      */
@@ -672,7 +684,7 @@
      * Supported tensor rank: up to 4
      *
      * Inputs:
-     * * 0: A tensor.
+     * * 0: A tensor. Since API level 29, this tensor may be zero-sized.
      *
      * Outputs:
      * * 0: A tensor with the same shape as input0.
@@ -765,7 +777,8 @@
      *      [batch_size, input_size], where "input_size" corresponds to the
      *      number of inputs to the layer, matching the second dimension of
      *      weights, and "batch_size" is calculated by dividing the number of
-     *      elements by "input_size".
+     *      elements by "input_size". Since API level 29, zero batch_size is
+     *      supported for this tensor.
      * * 1: A 2-D tensor, specifying the weights, of shape
      *      [num_units, input_size], where "num_units" corresponds to the number
      *      of output nodes.
@@ -780,10 +793,10 @@
      *      invoke on the result.
      *
      * Outputs:
-     * * 0: The output tensor, of shape [batch_size, num_units]. For output
-     *      tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following
-     *      condition must be satisfied:
-     *      output_scale > input_scale * filter_scale.
+     * * 0: The output tensor, of shape [batch_size, num_units]. Before API
+     *      level 29, For output tensor of {@link
+     *      OperandType::TENSOR_QUANT8_ASYMM}, the following condition must be
+     *      satisfied: output_scale > input_scale * filter_scale.
      *
      * Available since API level 27.
      */
@@ -861,6 +874,7 @@
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
      * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since API level 29)
      *
      * Supported tensor rank: up to 4
      * Tensors with rank less than 4 are only supported since API level 29.
@@ -875,6 +889,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} and same shape as input0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale must be 1.f / 128 and the zeroPoint must be 128.
      *
      * Available since API level 27.
      */
@@ -905,7 +921,8 @@
      *
      * Inputs (explicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input.
+     *      the input. Since API level 29, zero batches is supported for this
+     *      tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
      *      the left, in the ‘width’ dimension.
      * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -931,7 +948,8 @@
      *
      * Inputs (implicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input.
+     *      the input. Since API level 29, zero batches is supported for this
+     *      tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
      *      padding scheme, has to be one of the
      *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
@@ -987,12 +1005,21 @@
      *      the input.
      * * 1: An {@link OperandType::INT32} scalar, specifying the radius of
      *      the normalization window.
-     * * 2: An {@link OperandType::FLOAT32} scalar, specifying the bias, must
-     *      not be zero.
-     * * 3: An {@link OperandType::FLOAT32} scalar, specifying the scale
-     *      factor, alpha.
-     * * 4: An {@link OperandType::FLOAT32} scalar, specifying the exponent,
-     *      beta.
+     * * 2: A scalar, specifying the bias, must not be zero.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the bias
+     *      value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias
+     *      value must be of {@link OperandType::FLOAT32}.
+     * * 3: A scalar, specifying the scale factor, alpha.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the alpha
+     *      value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the alpha
+     *      value must be of {@link OperandType::FLOAT32}.
+     * * 4: A scalar, specifying the exponent, beta.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the beta
+     *      value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the beta
+     *      value must be of {@link OperandType::FLOAT32}.
      * * 5: An optional {@link OperandType::INT32} scalar, default to -1,
      *      specifying the dimension normalization would be performed on.
      *      Negative index is used to specify axis from the end (e.g. -1 for
@@ -1021,7 +1048,8 @@
      * Supported tensor rank: up to 4.
      *
      * Inputs:
-     * * 0: A tensor, specifying the input.
+     * * 0: A tensor, specifying the input. Since API level 29, this tensor may
+     *      be zero-sized.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
@@ -1149,28 +1177,32 @@
      * https://arxiv.org/pdf/1607.06450.pdf
      *
      * The operation has the following independently optional inputs:
+     * * The cell-to-input weights (\f$W_{ci}\f$), cell-to-forget weights
+     *   (\f$W_{cf}\f$) and cell-to-output weights (\f$W_{co}\f$) either all
+     *   have values or neither of them have values (i.e., all set to null). If
+     *   they have values, the peephole optimization is used.
      * * The input-to-input weights (\f$W_{xi}\f$), recurrent-to-input weights
-     *   (\f$W_{hi}\f$), cell-to-input (\f$W_{ci}\f$) weights, and input gate
-     *   bias (\f$b_i\f$) either all have values, or none of them have values
-     *   (i.e., all set to null). If they have no values, coupling of input and
-     *   forget gates (CIFG) is used, in which case the input gate (\f$i_t\f$)
-     *   is calculated using the following equation instead.
+     *   (\f$W_{hi}\f$) and input gate bias (\f$b_i\f$) either all have values,
+     *   or none of them have values. If they have no values, coupling of input
+     *   and forget gates (CIFG) is used, in which case the input gate
+     *   (\f$i_t\f$) is calculated using the following equation instead.
      *   \f{eqnarray*}{
      *   i_t = 1 - f_t
      *   \f}
-     * * The cell-to-forget weights (\f$W_{cf}\f$) and cell-to-output weights
-     *   (\f$W_{co}\f$) either both have values or neither of them have values.
-     *   If they have values, the peephole optimization is used. Additionally,
-     *   if CIFG is not used, cell-to-input weights (\f$W_{ci}\f$) is also
-     *   required to have values for peephole optimization.
+     *   In case peephole optimization is used and CIFG is not used
+     *   cell-to-input (\f$W_{ci}\f$) weights must be present. Otherwise, the
+     *   cell-to-input weights must have no value.
      * * The projection weights (\f$W_{proj}\f$) is required only for the
      *   recurrent projection layer, and should otherwise have no value.
      * * The projection bias (\f$b_{proj}\f$) may (but not required to) have a
      *   value if the recurrent projection layer exists, and should otherwise
      *   have no value.
      * * (API level >= 29) The four layer normalization weights either all have
-     *   values or none of them have values. Layer normalization is used when
-     *   values are present.
+     *   values or none of them have values. Additionally, if CIFG is used,
+     *   input layer normalization weights tensor is omitted and the other layer
+     *   normalization weights either all have values or none of them have
+     *   values. Layer normalization is used when the values of all the layer
+     *   normalization weights are present.
      *
      * References:
      *
@@ -1333,7 +1365,8 @@
      *
      * Inputs (explicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input.
+     *      the input. Since API level 29, zero batches is supported for this
+     *      tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
      *      the left, in the ‘width’ dimension.
      * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -1359,7 +1392,8 @@
      *
      * Inputs (implicit padding):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input.
+     *      the input. Since API level 29, zero batches is supported for this
+     *      tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
      *      padding scheme, has to be one of the
      *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
@@ -1406,6 +1440,10 @@
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
+     * Since API level 29, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
      * Supported tensor rank: up to 4
      *
      * Inputs:
@@ -1441,7 +1479,8 @@
      * Supported tensor rank: up to 4.
      *
      * Inputs:
-     * * 0: A tensor, specifying the input.
+     * * 0: A tensor, specifying the input. Since API level 29, this tensor may
+     *      be zero-sized.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
@@ -1465,7 +1504,8 @@
      * Supported tensor rank: up to 4.
      *
      * Inputs:
-     * * 0: A tensor, specifying the input.
+     * * 0: A tensor, specifying the input. Since API level 29, this tensor may
+     *      be zero-sized.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
@@ -1489,7 +1529,8 @@
      * Supported tensor rank: up to 4.
      *
      * Inputs:
-     * * 0: A tensor, specifying the input.
+     * * 0: A tensor, specifying the input. Since API level 29, this tensor may
+     *      be zero-sized.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
@@ -1517,6 +1558,11 @@
      *      shape of the output tensor. The number of elements implied by shape
      *      must be the same as the number of elements in the input tensor.
      *
+     *      If one component of shape is the special value -1, the size of that
+     *      dimension is computed so that the total size remains constant. In
+     *      particular, a shape of [-1] flattens into 1-D. At most one component
+     *      of shape can be -1.
+     *
      * Outputs:
      * * 0: The output tensor, of shape specified by the input shape.
      *
@@ -1541,17 +1587,38 @@
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
      *
-     * Inputs:
+     * Both resizing by shape and resizing by scale are supported.
+     *
+     * Inputs (resizing by shape):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input.
+     *      the input. Since API level 29, zero batches is supported for this
+     *      tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the output
-     *      height of the output tensor.
-     * * 2: An {@link OperandType::INT32} scalar, specifying the output
      *      width of the output tensor.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
      * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
      *      Available since API level 29.
      *
+     * Inputs (resizing by scale, since API level 29):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input. Zero batches is supported for this tensor.
+     * * 1: A scalar, specifying width_scale, the scaling factor of the width
+     *      dimension from the input tensor to the output tensor. The output
+     *      width is calculated as new_width = floor(width * width_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 2: A scalar, specifying height_scale, the scaling factor of the height
+     *      dimension from the input tensor to the output tensor. The output
+     *      height is calculated as new_height = floor(height * height_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, new_height, new_width, depth].
@@ -1637,7 +1704,8 @@
      * Tensors with rank other than 2 or 4 are only supported since API level 29.
      *
      * Inputs:
-     * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped.
+     * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped. Since
+     *      API level 29, this tensor may be zero-sized.
      * * 1: A scalar, specifying the positive scaling factor for the exponent,
      *      beta. If input0 is of {@link OperandType::TENSOR_FLOAT32} or
      *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the scalar must be of
@@ -1795,7 +1863,8 @@
      * Supported tensor rank: up to 4.
      *
      * Inputs:
-     * * 0: A tensor, specifying the input.
+     * * 0: A tensor, specifying the input. Since API level 29, this tensor may
+     *      be zero-sized.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0.
@@ -1862,6 +1931,10 @@
      *     input2.dimension = {5, 4, 3, 1}
      *     output.dimension = {5, 4, 3, 2}
      *
+     * Since API level 29, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
      * * {@link OperandType::TENSOR_FLOAT32}
@@ -1891,9 +1964,6 @@
      * in axis. If keep_dims is true, the reduced dimensions are retained with
      * length 1.
      *
-     * If dimensions to reduce have no entries, all dimensions are reduced, and
-     * a tensor with a single element is returned.
-     *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
      * * {@link OperandType::TENSOR_FLOAT32}
@@ -1904,8 +1974,14 @@
      * Inputs:
      * * 0: A tensor, specifying the input.
      * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}. The dimensions
-     *      to reduce. If None (the default), reduces all dimensions. Must be in
-     *      the range [-rank(input_tensor), rank(input_tensor)).
+     *      to reduce. Must be in the range
+     *      [-rank(input_tensor), rank(input_tensor)).
+     *
+     *      NOTE: When the operation was introduced, the documentation
+     *      incorrectly stated that if dimensions were empty, the operation
+     *      would reduce across all dimensions. This behavior was never
+     *      implemented.
+     *
      * * 2: An {@link OperandType::INT32} scalar, keep_dims. If positive,
      *      retains reduced dimensions with length 1.
      *
@@ -1924,7 +2000,8 @@
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (full support since API
+     *   level 29, see the output section)
      *
      * Supported tensor rank: up to 4
      *
@@ -1947,6 +2024,10 @@
      *          output0.dimension[i] =
      *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
      *
+     *      NOTE: Before API level 29, the pad value for
+     *      {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} is undefined.
+     *      Since API level 29, the pad value is always the logical zero.
+     *
      * Available since API level 28.
      */
     PAD = @1.1::OperationType:PAD,
@@ -1979,7 +2060,8 @@
      *      must be >= 1.
      * * 2: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings
      *      for each spatial dimension of the input tensor. All values must be
-     *      >= 0. The shape of the tensor must be {rank(input0), 2}.
+     *      >= 0. The shape of the tensor must be {M, 2}, where M is the number
+     *      of spatial dimensions.
      *      padding[i, 0] specifies the number of element to be padded in the
      *      front of dimension i.
      *      padding[i, 1] specifies the number of element to be padded after the
@@ -2094,6 +2176,10 @@
      *     input2.dimension = {5, 4, 3, 1}
      *     output.dimension = {5, 4, 3, 2}
      *
+     * Since API level 29, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16} (since API level 29)
      * * {@link OperandType::TENSOR_FLOAT32}
@@ -2134,6 +2220,7 @@
      *
      * Inputs:
      * * 0: An n-D tensor, specifying the tensor to be transposed.
+     *      Since API level 29, this tensor may be zero-sized.
      * * 1: An optional 1-D Tensor of {@link OperandType::TENSOR_INT32},
      *      the permutation of the dimensions of the input tensor.
      *
@@ -2230,7 +2317,8 @@
      * * 0: A 2-D Tensor of shape [num_rois, 4], specifying the locations of the
      *      bounding box proposals, each line with format [x1, y1, x2, y2].
      *      For tensor of type {@link OperandType::TENSOR_QUANT16_ASYMM},
-     *      the zeroPoint must be 0 and the scale must be 0.125.
+     *      the zeroPoint must be 0 and the scale must be 0.125. Zero num_rois
+     *      is supported for this tensor.
      * * 1: A 2-D Tensor of shape [num_rois, num_classes * 4], specifying the
      *      bounding box delta for each region of interest and each class. The
      *      bounding box deltas are organized in the following order
@@ -2239,10 +2327,12 @@
      *      and height, dw and dh is the log-scale relative correction factor
      *      for the width and height. For input0 of type
      *      {@link OperandType::TENSOR_QUANT16_ASYMM}, this tensor should be
-     *      of {@link OperandType::TENSOR_QUANT8_ASYMM}.
+     *      of {@link OperandType::TENSOR_QUANT8_ASYMM}. Zero num_rois is
+     *      supported for this tensor.
      * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
      *      [num_rois], specifying the batch index of each box. Boxes with
-     *      the same batch index are grouped together.
+     *      the same batch index are grouped together. Zero num_rois is
+     *      supported for this tensor.
      * * 3: A 2-D Tensor of shape [batches, 2], specifying the information of
      *      each image in the batch, each line with format
      *      [image_height, image_width].
@@ -2271,113 +2361,113 @@
      * Inputs:
      * * 0: The input.
      *      A 3-D tensor of shape:
-     *        If time-major: [max_time, batch_size, output_size]
-     *        If batch-major: [batch_size, max_time, output_size]
+     *        If time-major: [max_time, batch_size, input_size]
+     *        If batch-major: [batch_size, max_time, input_size]
      *      where "max_time" is the number of timesteps (sequence length),
      *      "batch_size" corresponds to the batching dimension, and
      *      "input_size" is the size of the input.
      * * 1: The forward input-to-input weights. Optional.
-     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
-     *      corresponds to the number of cell units.
+     *      A 2-D tensor of shape [fw_num_units, input_size], where “fw_num_units”
+     *      corresponds to the number of forward cell units.
      * * 2: The forward input-to-forget weights.
-     *      A 2-D tensor of shape [num_units, input_size].
+     *      A 2-D tensor of shape [fw_num_units, input_size].
      * * 3: The forward input-to-cell weights.
-     *      A 2-D tensor of shape [num_units, input_size].
+     *      A 2-D tensor of shape [fw_num_units, input_size].
      * * 4: The forward input-to-output weights.
-     *      A 2-D tensor of shape [num_units, input_size].
+     *      A 2-D tensor of shape [fw_num_units, input_size].
      * * 5: The forward recurrent-to-input weights. Optional.
-     *      A 2-D tensor of shape [num_units, output_size], where “output_size”
-     *      corresponds to either the number of cell units (i.e., “num_units”),
-     *      or the second dimension of the “projection_weights”, if defined.
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size], where “fw_output_size”
+     *      corresponds to either the number of cell units (i.e., fw_num_units),
+     *      or the second dimension of the “fw_projection_weights”, if defined.
      * * 6: The forward recurrent-to-forget weights.
-     *      A 2-D tensor of shape [num_units, output_size].
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size].
      * * 7: The forward recurrent-to-cell weights.
-     *      A 2-D tensor of shape [num_units, output_size].
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size].
      * * 8: The forward recurrent-to-output weights.
-     *      A 2-D tensor of shape [num_units, output_size].
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size].
      * * 9: The forward cell-to-input weights. Optional.
-     *      A 1-D tensor of shape [num_units].
+     *      A 1-D tensor of shape [fw_num_units].
      * * 10: The forward cell-to-forget weights. Optional.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [fw_num_units].
      * * 11: The forward cell-to-output weights. Optional.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [fw_num_units].
      * * 12: The forward input gate bias. Optional.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [fw_num_units].
      * * 13: The forward forget gate bias.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [fw_num_units].
      * * 14: The forward cell gate bias.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [fw_num_units].
      * * 15: The forward output gate bias.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [fw_num_units].
      * * 16: The forward projection weights. Optional.
-     *       A 2-D tensor of shape [output_size, num_units].
+     *       A 2-D tensor of shape [fw_output_size, fw_num_units].
      * * 17: The forward projection bias. Optional.
-     *       A 1-D tensor of shape [output_size].
+     *       A 1-D tensor of shape [fw_output_size].
      * * 18: The backward input-to-input weights. Optional.
-     *       A 2-D tensor of shape [num_units, input_size], where “num_units”
-     *       corresponds to the number of cell units.
+     *       A 2-D tensor of shape [bw_num_units, input_size], where “bw_num_units”
+     *       corresponds to the number of backward cell units.
      * * 19: The backward input-to-forget weights.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [bw_num_units, input_size].
      * * 20: The backward input-to-cell weights.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [bw_num_units, input_size].
      * * 21: The backward input-to-output weights.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [bw_num_units, input_size].
      * * 22: The backward recurrent-to-input weights. Optional.
-     *       A 2-D tensor of shape [num_units, output_size], where “output_size”
-     *       corresponds to either the number of cell units (i.e., “num_units”),
-     *       or the second dimension of the “projection_weights”, if defined.
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size], where “bw_output_size”
+     *       corresponds to either the number of cell units (i.e., “bw_num_units”),
+     *       or the second dimension of the “bw_projection_weights”, if defined.
      * * 23: The backward recurrent-to-forget weights.
-     *       A 2-D tensor of shape [num_units, output_size].
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size].
      * * 24: The backward recurrent-to-cell weights.
-     *       A 2-D tensor of shape [num_units, output_size].
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size].
      * * 25: The backward recurrent-to-output weights.
-     *       A 2-D tensor of shape [num_units, output_size].
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size].
      * * 26: The backward cell-to-input weights. Optional.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [bw_num_units].
      * * 27: The backward cell-to-forget weights. Optional.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [bw_num_units].
      * * 28: The backward cell-to-output weights. Optional.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [bw_num_units].
      * * 29: The backward input gate bias. Optional.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [bw_num_units].
      * * 30: The backward forget gate bias.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [bw_num_units].
      * * 31: The backward cell gate bias.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [bw_num_units].
      * * 32: The backward output gate bias.
-     *       A 1-D tensor of shape [num_units].
+     *       A 1-D tensor of shape [bw_num_units].
      * * 33: The backward projection weights. Optional.
-     *       A 2-D tensor of shape [output_size, num_units].
+     *       A 2-D tensor of shape [bw_output_size, bw_num_units].
      * * 34: The backward projection bias. Optional.
-     *       A 1-D tensor of shape [output_size].
+     *       A 1-D tensor of shape [bw_output_size].
      * * 35: The forward input activation state.
-     *       A 2-D tensor of shape [batch_size, output_size].
+     *       A 2-D tensor of shape [batch_size, bw_output_size].
      * * 36: The forward input cell state.
-     *       A 2-D tensor of shape [batch_size, num_units].
+     *       A 2-D tensor of shape [batch_size, bw_num_units].
      * * 37: The backward input activation state.
-     *       A 2-D tensor of shape [batch_size, output_size].
+     *       A 2-D tensor of shape [batch_size, bw_output_size].
      * * 38: The backward input cell state.
-     *       A 2-D tensor of shape [batch_size, num_units].
+     *       A 2-D tensor of shape [batch_size, bw_num_units].
      * * 39: The auxiliary input. Optional.
      *       A 3-D tensor of shape [max_time, batch_size, input_size], where “batch_size”
      *       corresponds to the batching dimension, and “input_size” is the size
      *       of the input.
      * * 40: The forward auxiliary input-to-input weights. Optional.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [fw_num_units, input_size].
      * * 41: The forward auxiliary input-to-forget weights. Optional.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [fw_num_units, input_size].
      * * 42: The forward auxiliary input-to-cell weights. Optional.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [fw_num_units, input_size].
      * * 43: The forward auxiliary input-to-output weights. Optional.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [fw_num_units, input_size].
      * * 44: The backward auxiliary input-to-input weights. Optional.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [bw_num_units, input_size].
      * * 45: The backward auxiliary input-to-forget weights. Optional.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [bw_num_units, input_size].
      * * 46: The backward auxiliary input-to-cell weights. Optional.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [bw_num_units, input_size].
      * * 47: The backward auxiliary input-to-output weights. Optional.
-     *       A 2-D tensor of shape [num_units, input_size].
+     *       A 2-D tensor of shape [bw_num_units, input_size].
      * * 48: The activation function.
      *       A value indicating the activation function:
      *       <ul>
@@ -2409,16 +2499,46 @@
      * * 52: time_major
      *       An {@link OperandType::BOOL} scalar specifying the shape format
      *       of input and output tensors.
+     * * 53: The forward input layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at input gate.
+     * * 54: The forward forget layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at forget gate.
+     * * 55: The forward cell layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at cell gate.
+     * * 56: The forward output layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at output gate.
+     * * 57: The backward input layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at input gate.
+     * * 58: The backward forget layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at forget gate.
+     * * 59: The backward cell layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at cell gate.
+     * * 60: The backward output layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at output gate.
      *
      * Outputs:
      * * 0: The forward output.
      *      A 3-D tensor of shape:
-     *        If time-major: [max_time, batch_size, output_size]
-     *        If batch-major: [batch_size, max_time, output_size]
+     *        If time-major and not merge_outputs:
+     *          [max_time, batch_size, fw_output_size]
+     *        If time-major and merge_outputs:
+     *          [max_time, batch_size, fw_output_size + bw_output_size]
+     *        If batch-major and not merge_outputs:
+     *          [batch_size, max_time, fw_output_size]
+     *        If batch-major and merge_outputs:
+     *          [batch_size, max_time, fw_output_size + bw_output_size]
      * * 1: The backward output.  Unused if merge_outputs is true.
      *      A 3-D tensor of shape:
-     *        If time-major: [max_time, batch_size, output_size]
-     *        If batch-major: [batch_size, max_time, output_size]
+     *        If time-major: [max_time, batch_size, bw_output_size]
+     *        If batch-major: [batch_size, max_time, bw_output_size]
      *
      * Available since API level 29.
      */
@@ -2546,10 +2666,17 @@
     /**
      * Greedily selects a subset of bounding boxes in descending order of score.
      *
-     * This op applies hard NMS algorithm to each class. In each loop of
-     * execution, the box with maximum score gets selected, and any boxes with
-     * the intersection-over-union (IOU) greater than a threshold are removed
-     * from the pending set.
+     * This op applies NMS algorithm to each class. In each loop of execution,
+     * the box with maximum score gets selected and removed from the pending set.
+     * The scores of the rest of boxes are lowered according to the
+     * intersection-over-union (IOU) overlapping with the previously selected
+     * boxes and a specified NMS kernel method. Any boxes with score less
+     * than a threshold are removed from the pending set.
+     *
+     * Three NMS kernels are supported:
+     * * Hard:     score_new = score_old * (1 if IoU < threshold else 0)
+     * * Linear:   score_new = score_old * (1 if IoU < threshold else 1 - IoU)
+     * * Gaussian: score_new = score_old * exp(- IoU^2 / sigma)
      *
      * Axis-aligned bounding boxes are represented by its upper-left corner
      * coordinate (x1,y1) and lower-right corner coordinate (x2,y2). A valid
@@ -2563,25 +2690,34 @@
      * Inputs:
      * * 0: A 2-D Tensor of shape [num_rois, num_classes], specifying the score
      *      of each bounding box proposal. The boxes are grouped by batches in the
-     *      first dimension.
+     *      first dimension. Zero num_rois is supported for this tensor.
      * * 1: A 2-D Tensor specifying the bounding boxes of shape
      *      [num_rois, num_classes * 4], organized in the order [x1, y1, x2, y2].
      *      The boxes are grouped by batches in the first dimension. The sequential
      *      order of the boxes corresponds with input0. For input0 of type
      *      {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of
      *      {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint of 0 and
-     *      scale of 0.125.
+     *      scale of 0.125. Zero num_rois is supported for this tensor.
      * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
      *      [num_rois], specifying the batch index of each box. Boxes with
      *      the same batch index are grouped together.
      * * 3: An {@link OperandType::FLOAT32} scalar, score_threshold. Boxes
      *      with scores lower than the threshold are filtered before sending
      *      to the NMS algorithm.
-     * * 4: An {@link OperandType::FLOAT32} scalar, specifying the IoU
-     *      threshold.
-     * * 5: An {@link OperandType::INT32} scalar, specifying the maximum
+     * * 4: An {@link OperandType::INT32} scalar, specifying the maximum
      *      number of selected bounding boxes for each image. Set to a negative
      *      value for unlimited number of output bounding boxes.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the NMS
+     *      kernel method, options are 0:hard, 1:linear, 2:gaussian.
+     * * 6: An {@link OperandType::FLOAT32} scalar, specifying the IoU
+     *      threshold in hard and linear NMS kernel. This field is ignored if
+     *      gaussian kernel is selected.
+     * * 7: An {@link OperandType::FLOAT32} scalar, specifying the sigma in
+     *      gaussian NMS kernel. This field is ignored if gaussian kernel is
+     *      not selected.
+     * * 8: An {@link OperandType::FLOAT32} scalar, nms_score_threshold.
+     *      Boxes with scores lower than the threshold are dropped during the
+     *      score updating phase in soft NMS.
      *
      * Outputs:
      * * 0: A 1-D Tensor of the same {@link OperandType} as input0, with shape
@@ -2599,8 +2735,8 @@
      *      [num_output_rois], specifying the class of each output box. The
      *      sequential order of the boxes corresponds with output0.
      * * 3: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
-     *      [num_rois], specifying the batch index of each box. Boxes with
-     *      the same batch index are grouped together.
+     *      [num_output_rois], specifying the batch index of each box. Boxes
+     *      with the same batch index are grouped together.
      *
      * Available since API level 29.
      */
@@ -2936,8 +3072,8 @@
      *      For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the
      *      scale must be 0.125 and the zero point must be 0.
      * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
-     *      [num_rois], specifying the batch index of each box. Boxes with
-     *      the same batch index are grouped together.
+     *      [num_output_rois], specifying the batch index of each box. Boxes
+     *      with the same batch index are grouped together.
      *
      * Available since API level 29.
      */
@@ -3121,11 +3257,7 @@
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
-     *      [batches, out_height, out_width, depth_out]. For output tensor of
-     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition
-     *      must be satisfied: output_scale > input_scale * filter_scale (for
-     *      filter tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
-     *      this condition must be true for all filter scales).
+     *      [batches, out_height, out_width, depth_out].
      *
      * Available since API level 29.
      */
@@ -3378,8 +3510,12 @@
      *
      * Inputs:
      * * 0: A tensor specifying the input logits.
-     * * 1: An {@link OperandType::FLOAT32} scalar, specifying the positive
-     *      scaling factor for the exponent, beta.
+     * * 1: A scalar, specifying the positive scaling factor for the exponent,
+     *      beta.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the beta
+     *      value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the beta
+     *      value must be of {@link OperandType::FLOAT32}.
      * * 2: An {@link OperandType::INT32} scalar specifying the axis to
      *      reduce across. Negative index is used to specify axis from the
      *      end (e.g. -1 for the last axis). Must be in the range [-n, n).
@@ -3401,13 +3537,15 @@
      * * {@link OperandType::TENSOR_INT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
+     * Supported tensor rank: from 1.
+     *
      * Inputs:
      * * 0: A tensor.
      * * 1: A tensor of the same {@link OperandType} and compatible dimensions
      *      with input0.
      *
      * Outputs:
-     * * 0: The sum, a tensor of the same {@link OperandType} as input0.
+     * * 0: A tensor of the same {@link OperandType} as input0.
      *
      * Available since API level 29.
      */
@@ -3422,13 +3560,15 @@
      * * {@link OperandType::TENSOR_INT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
+     * Supported tensor rank: from 1.
+     *
      * Inputs:
      * * 0: A tensor.
      * * 1: A tensor of the same {@link OperandType} and compatible dimensions
      *      with input0.
      *
      * Outputs:
-     * * 0: The sum, a tensor of the same {@link OperandType} as input0.
+     * * 0: A tensor of the same {@link OperandType} as input0.
      *
      * Available since API level 29.
      */
@@ -3607,7 +3747,7 @@
      * Supported tensor rank: from 1
      *
      * Inputs:
-     * * 0: A tensor.
+     * * 0: A tensor, may be zero-sized.
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0, but with
@@ -3939,10 +4079,12 @@
      *      the regions of interest, each line with format [x1, y1, x2, y2].
      *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM},
-     *      with zeroPoint of 0 and scale of 0.125.
+     *      with zeroPoint of 0 and scale of 0.125. Zero num_rois is
+     *      supported for this tensor.
      * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
      *      [num_rois], specifying the batch index of each box. Boxes with
-     *      the same batch index are grouped together.
+     *      the same batch index are grouped together. Zero num_rois is
+     *      supported for this tensor.
      * * 3: An {@link OperandType::INT32} scalar, specifying the output
      *      height of the output tensor.
      * * 4: An {@link OperandType::INT32} scalar, specifying the output
@@ -4107,7 +4249,7 @@
      * Supported tensor rank: from 1
      *
      * Inputs:
-     * * 0: An n-D tensor to take slice from.
+     * * 0: An n-D tensor to take slice from, may be zero-sized.
      * * 1: A 1-D tensor of type {@link OperandType::TENSOR_INT32} specifying
      *      the beginning indices of the slice in each dimension.
      * * 2: A 1-D tensor of type {@link OperandType::TENSOR_INT32} specifying
@@ -4330,11 +4472,7 @@
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
-     *      [batches, out_height, out_width, depth_out]. For output tensor of
-     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition
-     *      must be satisfied: output_scale > input_scale * filter_scale (for
-     *      filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
-     *      this condition must be true for all filter scales).
+     *      [batches, out_height, out_width, depth_out].
      *
      * Available since API level 29.
      */
@@ -4366,9 +4504,9 @@
      * Inputs:
      * * 0: The input (\f$x_t\f$).
      *      A 3-D tensor of shape:
-     *        If time-major: [max_time, batch_size, output_size]
-     *        If batch-major: [batch_size, max_time, output_size]
-     *      where “max_size” is the number of timesteps (sequence length),
+     *        If time-major: [max_time, batch_size, input_size]
+     *        If batch-major: [batch_size, max_time, input_size]
+     *      where “max_time” is the number of timesteps (sequence length),
      *      “batch_size” corresponds to the batching dimension, and
      *      “input_size” is the size of the input.
      * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional.
@@ -4428,16 +4566,16 @@
      *      projection layer, such that values are bound within
      *      [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
      * * 23:Time-major if true, batch-major if false.
-     * * 24:The input layer normalization weights.
+     * * 24:The input layer normalization weights. Optional.
      *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
      *      to activation at input gate.
-     * * 25:The forget layer normalization weights.
+     * * 25:The forget layer normalization weights. Optional.
      *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
      *      to activation at forget gate.
-     * * 26:The cell layer normalization weights.
+     * * 26:The cell layer normalization weights. Optional.
      *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
      *      to activation at cell gate.
-     * * 27:The output layer normalization weights.
+     * * 27:The output layer normalization weights. Optional.
      *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
      *      to activation at output gate.
      *
@@ -4525,13 +4663,33 @@
      * [batch, height, width, channels]. Alternatively, the data layout could
      * be NCHW, the data storage order of: [batch, channels, height, width].
      *
-     * Inputs:
+     * Both resizing by shape and resizing by scale are supported.
+     *
+     * Inputs (resizing by shape):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
-     *      the input.
+     *      the input. Zero batches is supported for this tensor.
      * * 1: An {@link OperandType::INT32} scalar, specifying the output
-     *      height of the output tensor.
-     * * 2: An {@link OperandType::INT32} scalar, specifying the output
      *      width of the output tensor.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
+     * * 3: An {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *
+     * Inputs (resizing by scale):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input. Zero batches is supported for this tensor.
+     * * 1: A scalar, specifying width_scale, the scaling factor of the width
+     *      dimension from the input tensor to the output tensor. The output
+     *      width is calculated as new_width = floor(width * width_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 2: A scalar, specifying height_scale, the scaling factor of the height
+     *      dimension from the input tensor to the output tensor. The output
+     *      height is calculated as new_height = floor(height * height_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
      * * 3: An {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
      *
@@ -4592,6 +4750,39 @@
 };
 
 /**
+ * The capabilities of a driver.
+ *
+ * Performance of an operation comes from the type of its first operand.
+ * This represents performance for non extension operand types.
+ */
+struct Capabilities {
+    /**
+     * Driver performance when operating on float32 data but performing
+     * calculations with range and/or precision as low as that of the IEEE
+     * 754 16-bit floating-point format.
+     */
+    PerformanceInfo relaxedFloat32toFloat16PerformanceScalar;
+    PerformanceInfo relaxedFloat32toFloat16PerformanceTensor;
+
+    /**
+     * Driver performance when operating on a particular data type.
+     * In the case of float32 data, this is used when the calculations
+     * are not relaxed.
+     */
+    struct OperandPerformance {
+        OperandType type;
+        PerformanceInfo info;
+    };
+
+    /**
+     * Performance by operand type. Must be sorted by OperandType.
+     * If a particular OperandType is not present in operandPerformance,
+     * its performance is treated as { .execTime = FLT_MAX, .powerUsage = FLT_MAX }.
+     */
+    vec<OperandPerformance> operandPerformance;
+};
+
+/**
  * Describes one operation of the model's graph.
  */
 struct Operation {
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 891b414..6c26820 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -20,6 +20,7 @@
     defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
     srcs: [
         "GeneratedTestsV1_0.cpp",
+        "ValidateBurst.cpp",
     ],
     cflags: [
         "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
@@ -32,6 +33,7 @@
     defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
     srcs: [
         "GeneratedTestsV1_1.cpp",
+        "ValidateBurst.cpp",
     ],
     cflags: [
         "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
@@ -46,6 +48,7 @@
         "BasicTests.cpp",
         "CompilationCachingTests.cpp",
         "GeneratedTests.cpp",
+        "ValidateBurst.cpp",
     ],
     cflags: [
         "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
@@ -58,6 +61,7 @@
     srcs: [
         "BasicTests.cpp",
         "GeneratedTests.cpp",
+        "ValidateBurst.cpp",
     ],
     cflags: [
         "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE",
diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
index 365a750..5c269df 100644
--- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
@@ -25,7 +25,7 @@
 namespace vts {
 namespace functional {
 
-using V1_1::Capabilities;
+using V1_0::PerformanceInfo;
 
 // create device test
 TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
@@ -37,6 +37,31 @@
     EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
 }
 
+// initialization
+TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+    using OperandPerformance = Capabilities::OperandPerformance;
+    Return<void> ret = device->getCapabilities_1_2([](ErrorStatus status,
+                                                      const Capabilities& capabilities) {
+        EXPECT_EQ(ErrorStatus::NONE, status);
+
+        auto isPositive = [](const PerformanceInfo& perf) {
+            return perf.execTime > 0.0f && perf.powerUsage > 0.0f;
+        };
+
+        EXPECT_TRUE(isPositive(capabilities.relaxedFloat32toFloat16PerformanceScalar));
+        EXPECT_TRUE(isPositive(capabilities.relaxedFloat32toFloat16PerformanceTensor));
+        const auto& opPerf = capabilities.operandPerformance;
+        EXPECT_TRUE(std::all_of(
+                opPerf.begin(), opPerf.end(),
+                [isPositive](const OperandPerformance& a) { return isPositive(a.info); }));
+        EXPECT_TRUE(std::is_sorted(opPerf.begin(), opPerf.end(),
+                                   [](const OperandPerformance& a, const OperandPerformance& b) {
+                                       return a.type < b.type;
+                                   }));
+    });
+    EXPECT_TRUE(ret.isOk());
+}
+
 // device version test
 TEST_F(NeuralnetworksHidlTest, GetDeviceVersionStringTest) {
     Return<void> ret = device->getVersionString([](ErrorStatus status, const hidl_string& version) {
@@ -77,10 +102,15 @@
     EXPECT_TRUE(ret.isOk());
 }
 
-// isCachingSupported test
-TEST_F(NeuralnetworksHidlTest, IsCachingSupported) {
-    Return<void> ret = device->isCachingSupported(
-            [](ErrorStatus status, bool) { EXPECT_EQ(ErrorStatus::NONE, status); });
+// getNumberOfCacheFilesNeeded test
+TEST_F(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) {
+    Return<void> ret = device->getNumberOfCacheFilesNeeded(
+            [](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) {
+                EXPECT_EQ(ErrorStatus::NONE, status);
+                EXPECT_LE(numModelCache,
+                          static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES));
+                EXPECT_LE(numDataCache, static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES));
+            });
     EXPECT_TRUE(ret.isOk());
 }
 }  // namespace functional
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 00989e5..4411b90 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -16,21 +16,22 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
-#include "VtsHalNeuralnetworks.h"
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <ftw.h>
+#include <gtest/gtest.h>
+#include <hidlmemory/mapping.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <random>
 
 #include "Callbacks.h"
 #include "GeneratedTestHarness.h"
 #include "TestHarness.h"
 #include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-#include <cstdio>
-#include <cstdlib>
-#include <random>
-
-#include <gtest/gtest.h>
+#include "VtsHalNeuralnetworks.h"
 
 namespace android {
 namespace hardware {
@@ -44,9 +45,9 @@
 using ::android::nn::allocateSharedMemory;
 using ::test_helper::MixedTypedExample;
 
-namespace {
+namespace float32_model {
 
-// In frameworks/ml/nn/runtime/tests/generated/, creates a hidl model of mobilenet.
+// In frameworks/ml/nn/runtime/test/generated/, creates a hidl model of float32 mobilenet.
 #include "examples/mobilenet_224_gender_basic_fixed.example.cpp"
 #include "vts_models/mobilenet_224_gender_basic_fixed.model.cpp"
 
@@ -54,95 +55,338 @@
 [[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape;
 [[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape;
 
-enum class AccessMode { READ_ONLY, WRITE_ONLY };
+// 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}}}}}}};
+}
 
-void createCacheHandle(const std::vector<std::string>& files, AccessMode mode,
-                       hidl_handle* handle) {
-    std::vector<int> fds;
-    for (const auto& file : files) {
-        int fd;
-        if (mode == AccessMode::READ_ONLY) {
-            fd = open(file.c_str(), O_RDONLY);
-        } else if (mode == AccessMode::WRITE_ONLY) {
-            fd = open(file.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
-        } else {
-            FAIL();
+}  // namespace float32_model
+
+namespace quant8_model {
+
+// In frameworks/ml/nn/runtime/test/generated/, creates a hidl model of quant8 mobilenet.
+#include "examples/mobilenet_quantized.example.cpp"
+#include "vts_models/mobilenet_quantized.model.cpp"
+
+// Prevent the compiler from complaining about an otherwise unused function.
+[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape;
+[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape;
+
+// MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h.
+// This function assumes the operation is always ADD.
+std::vector<MixedTypedExample> getLargeModelExamples(uint32_t len) {
+    uint8_t outputValue = 1 + static_cast<uint8_t>(len);
+    return {{.operands = {// Input
+                          {.operandDimensions = {{0, {1}}}, .quant8AsymmOperands = {{0, {1}}}},
+                          // Output
+                          {.operandDimensions = {{0, {1}}},
+                           .quant8AsymmOperands = {{0, {outputValue}}}}}}};
+}
+
+}  // namespace quant8_model
+
+namespace {
+
+enum class AccessMode { READ_WRITE, READ_ONLY, WRITE_ONLY };
+
+// Creates cache handles based on provided file groups.
+// The outer vector corresponds to handles and the inner vector is for fds held by each handle.
+void createCacheHandles(const std::vector<std::vector<std::string>>& fileGroups,
+                        const std::vector<AccessMode>& mode, hidl_vec<hidl_handle>* handles) {
+    handles->resize(fileGroups.size());
+    for (uint32_t i = 0; i < fileGroups.size(); i++) {
+        std::vector<int> fds;
+        for (const auto& file : fileGroups[i]) {
+            int fd;
+            if (mode[i] == AccessMode::READ_ONLY) {
+                fd = open(file.c_str(), O_RDONLY);
+            } else if (mode[i] == AccessMode::WRITE_ONLY) {
+                fd = open(file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+            } else if (mode[i] == AccessMode::READ_WRITE) {
+                fd = open(file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+            } else {
+                FAIL();
+            }
+            ASSERT_GE(fd, 0);
+            fds.push_back(fd);
         }
-        ASSERT_GE(fd, 0);
-        fds.push_back(fd);
+        native_handle_t* cacheNativeHandle = native_handle_create(fds.size(), 0);
+        ASSERT_NE(cacheNativeHandle, nullptr);
+        std::copy(fds.begin(), fds.end(), &cacheNativeHandle->data[0]);
+        (*handles)[i].setTo(cacheNativeHandle, /*shouldOwn=*/true);
     }
-    native_handle_t* cacheNativeHandle = native_handle_create(fds.size(), 0);
-    ASSERT_NE(cacheNativeHandle, nullptr);
-    for (uint32_t i = 0; i < fds.size(); i++) {
-        cacheNativeHandle->data[i] = fds[i];
+}
+
+void createCacheHandles(const std::vector<std::vector<std::string>>& fileGroups, AccessMode mode,
+                        hidl_vec<hidl_handle>* handles) {
+    createCacheHandles(fileGroups, std::vector<AccessMode>(fileGroups.size(), mode), handles);
+}
+
+// Create a chain of broadcast operations. The second operand is always constant tensor [1].
+// For simplicity, activation scalar is shared. The second operand is not shared
+// in the model to let driver maintain a non-trivial size of constant data and the corresponding
+// data locations in cache.
+//
+//                --------- activation --------
+//                ↓      ↓      ↓             ↓
+// E.g. input -> ADD -> ADD -> ADD -> ... -> ADD -> output
+//                ↑      ↑      ↑             ↑
+//               [1]    [1]    [1]           [1]
+//
+// This function assumes the operation is either ADD or MUL.
+template <typename CppType, OperandType operandType>
+Model createLargeTestModelImpl(OperationType op, uint32_t len) {
+    EXPECT_TRUE(op == OperationType::ADD || op == OperationType::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));
+
+    // The activation scalar, value = 0.
+    operands[0] = {
+            .type = OperandType::INT32,
+            .dimensions = {},
+            .numberOfConsumers = len,
+            .scale = 0.0f,
+            .zeroPoint = 0,
+            .lifetime = OperandLifeTime::CONSTANT_COPY,
+            .location = {.poolIndex = 0, .offset = 0, .length = sizeof(int32_t)},
+    };
+    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) {
+        bufferValue = 1.0f;
+        scale1 = 0.0f;
+        scale2 = 0.0f;
+    } else if (op == OperationType::ADD) {
+        bufferValue = 1;
+        scale1 = 1.0f;
+        scale2 = 1.0f;
+    } else {
+        // To satisfy the constraint on quant8 MUL: input0.scale * input1.scale < output.scale,
+        // set input1 to have scale = 0.5f and bufferValue = 2, i.e. 1.0f in floating point.
+        bufferValue = 2;
+        scale1 = 1.0f;
+        scale2 = 0.5f;
     }
-    handle->setTo(cacheNativeHandle, /*shouldOwn=*/true);
+
+    for (uint32_t i = 0; i < len; i++) {
+        const uint32_t firstInputIndex = i * 2 + 1;
+        const uint32_t secondInputIndex = firstInputIndex + 1;
+        const uint32_t outputIndex = secondInputIndex + 1;
+
+        // The first operation input.
+        operands[firstInputIndex] = {
+                .type = operandType,
+                .dimensions = {1},
+                .numberOfConsumers = 1,
+                .scale = scale1,
+                .zeroPoint = 0,
+                .lifetime = (i == 0 ? OperandLifeTime::MODEL_INPUT
+                                    : OperandLifeTime::TEMPORARY_VARIABLE),
+                .location = {},
+        };
+
+        // The second operation input, value = 1.
+        operands[secondInputIndex] = {
+                .type = operandType,
+                .dimensions = {1},
+                .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)},
+        };
+        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
+        // of all but the last member of the chain; and after the loop as a model output, in the
+        // case of the last member of the chain.
+        operations[i] = {
+                .type = op,
+                .inputs = {firstInputIndex, secondInputIndex, /*activation scalar*/ 0},
+                .outputs = {outputIndex},
+        };
+    }
+
+    // The model output.
+    operands.back() = {
+            .type = operandType,
+            .dimensions = {1},
+            .numberOfConsumers = 0,
+            .scale = scale1,
+            .zeroPoint = 0,
+            .lifetime = OperandLifeTime::MODEL_OUTPUT,
+            .location = {},
+    };
+
+    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,
+    };
 }
 
 }  // namespace
 
 // Tag for the compilation caching tests.
-class CompilationCachingTest : public NeuralnetworksHidlTest {
+class CompilationCachingTestBase : public NeuralnetworksHidlTest {
   protected:
+    CompilationCachingTestBase(OperandType type) : kOperandType(type) {}
+
     void SetUp() override {
         NeuralnetworksHidlTest::SetUp();
         ASSERT_NE(device.get(), nullptr);
 
-        // Create cache directory. The cache directory and cache files are always created to test
-        // the behavior of prepareModelFromCache, even when caching is not supported.
+        // Create cache directory. The cache directory and a temporary cache file is always created
+        // to test the behavior of prepareModelFromCache, even when caching is not supported.
         char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX";
         char* cacheDir = mkdtemp(cacheDirTemp);
         ASSERT_NE(cacheDir, nullptr);
         mCacheDir = cacheDir;
+        mCacheDir.push_back('/');
 
-        // Create empty cache files.
-        mCache1 = mCacheDir + "/cache1";
-        mCache2 = mCacheDir + "/cache2";
-        mCache3 = mCacheDir + "/cache3";
-        // A dummy handle, use AccessMode::WRITE_ONLY for createCacheHandle to create files.
-        hidl_handle handle;
-        createCacheHandle({mCache1, mCache2, mCache3}, AccessMode::WRITE_ONLY, &handle);
-
-        // Check if caching is supported.
-        bool isCachingSupported;
-        Return<void> ret = device->isCachingSupported(
-                [&isCachingSupported](ErrorStatus status, bool supported) {
+        Return<void> ret = device->getNumberOfCacheFilesNeeded(
+                [this](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) {
                     EXPECT_EQ(ErrorStatus::NONE, status);
-                    isCachingSupported = supported;
+                    mNumModelCache = numModelCache;
+                    mNumDataCache = numDataCache;
                 });
         EXPECT_TRUE(ret.isOk());
-        if (isCachingSupported) {
-            mIsCachingSupported = true;
-        } else {
+        mIsCachingSupported = mNumModelCache > 0 || mNumDataCache > 0;
+
+        // Create empty cache files.
+        mTmpCache = mCacheDir + "tmp";
+        for (uint32_t i = 0; i < mNumModelCache; i++) {
+            mModelCache.push_back({mCacheDir + "model" + std::to_string(i)});
+        }
+        for (uint32_t i = 0; i < mNumDataCache; i++) {
+            mDataCache.push_back({mCacheDir + "data" + std::to_string(i)});
+        }
+        // Dummy handles, use AccessMode::WRITE_ONLY for createCacheHandles to create files.
+        hidl_vec<hidl_handle> modelHandle, dataHandle, tmpHandle;
+        createCacheHandles(mModelCache, AccessMode::WRITE_ONLY, &modelHandle);
+        createCacheHandles(mDataCache, AccessMode::WRITE_ONLY, &dataHandle);
+        createCacheHandles({{mTmpCache}}, AccessMode::WRITE_ONLY, &tmpHandle);
+
+        if (!mIsCachingSupported) {
             LOG(INFO) << "NN VTS: Early termination of test because vendor service does not "
                          "support compilation caching.";
             std::cout << "[          ]   Early termination of test because vendor service does not "
                          "support compilation caching."
                       << std::endl;
-            mIsCachingSupported = false;
         }
     }
 
     void TearDown() override {
-        // The tmp directory is only removed when the driver reports caching not supported,
-        // otherwise it is kept for debugging purpose.
-        if (!mIsCachingSupported) {
-            remove(mCache1.c_str());
-            remove(mCache2.c_str());
-            remove(mCache3.c_str());
-            rmdir(mCacheDir.c_str());
+        // If the test passes, remove the tmp directory.  Otherwise, keep it for debugging purposes.
+        if (!::testing::Test::HasFailure()) {
+            // Recursively remove the cache directory specified by mCacheDir.
+            auto callback = [](const char* entry, const struct stat*, int, struct FTW*) {
+                return remove(entry);
+            };
+            nftw(mCacheDir.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
         }
         NeuralnetworksHidlTest::TearDown();
     }
 
-    void saveModelToCache(sp<IPreparedModel> preparedModel, const hidl_handle& cache1,
-                          const hidl_handle& cache2, ErrorStatus* status) {
-        // Save IPreparedModel to cache.
+    // Model and examples creators. According to kOperandType, the following methods will return
+    // either float32 model/examples or the quant8 variant.
+    Model createTestModel() {
+        if (kOperandType == OperandType::TENSOR_FLOAT32) {
+            return float32_model::createTestModel();
+        } else {
+            return quant8_model::createTestModel();
+        }
+    }
+
+    std::vector<MixedTypedExample> get_examples() {
+        if (kOperandType == OperandType::TENSOR_FLOAT32) {
+            return float32_model::get_examples();
+        } 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);
+        }
+    }
+
+    // See if the service can handle the model.
+    bool isModelFullySupported(const V1_2::Model& model) {
+        bool fullySupportsModel = false;
+        Return<void> supportedCall = device->getSupportedOperations_1_2(
+                model,
+                [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec<bool>& supported) {
+                    ASSERT_EQ(ErrorStatus::NONE, status);
+                    ASSERT_EQ(supported.size(), model.operations.size());
+                    fullySupportsModel = std::all_of(supported.begin(), supported.end(),
+                                                     [](bool valid) { return valid; });
+                });
+        EXPECT_TRUE(supportedCall.isOk());
+        return fullySupportsModel;
+    }
+
+    void saveModelToCache(const V1_2::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> saveToCacheStatus =
-                preparedModel->saveToCache(cache1, cache2, cacheToken);
-        ASSERT_TRUE(saveToCacheStatus.isOk());
-        *status = static_cast<ErrorStatus>(saveToCacheStatus);
+        Return<ErrorStatus> prepareLaunchStatus =
+                device->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER, modelCache,
+                                         dataCache, cacheToken, preparedModelCallback);
+        ASSERT_TRUE(prepareLaunchStatus.isOk());
+        ASSERT_EQ(static_cast<ErrorStatus>(prepareLaunchStatus), ErrorStatus::NONE);
+
+        // Retrieve prepared model.
+        preparedModelCallback->wait();
+        ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE);
+        if (preparedModel != nullptr) {
+            *preparedModel =
+                    V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
+                            .withDefault(nullptr);
+        }
     }
 
     bool checkEarlyTermination(ErrorStatus status) {
@@ -157,14 +401,27 @@
         return false;
     }
 
-    void prepareModelFromCache(const hidl_handle& cache1, const hidl_handle& cache2,
+    bool checkEarlyTermination(const V1_2::Model& model) {
+        if (!isModelFullySupported(model)) {
+            LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                         "prepare model that it does not support.";
+            std::cout << "[          ]   Early termination of test because vendor service cannot "
+                         "prepare model that it does not support."
+                      << std::endl;
+            return true;
+        }
+        return false;
+    }
+
+    void prepareModelFromCache(const hidl_vec<hidl_handle>& modelCache,
+                               const hidl_vec<hidl_handle>& dataCache,
                                sp<IPreparedModel>* preparedModel, ErrorStatus* status) {
         // Launch prepare model from cache.
         sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
         ASSERT_NE(nullptr, preparedModelCallback.get());
         hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
-        Return<ErrorStatus> prepareLaunchStatus =
-                device->prepareModelFromCache(cache1, cache2, cacheToken, preparedModelCallback);
+        Return<ErrorStatus> prepareLaunchStatus = device->prepareModelFromCache(
+                modelCache, dataCache, cacheToken, preparedModelCallback);
         ASSERT_TRUE(prepareLaunchStatus.isOk());
         if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) {
             *preparedModel = nullptr;
@@ -179,345 +436,844 @@
                                  .withDefault(nullptr);
     }
 
+    // Absolute path to the temporary cache directory.
     std::string mCacheDir;
-    std::string mCache1;
-    std::string mCache2;
-    std::string mCache3;
+
+    // Groups of file paths for model and data cache in the tmp cache directory, initialized with
+    // outer_size = mNum{Model|Data}Cache, inner_size = 1. The outer vector corresponds to handles
+    // and the inner vector is for fds held by each handle.
+    std::vector<std::vector<std::string>> mModelCache;
+    std::vector<std::vector<std::string>> mDataCache;
+
+    // A separate temporary file path in the tmp cache directory.
+    std::string mTmpCache;
+
     uint8_t mToken[static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)] = {};
-    bool mIsCachingSupported;
+    uint32_t mNumModelCache;
+    uint32_t mNumDataCache;
+    uint32_t mIsCachingSupported;
+
+    // The primary data type of the testModel.
+    const OperandType kOperandType;
 };
 
-TEST_F(CompilationCachingTest, CacheSavingAndRetrieval) {
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // Save the compilation to cache.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        if (!mIsCachingSupported) {
-            EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        } else {
-            if (checkEarlyTermination(status)) return;
-            ASSERT_EQ(status, ErrorStatus::NONE);
-        }
-    }
-
-    // Retrieve preparedModel from cache.
-    {
-        preparedModel = nullptr;
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
-        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
-        if (!mIsCachingSupported) {
-            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-            ASSERT_EQ(preparedModel, nullptr);
-            return;
-        } else {
-            ASSERT_EQ(status, ErrorStatus::NONE);
-            ASSERT_NE(preparedModel, nullptr);
-        }
-    }
-
-    // Execute and verify results.
-    generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
-                                           testModel.relaxComputationFloat32toFloat16,
-                                           /*testDynamicOutputShape=*/false);
-}
-
-TEST_F(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // Save the compilation to cache.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        if (!mIsCachingSupported) {
-            EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        } else {
-            if (checkEarlyTermination(status)) return;
-            ASSERT_EQ(status, ErrorStatus::NONE);
-        }
-    }
-
-    // Retrieve preparedModel from cache.
-    {
-        preparedModel = nullptr;
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
-        uint8_t dummyByte = 0;
-        // Advance offset by one byte.
-        ASSERT_GE(read(cache1.getNativeHandle()->data[0], &dummyByte, 1), 0);
-        ASSERT_GE(read(cache2.getNativeHandle()->data[0], &dummyByte, 1), 0);
-        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
-        if (!mIsCachingSupported) {
-            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-            ASSERT_EQ(preparedModel, nullptr);
-            return;
-        } else {
-            ASSERT_EQ(status, ErrorStatus::NONE);
-            ASSERT_NE(preparedModel, nullptr);
-        }
-    }
-
-    // Execute and verify results.
-    generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
-                                           testModel.relaxComputationFloat32toFloat16,
-                                           /*testDynamicOutputShape=*/false);
-}
-
-TEST_F(CompilationCachingTest, SaveToCacheInvalidNumFd) {
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // cache1 with invalid NumFd.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1, mCache3}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        if (status != ErrorStatus::GENERAL_FAILURE) {
-            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
-        }
-    }
-
-    // cache2 with invalid NumFd.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2, mCache3}, AccessMode::WRITE_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        if (status != ErrorStatus::GENERAL_FAILURE) {
-            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
-        }
-    }
-}
-
-TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) {
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // Save the compilation to cache.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        if (status != ErrorStatus::GENERAL_FAILURE) {
-            ASSERT_EQ(status, ErrorStatus::NONE);
-        }
-    }
-
-    // cache1 with invalid NumFd.
-    {
-        preparedModel = nullptr;
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1, mCache3}, AccessMode::READ_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
-        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
-        if (status != ErrorStatus::GENERAL_FAILURE) {
-            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
-            ASSERT_EQ(preparedModel, nullptr);
-        }
-    }
-
-    // cache2 with invalid NumFd.
-    {
-        preparedModel = nullptr;
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
-        createCacheHandle({mCache2, mCache3}, AccessMode::READ_ONLY, &cache2);
-        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
-        if (status != ErrorStatus::GENERAL_FAILURE) {
-            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
-            ASSERT_EQ(preparedModel, nullptr);
-        }
-    }
-}
-
-TEST_F(CompilationCachingTest, SaveToCacheInvalidAccessMode) {
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // cache1 with invalid access mode.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-    }
-
-    // cache2 with invalid access mode.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-    }
-}
-
-TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) {
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // Save the compilation to cache.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        if (status != ErrorStatus::GENERAL_FAILURE) {
-            ASSERT_EQ(status, ErrorStatus::NONE);
-        }
-    }
-
-    // cache1 with invalid access mode.
-    {
-        preparedModel = nullptr;
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
-        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        ASSERT_EQ(preparedModel, nullptr);
-    }
-
-    // cache2 with invalid access mode.
-    {
-        preparedModel = nullptr;
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        ASSERT_EQ(preparedModel, nullptr);
-    }
-}
-
-TEST_F(CompilationCachingTest, SaveToCacheInvalidOffset) {
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // cache1 with invalid file descriptor offset.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        uint8_t dummyByte = 0;
-        // Advance offset by one byte.
-        ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-    }
-
-    // cache2 with invalid file descriptor offset.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        uint8_t dummyByte = 0;
-        // Advance offset by one byte.
-        ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-    }
-}
-
-TEST_F(CompilationCachingTest, SaveToCacheInvalidFileSize) {
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // cache1 with invalid file size.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        uint8_t dummyByte = 0;
-        // Write one byte and seek back to the beginning.
-        ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1);
-        ASSERT_EQ(lseek(cache1.getNativeHandle()->data[0], 0, SEEK_SET), 0);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-    }
-
-    // cache2 with invalid file size.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        uint8_t dummyByte = 0;
-        // Write one byte and seek back to the beginning.
-        ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1);
-        ASSERT_EQ(lseek(cache2.getNativeHandle()->data[0], 0, SEEK_SET), 0);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-    }
-}
-
-class CompilationCachingSecurityTest : public CompilationCachingTest,
-                                       public ::testing::WithParamInterface<uint32_t> {
+// A parameterized fixture of CompilationCachingTestBase. Every test will run twice, with the first
+// pass running with float32 models and the second pass running with quant8 models.
+class CompilationCachingTest : public CompilationCachingTestBase,
+                               public ::testing::WithParamInterface<OperandType> {
   protected:
+    CompilationCachingTest() : CompilationCachingTestBase(GetParam()) {}
+};
+
+TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) {
+    // Create test HIDL model and compile.
+    const Model testModel = createTestModel();
+    if (checkEarlyTermination(testModel)) return;
+    sp<IPreparedModel> preparedModel = nullptr;
+
+    // Save the compilation to cache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(testModel, modelCache, dataCache);
+    }
+
+    // Retrieve preparedModel from cache.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (!mIsCachingSupported) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+            ASSERT_EQ(preparedModel, nullptr);
+            return;
+        } else if (checkEarlyTermination(status)) {
+            ASSERT_EQ(preparedModel, nullptr);
+            return;
+        } else {
+            ASSERT_EQ(status, ErrorStatus::NONE);
+            ASSERT_NE(preparedModel, nullptr);
+        }
+    }
+
+    // Execute and verify results.
+    generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
+                                           testModel.relaxComputationFloat32toFloat16,
+                                           /*testDynamicOutputShape=*/false);
+}
+
+TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
+    // Create test HIDL model and compile.
+    const Model testModel = createTestModel();
+    if (checkEarlyTermination(testModel)) return;
+    sp<IPreparedModel> preparedModel = nullptr;
+
+    // Save the compilation to cache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        uint8_t dummyBytes[] = {0, 0};
+        // Write a dummy integer to the cache.
+        // The driver should be able to handle non-empty cache and non-zero fd offset.
+        for (uint32_t i = 0; i < modelCache.size(); i++) {
+            ASSERT_EQ(write(modelCache[i].getNativeHandle()->data[0], &dummyBytes,
+                            sizeof(dummyBytes)),
+                      sizeof(dummyBytes));
+        }
+        for (uint32_t i = 0; i < dataCache.size(); i++) {
+            ASSERT_EQ(
+                    write(dataCache[i].getNativeHandle()->data[0], &dummyBytes, sizeof(dummyBytes)),
+                    sizeof(dummyBytes));
+        }
+        saveModelToCache(testModel, modelCache, dataCache);
+    }
+
+    // Retrieve preparedModel from cache.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        uint8_t dummyByte = 0;
+        // Advance the offset of each handle by one byte.
+        // The driver should be able to handle non-zero fd offset.
+        for (uint32_t i = 0; i < modelCache.size(); i++) {
+            ASSERT_GE(read(modelCache[i].getNativeHandle()->data[0], &dummyByte, 1), 0);
+        }
+        for (uint32_t i = 0; i < dataCache.size(); i++) {
+            ASSERT_GE(read(dataCache[i].getNativeHandle()->data[0], &dummyByte, 1), 0);
+        }
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (!mIsCachingSupported) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+            ASSERT_EQ(preparedModel, nullptr);
+            return;
+        } else if (checkEarlyTermination(status)) {
+            ASSERT_EQ(preparedModel, nullptr);
+            return;
+        } else {
+            ASSERT_EQ(status, ErrorStatus::NONE);
+            ASSERT_NE(preparedModel, nullptr);
+        }
+    }
+
+    // Execute and verify results.
+    generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
+                                           testModel.relaxComputationFloat32toFloat16,
+                                           /*testDynamicOutputShape=*/false);
+}
+
+TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) {
+    // Create test HIDL model and compile.
+    const Model testModel = createTestModel();
+    if (checkEarlyTermination(testModel)) return;
+
+    // Test with number of model cache files greater than mNumModelCache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an additional cache file for model cache.
+        mModelCache.push_back({mTmpCache});
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache.pop_back();
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
+                                               get_examples(),
+                                               testModel.relaxComputationFloat32toFloat16,
+                                               /*testDynamicOutputShape=*/false);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of model cache files smaller than mNumModelCache.
+    if (mModelCache.size() > 0) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pop out the last cache file.
+        auto tmp = mModelCache.back();
+        mModelCache.pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache.push_back(tmp);
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
+                                               get_examples(),
+                                               testModel.relaxComputationFloat32toFloat16,
+                                               /*testDynamicOutputShape=*/false);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of data cache files greater than mNumDataCache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an additional cache file for data cache.
+        mDataCache.push_back({mTmpCache});
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache.pop_back();
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
+                                               get_examples(),
+                                               testModel.relaxComputationFloat32toFloat16,
+                                               /*testDynamicOutputShape=*/false);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of data cache files smaller than mNumDataCache.
+    if (mDataCache.size() > 0) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pop out the last cache file.
+        auto tmp = mDataCache.back();
+        mDataCache.pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache.push_back(tmp);
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
+                                               get_examples(),
+                                               testModel.relaxComputationFloat32toFloat16,
+                                               /*testDynamicOutputShape=*/false);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumCache) {
+    // Create test HIDL model and compile.
+    const Model testModel = createTestModel();
+    if (checkEarlyTermination(testModel)) 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);
+    }
+
+    // Test with number of model cache files greater than mNumModelCache.
+    {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        mModelCache.push_back({mTmpCache});
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache.pop_back();
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of model cache files smaller than mNumModelCache.
+    if (mModelCache.size() > 0) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        auto tmp = mModelCache.back();
+        mModelCache.pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache.push_back(tmp);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of data cache files greater than mNumDataCache.
+    {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        mDataCache.push_back({mTmpCache});
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache.pop_back();
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Test with number of data cache files smaller than mNumDataCache.
+    if (mDataCache.size() > 0) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        auto tmp = mDataCache.back();
+        mDataCache.pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache.push_back(tmp);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) {
+    // Create test HIDL model and compile.
+    const Model testModel = createTestModel();
+    if (checkEarlyTermination(testModel)) return;
+
+    // Go through each handle in model cache, test with NumFd greater than 1.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an invalid number of fds for handle i.
+        mModelCache[i].push_back(mTmpCache);
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache[i].pop_back();
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
+                                               get_examples(),
+                                               testModel.relaxComputationFloat32toFloat16,
+                                               /*testDynamicOutputShape=*/false);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in model cache, test with NumFd equal to 0.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an invalid number of fds for handle i.
+        auto tmp = mModelCache[i].back();
+        mModelCache[i].pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache[i].push_back(tmp);
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
+                                               get_examples(),
+                                               testModel.relaxComputationFloat32toFloat16,
+                                               /*testDynamicOutputShape=*/false);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with NumFd greater than 1.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an invalid number of fds for handle i.
+        mDataCache[i].push_back(mTmpCache);
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache[i].pop_back();
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
+                                               get_examples(),
+                                               testModel.relaxComputationFloat32toFloat16,
+                                               /*testDynamicOutputShape=*/false);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with NumFd equal to 0.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        // Pass an invalid number of fds for handle i.
+        auto tmp = mDataCache[i].back();
+        mDataCache[i].pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache[i].push_back(tmp);
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
+                                               get_examples(),
+                                               testModel.relaxComputationFloat32toFloat16,
+                                               /*testDynamicOutputShape=*/false);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) {
+    // Create test HIDL model and compile.
+    const Model testModel = createTestModel();
+    if (checkEarlyTermination(testModel)) 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);
+    }
+
+    // Go through each handle in model cache, test with NumFd greater than 1.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        mModelCache[i].push_back(mTmpCache);
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache[i].pop_back();
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in model cache, test with NumFd equal to 0.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        auto tmp = mModelCache[i].back();
+        mModelCache[i].pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mModelCache[i].push_back(tmp);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with NumFd greater than 1.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        mDataCache[i].push_back(mTmpCache);
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache[i].pop_back();
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with NumFd equal to 0.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        auto tmp = mDataCache[i].back();
+        mDataCache[i].pop_back();
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        mDataCache[i].push_back(tmp);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) {
+    // Create test HIDL model and compile.
+    const Model testModel = createTestModel();
+    if (checkEarlyTermination(testModel)) return;
+    std::vector<AccessMode> modelCacheMode(mNumModelCache, AccessMode::READ_WRITE);
+    std::vector<AccessMode> dataCacheMode(mNumDataCache, AccessMode::READ_WRITE);
+
+    // Go through each handle in model cache, test with invalid access mode.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        modelCacheMode[i] = AccessMode::READ_ONLY;
+        createCacheHandles(mModelCache, modelCacheMode, &modelCache);
+        createCacheHandles(mDataCache, dataCacheMode, &dataCache);
+        modelCacheMode[i] = AccessMode::READ_WRITE;
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
+                                               get_examples(),
+                                               testModel.relaxComputationFloat32toFloat16,
+                                               /*testDynamicOutputShape=*/false);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with invalid access mode.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        dataCacheMode[i] = AccessMode::READ_ONLY;
+        createCacheHandles(mModelCache, modelCacheMode, &modelCache);
+        createCacheHandles(mDataCache, dataCacheMode, &dataCache);
+        dataCacheMode[i] = AccessMode::READ_WRITE;
+        sp<IPreparedModel> preparedModel = nullptr;
+        saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+        ASSERT_NE(preparedModel, nullptr);
+        // Execute and verify results.
+        generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
+                                               get_examples(),
+                                               testModel.relaxComputationFloat32toFloat16,
+                                               /*testDynamicOutputShape=*/false);
+        // Check if prepareModelFromCache fails.
+        preparedModel = nullptr;
+        ErrorStatus status;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) {
+    // Create test HIDL model and compile.
+    const Model testModel = createTestModel();
+    if (checkEarlyTermination(testModel)) return;
+    std::vector<AccessMode> modelCacheMode(mNumModelCache, AccessMode::READ_WRITE);
+    std::vector<AccessMode> dataCacheMode(mNumDataCache, AccessMode::READ_WRITE);
+
+    // Save the compilation to cache.
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(testModel, modelCache, dataCache);
+    }
+
+    // Go through each handle in model cache, test with invalid access mode.
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        modelCacheMode[i] = AccessMode::WRITE_ONLY;
+        createCacheHandles(mModelCache, modelCacheMode, &modelCache);
+        createCacheHandles(mDataCache, dataCacheMode, &dataCache);
+        modelCacheMode[i] = AccessMode::READ_WRITE;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // Go through each handle in data cache, test with invalid access mode.
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        dataCacheMode[i] = AccessMode::WRITE_ONLY;
+        createCacheHandles(mModelCache, modelCacheMode, &modelCache);
+        createCacheHandles(mDataCache, dataCacheMode, &dataCache);
+        dataCacheMode[i] = AccessMode::READ_WRITE;
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+// Copy file contents between file groups.
+// The outer vector corresponds to handles and the inner vector is for fds held by each handle.
+// The outer vector sizes must match and the inner vectors must have size = 1.
+static void copyCacheFiles(const std::vector<std::vector<std::string>>& from,
+                           const std::vector<std::vector<std::string>>& to) {
+    constexpr size_t kBufferSize = 1000000;
+    uint8_t buffer[kBufferSize];
+
+    ASSERT_EQ(from.size(), to.size());
+    for (uint32_t i = 0; i < from.size(); i++) {
+        ASSERT_EQ(from[i].size(), 1u);
+        ASSERT_EQ(to[i].size(), 1u);
+        int fromFd = open(from[i][0].c_str(), O_RDONLY);
+        int toFd = open(to[i][0].c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+        ASSERT_GE(fromFd, 0);
+        ASSERT_GE(toFd, 0);
+
+        ssize_t readBytes;
+        while ((readBytes = read(fromFd, &buffer, kBufferSize)) > 0) {
+            ASSERT_EQ(write(toFd, &buffer, readBytes), readBytes);
+        }
+        ASSERT_GE(readBytes, 0);
+
+        close(fromFd);
+        close(toFd);
+    }
+}
+
+// Number of operations in the large test model.
+constexpr uint32_t kLargeModelSize = 100;
+constexpr uint32_t kNumIterationsTOCTOU = 100;
+
+TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) {
+    if (!mIsCachingSupported) return;
+
+    // Create test models and check if fully supported by the service.
+    const Model testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
+    if (checkEarlyTermination(testModelMul)) return;
+    const Model testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
+    if (checkEarlyTermination(testModelAdd)) return;
+
+    // Save the testModelMul compilation to cache.
+    auto modelCacheMul = mModelCache;
+    for (auto& cache : modelCacheMul) {
+        cache[0].append("_mul");
+    }
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(testModelMul, modelCache, dataCache);
+    }
+
+    // Use a different token for testModelAdd.
+    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.
+        {
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+
+            // Spawn a thread to copy the cache content concurrently while saving to cache.
+            std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
+            saveModelToCache(testModelAdd, modelCache, dataCache);
+            thread.join();
+        }
+
+        // Retrieve preparedModel from cache.
+        {
+            sp<IPreparedModel> preparedModel = nullptr;
+            ErrorStatus status;
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+
+            // The preparation may fail or succeed, but must not crash. If the preparation succeeds,
+            // the prepared model must be executed with the correct result and not crash.
+            if (status != ErrorStatus::NONE) {
+                ASSERT_EQ(preparedModel, nullptr);
+            } else {
+                ASSERT_NE(preparedModel, nullptr);
+                generated_tests::EvaluatePreparedModel(
+                        preparedModel, [](int) { return false; },
+                        getLargeModelExamples(kLargeModelSize),
+                        testModelAdd.relaxComputationFloat32toFloat16,
+                        /*testDynamicOutputShape=*/false);
+            }
+        }
+    }
+}
+
+TEST_P(CompilationCachingTest, PrepareFromCache_TOCTOU) {
+    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;
+
+    // Save the testModelMul compilation to cache.
+    auto modelCacheMul = mModelCache;
+    for (auto& cache : modelCacheMul) {
+        cache[0].append("_mul");
+    }
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(testModelMul, modelCache, dataCache);
+    }
+
+    // Use a different token for testModelAdd.
+    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.
+        {
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+            saveModelToCache(testModelAdd, modelCache, dataCache);
+        }
+
+        // Retrieve preparedModel from cache.
+        {
+            sp<IPreparedModel> preparedModel = nullptr;
+            ErrorStatus status;
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+
+            // Spawn a thread to copy the cache content concurrently while preparing from cache.
+            std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
+            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+            thread.join();
+
+            // The preparation may fail or succeed, but must not crash. If the preparation succeeds,
+            // the prepared model must be executed with the correct result and not crash.
+            if (status != ErrorStatus::NONE) {
+                ASSERT_EQ(preparedModel, nullptr);
+            } else {
+                ASSERT_NE(preparedModel, nullptr);
+                generated_tests::EvaluatePreparedModel(
+                        preparedModel, [](int) { return false; },
+                        getLargeModelExamples(kLargeModelSize),
+                        testModelAdd.relaxComputationFloat32toFloat16,
+                        /*testDynamicOutputShape=*/false);
+            }
+        }
+    }
+}
+
+TEST_P(CompilationCachingTest, ReplaceSecuritySensitiveCache) {
+    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;
+
+    // Save the testModelMul compilation to cache.
+    auto modelCacheMul = mModelCache;
+    for (auto& cache : modelCacheMul) {
+        cache[0].append("_mul");
+    }
+    {
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        saveModelToCache(testModelMul, modelCache, dataCache);
+    }
+
+    // Use a different token for testModelAdd.
+    mToken[0]++;
+
+    // Save the testModelAdd 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);
+    }
+
+    // Replace the model cache of testModelAdd with testModelMul.
+    copyCacheFiles(modelCacheMul, mModelCache);
+
+    // Retrieve the preparedModel from cache, expect failure.
+    {
+        sp<IPreparedModel> preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_vec<hidl_handle> modelCache, dataCache;
+        createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+        createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+static const auto kOperandTypeChoices =
+        ::testing::Values(OperandType::TENSOR_FLOAT32, OperandType::TENSOR_QUANT8_ASYMM);
+
+INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest, kOperandTypeChoices);
+
+class CompilationCachingSecurityTest
+    : public CompilationCachingTestBase,
+      public ::testing::WithParamInterface<std::tuple<OperandType, uint32_t>> {
+  protected:
+    CompilationCachingSecurityTest() : CompilationCachingTestBase(std::get<0>(GetParam())) {}
+
     void SetUp() {
-        CompilationCachingTest::SetUp();
+        CompilationCachingTestBase::SetUp();
         generator.seed(kSeed);
     }
 
@@ -528,138 +1284,130 @@
         return dis(generator);
     }
 
-    const uint32_t kSeed = GetParam();
-    std::mt19937 generator;
-};
-
-TEST_P(CompilationCachingSecurityTest, CorruptedSecuritySensitiveCache) {
-    if (!mIsCachingSupported) return;
-
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // Save the compilation to cache.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        if (checkEarlyTermination(status)) return;
-        ASSERT_EQ(status, ErrorStatus::NONE);
-    }
-
     // Randomly flip one single bit of the cache entry.
-    FILE* pFile = fopen(mCache1.c_str(), "r+");
-    ASSERT_EQ(fseek(pFile, 0, SEEK_END), 0);
-    long int fileSize = ftell(pFile);
-    ASSERT_GT(fileSize, 0);
-    ASSERT_EQ(fseek(pFile, getRandomInt(0l, fileSize - 1), SEEK_SET), 0);
-    int readByte = fgetc(pFile);
-    ASSERT_NE(readByte, EOF);
-    ASSERT_EQ(fseek(pFile, -1, SEEK_CUR), 0);
-    ASSERT_NE(fputc(static_cast<uint8_t>(readByte) ^ (1U << getRandomInt(0, 7)), pFile), EOF);
-    fclose(pFile);
-
-    // Retrieve preparedModel from cache, expect failure.
-    {
-        preparedModel = nullptr;
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
-        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        ASSERT_EQ(preparedModel, nullptr);
-    }
-}
-
-TEST_P(CompilationCachingSecurityTest, WrongLengthSecuritySensitiveCache) {
-    if (!mIsCachingSupported) return;
-
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // Save the compilation to cache.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        if (checkEarlyTermination(status)) return;
-        ASSERT_EQ(status, ErrorStatus::NONE);
+    void flipOneBitOfCache(const std::string& filename, bool* skip) {
+        FILE* pFile = fopen(filename.c_str(), "r+");
+        ASSERT_EQ(fseek(pFile, 0, SEEK_END), 0);
+        long int fileSize = ftell(pFile);
+        if (fileSize == 0) {
+            fclose(pFile);
+            *skip = true;
+            return;
+        }
+        ASSERT_EQ(fseek(pFile, getRandomInt(0l, fileSize - 1), SEEK_SET), 0);
+        int readByte = fgetc(pFile);
+        ASSERT_NE(readByte, EOF);
+        ASSERT_EQ(fseek(pFile, -1, SEEK_CUR), 0);
+        ASSERT_NE(fputc(static_cast<uint8_t>(readByte) ^ (1U << getRandomInt(0, 7)), pFile), EOF);
+        fclose(pFile);
+        *skip = false;
     }
 
     // Randomly append bytes to the cache entry.
-    FILE* pFile = fopen(mCache1.c_str(), "a");
-    uint32_t appendLength = getRandomInt(1, 256);
-    for (uint32_t i = 0; i < appendLength; i++) {
-        ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+    void appendBytesToCache(const std::string& filename, bool* skip) {
+        FILE* pFile = fopen(filename.c_str(), "a");
+        uint32_t appendLength = getRandomInt(1, 256);
+        for (uint32_t i = 0; i < appendLength; i++) {
+            ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+        }
+        fclose(pFile);
+        *skip = false;
     }
-    fclose(pFile);
 
-    // Retrieve preparedModel from cache, expect failure.
-    {
-        preparedModel = nullptr;
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
-        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        ASSERT_EQ(preparedModel, nullptr);
+    enum class ExpectedResult { GENERAL_FAILURE, NOT_CRASH };
+
+    // Test if the driver behaves as expected when given corrupted cache or token.
+    // The modifier will be invoked after save to cache but before prepare from cache.
+    // The modifier accepts one pointer argument "skip" as the returning value, indicating
+    // whether the test should be skipped or not.
+    void testCorruptedCache(ExpectedResult expected, std::function<void(bool*)> modifier) {
+        const Model testModel = createTestModel();
+        if (checkEarlyTermination(testModel)) 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);
+        }
+
+        bool skip = false;
+        modifier(&skip);
+        if (skip) return;
+
+        // Retrieve preparedModel from cache.
+        {
+            sp<IPreparedModel> preparedModel = nullptr;
+            ErrorStatus status;
+            hidl_vec<hidl_handle> modelCache, dataCache;
+            createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
+            createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
+            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+
+            switch (expected) {
+                case ExpectedResult::GENERAL_FAILURE:
+                    ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+                    ASSERT_EQ(preparedModel, nullptr);
+                    break;
+                case ExpectedResult::NOT_CRASH:
+                    ASSERT_EQ(preparedModel == nullptr, status != ErrorStatus::NONE);
+                    break;
+                default:
+                    FAIL();
+            }
+        }
+    }
+
+    const uint32_t kSeed = std::get<1>(GetParam());
+    std::mt19937 generator;
+};
+
+TEST_P(CompilationCachingSecurityTest, CorruptedModelCache) {
+    if (!mIsCachingSupported) return;
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        testCorruptedCache(ExpectedResult::GENERAL_FAILURE,
+                           [this, i](bool* skip) { flipOneBitOfCache(mModelCache[i][0], skip); });
+    }
+}
+
+TEST_P(CompilationCachingSecurityTest, WrongLengthModelCache) {
+    if (!mIsCachingSupported) return;
+    for (uint32_t i = 0; i < mNumModelCache; i++) {
+        testCorruptedCache(ExpectedResult::GENERAL_FAILURE,
+                           [this, i](bool* skip) { appendBytesToCache(mModelCache[i][0], skip); });
+    }
+}
+
+TEST_P(CompilationCachingSecurityTest, CorruptedDataCache) {
+    if (!mIsCachingSupported) return;
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        testCorruptedCache(ExpectedResult::NOT_CRASH,
+                           [this, i](bool* skip) { flipOneBitOfCache(mDataCache[i][0], skip); });
+    }
+}
+
+TEST_P(CompilationCachingSecurityTest, WrongLengthDataCache) {
+    if (!mIsCachingSupported) return;
+    for (uint32_t i = 0; i < mNumDataCache; i++) {
+        testCorruptedCache(ExpectedResult::NOT_CRASH,
+                           [this, i](bool* skip) { appendBytesToCache(mDataCache[i][0], skip); });
     }
 }
 
 TEST_P(CompilationCachingSecurityTest, WrongToken) {
     if (!mIsCachingSupported) return;
-
-    // Create test HIDL model and compile.
-    Model testModel = createTestModel();
-    sp<IPreparedModel> preparedModel = nullptr;
-    generated_tests::PrepareModel(device, testModel, &preparedModel);
-    // Terminate early if the driver cannot prepare the model.
-    if (preparedModel == nullptr) return;
-
-    // Save the compilation to cache.
-    {
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
-        saveModelToCache(preparedModel, cache1, cache2, &status);
-        if (checkEarlyTermination(status)) return;
-        ASSERT_EQ(status, ErrorStatus::NONE);
-    }
-
-    // Randomly flip one single bit in mToken.
-    uint32_t ind = getRandomInt(0u, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN) - 1);
-    mToken[ind] ^= (1U << getRandomInt(0, 7));
-
-    // Retrieve the preparedModel from cache, expect failure.
-    {
-        preparedModel = nullptr;
-        ErrorStatus status;
-        hidl_handle cache1, cache2;
-        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
-        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
-        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        ASSERT_EQ(preparedModel, nullptr);
-    }
+    testCorruptedCache(ExpectedResult::GENERAL_FAILURE, [this](bool* skip) {
+        // Randomly flip one single bit in mToken.
+        uint32_t ind =
+                getRandomInt(0u, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN) - 1);
+        mToken[ind] ^= (1U << getRandomInt(0, 7));
+        *skip = false;
+    });
 }
 
 INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest,
-                        ::testing::Range(0U, 10U));
+                        ::testing::Combine(kOperandTypeChoices, ::testing::Range(0U, 10U)));
 
 }  // namespace functional
 }  // namespace vts
diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
new file mode 100644
index 0000000..43bd400
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "ExecutionBurstController.h"
+#include "ExecutionBurstServer.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_2 {
+namespace vts {
+namespace functional {
+
+using ::android::nn::ExecutionBurstController;
+using ::android::nn::RequestChannelSender;
+using ::android::nn::ResultChannelReceiver;
+using ExecutionBurstCallback = ::android::nn::ExecutionBurstController::ExecutionBurstCallback;
+
+// This constant value represents the length of an FMQ that is large enough to
+// return a result from a burst execution for all of the generated test cases.
+constexpr size_t kExecutionBurstChannelLength = 1024;
+
+// This constant value represents a length of an FMQ that is not large enough
+// to return a result from a burst execution for some of the generated test
+// cases.
+constexpr size_t kExecutionBurstChannelSmallLength = 8;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static bool badTiming(Timing timing) {
+    return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX;
+}
+
+static void createBurst(const sp<IPreparedModel>& preparedModel, const sp<IBurstCallback>& callback,
+                        std::unique_ptr<RequestChannelSender>* sender,
+                        std::unique_ptr<ResultChannelReceiver>* receiver,
+                        sp<IBurstContext>* context,
+                        size_t resultChannelLength = kExecutionBurstChannelLength) {
+    ASSERT_NE(nullptr, preparedModel.get());
+    ASSERT_NE(nullptr, sender);
+    ASSERT_NE(nullptr, receiver);
+    ASSERT_NE(nullptr, context);
+
+    // create FMQ objects
+    auto [fmqRequestChannel, fmqRequestDescriptor] =
+            RequestChannelSender::create(kExecutionBurstChannelLength, /*blocking=*/true);
+    auto [fmqResultChannel, fmqResultDescriptor] =
+            ResultChannelReceiver::create(resultChannelLength, /*blocking=*/true);
+    ASSERT_NE(nullptr, fmqRequestChannel.get());
+    ASSERT_NE(nullptr, fmqResultChannel.get());
+    ASSERT_NE(nullptr, fmqRequestDescriptor);
+    ASSERT_NE(nullptr, fmqResultDescriptor);
+
+    // configure burst
+    ErrorStatus errorStatus;
+    sp<IBurstContext> burstContext;
+    const Return<void> ret = preparedModel->configureExecutionBurst(
+            callback, *fmqRequestDescriptor, *fmqResultDescriptor,
+            [&errorStatus, &burstContext](ErrorStatus status, const sp<IBurstContext>& context) {
+                errorStatus = status;
+                burstContext = context;
+            });
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_EQ(ErrorStatus::NONE, errorStatus);
+    ASSERT_NE(nullptr, burstContext.get());
+
+    // return values
+    *sender = std::move(fmqRequestChannel);
+    *receiver = std::move(fmqResultChannel);
+    *context = burstContext;
+}
+
+static void createBurstWithResultChannelLength(
+        const sp<IPreparedModel>& preparedModel, size_t resultChannelLength,
+        std::shared_ptr<ExecutionBurstController>* controller) {
+    ASSERT_NE(nullptr, preparedModel.get());
+    ASSERT_NE(nullptr, controller);
+
+    // create FMQ objects
+    std::unique_ptr<RequestChannelSender> sender;
+    std::unique_ptr<ResultChannelReceiver> receiver;
+    sp<ExecutionBurstCallback> callback = new ExecutionBurstCallback();
+    sp<IBurstContext> context;
+    ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context,
+                                        resultChannelLength));
+    ASSERT_NE(nullptr, sender.get());
+    ASSERT_NE(nullptr, receiver.get());
+    ASSERT_NE(nullptr, context.get());
+
+    // return values
+    *controller = std::make_shared<ExecutionBurstController>(std::move(sender), std::move(receiver),
+                                                             context, callback);
+}
+
+// Primary validation function. This function will take a valid serialized
+// request, apply a mutation to it to invalidate the serialized request, then
+// pass it to interface calls that use the serialized request. Note that the
+// serialized request here is passed by value, and any mutation to the
+// serialized request does not leave this function.
+static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiver,
+                     const std::string& message, std::vector<FmqRequestDatum> serialized,
+                     const std::function<void(std::vector<FmqRequestDatum>*)>& mutation) {
+    mutation(&serialized);
+
+    // skip if packet is too large to send
+    if (serialized.size() > kExecutionBurstChannelLength) {
+        return;
+    }
+
+    SCOPED_TRACE(message);
+
+    // send invalid packet
+    ASSERT_TRUE(sender->sendPacket(serialized));
+
+    // receive error
+    auto results = receiver->getBlocking();
+    ASSERT_TRUE(results.has_value());
+    const auto [status, outputShapes, timing] = std::move(*results);
+    EXPECT_NE(ErrorStatus::NONE, status);
+    EXPECT_EQ(0u, outputShapes.size());
+    EXPECT_TRUE(badTiming(timing));
+}
+
+// For validation, valid packet entries are mutated to invalid packet entries,
+// or invalid packet entries are inserted into valid packets. This function
+// creates pre-set invalid packet entries for convenience.
+static std::vector<FmqRequestDatum> createBadRequestPacketEntries() {
+    const FmqRequestDatum::PacketInformation packetInformation = {
+            /*.packetSize=*/10, /*.numberOfInputOperands=*/10, /*.numberOfOutputOperands=*/10,
+            /*.numberOfPools=*/10};
+    const FmqRequestDatum::OperandInformation operandInformation = {
+            /*.hasNoValue=*/false, /*.location=*/{}, /*.numberOfDimensions=*/10};
+    const int32_t invalidPoolIdentifier = std::numeric_limits<int32_t>::max();
+    std::vector<FmqRequestDatum> bad(7);
+    bad[0].packetInformation(packetInformation);
+    bad[1].inputOperandInformation(operandInformation);
+    bad[2].inputOperandDimensionValue(0);
+    bad[3].outputOperandInformation(operandInformation);
+    bad[4].outputOperandDimensionValue(0);
+    bad[5].poolIdentifier(invalidPoolIdentifier);
+    bad[6].measureTiming(MeasureTiming::YES);
+    return bad;
+}
+
+// For validation, valid packet entries are mutated to invalid packet entries,
+// or invalid packet entries are inserted into valid packets. This function
+// retrieves pre-set invalid packet entries for convenience. This function
+// caches these data so they can be reused on subsequent validation checks.
+static const std::vector<FmqRequestDatum>& getBadRequestPacketEntries() {
+    static const std::vector<FmqRequestDatum> bad = createBadRequestPacketEntries();
+    return bad;
+}
+
+///////////////////////// REMOVE DATUM ////////////////////////////////////
+
+static void removeDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver,
+                            const std::vector<FmqRequestDatum>& serialized) {
+    for (size_t index = 0; index < serialized.size(); ++index) {
+        const std::string message = "removeDatum: removed datum at index " + std::to_string(index);
+        validate(sender, receiver, message, serialized,
+                 [index](std::vector<FmqRequestDatum>* serialized) {
+                     serialized->erase(serialized->begin() + index);
+                 });
+    }
+}
+
+///////////////////////// ADD DATUM ////////////////////////////////////
+
+static void addDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver,
+                         const std::vector<FmqRequestDatum>& serialized) {
+    const std::vector<FmqRequestDatum>& extra = getBadRequestPacketEntries();
+    for (size_t index = 0; index <= serialized.size(); ++index) {
+        for (size_t type = 0; type < extra.size(); ++type) {
+            const std::string message = "addDatum: added datum type " + std::to_string(type) +
+                                        " at index " + std::to_string(index);
+            validate(sender, receiver, message, serialized,
+                     [index, type, &extra](std::vector<FmqRequestDatum>* serialized) {
+                         serialized->insert(serialized->begin() + index, extra[type]);
+                     });
+        }
+    }
+}
+
+///////////////////////// MUTATE DATUM ////////////////////////////////////
+
+static bool interestingCase(const FmqRequestDatum& lhs, const FmqRequestDatum& rhs) {
+    using Discriminator = FmqRequestDatum::hidl_discriminator;
+
+    const bool differentValues = (lhs != rhs);
+    const bool sameDiscriminator = (lhs.getDiscriminator() == rhs.getDiscriminator());
+    const auto discriminator = rhs.getDiscriminator();
+    const bool isDimensionValue = (discriminator == Discriminator::inputOperandDimensionValue ||
+                                   discriminator == Discriminator::outputOperandDimensionValue);
+
+    return differentValues && !(sameDiscriminator && isDimensionValue);
+}
+
+static void mutateDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver,
+                            const std::vector<FmqRequestDatum>& serialized) {
+    const std::vector<FmqRequestDatum>& change = getBadRequestPacketEntries();
+    for (size_t index = 0; index < serialized.size(); ++index) {
+        for (size_t type = 0; type < change.size(); ++type) {
+            if (interestingCase(serialized[index], change[type])) {
+                const std::string message = "mutateDatum: changed datum at index " +
+                                            std::to_string(index) + " to datum type " +
+                                            std::to_string(type);
+                validate(sender, receiver, message, serialized,
+                         [index, type, &change](std::vector<FmqRequestDatum>* serialized) {
+                             (*serialized)[index] = change[type];
+                         });
+            }
+        }
+    }
+}
+
+///////////////////////// BURST VALIATION TESTS ////////////////////////////////////
+
+static void validateBurstSerialization(const sp<IPreparedModel>& preparedModel,
+                                       const std::vector<Request>& requests) {
+    // create burst
+    std::unique_ptr<RequestChannelSender> sender;
+    std::unique_ptr<ResultChannelReceiver> receiver;
+    sp<ExecutionBurstCallback> callback = new ExecutionBurstCallback();
+    sp<IBurstContext> context;
+    ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context));
+    ASSERT_NE(nullptr, sender.get());
+    ASSERT_NE(nullptr, receiver.get());
+    ASSERT_NE(nullptr, context.get());
+
+    // 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);
+
+        // ensure slot std::numeric_limits<int32_t>::max() doesn't exist (for
+        // subsequent slot validation testing)
+        ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) {
+            return slot != std::numeric_limits<int32_t>::max();
+        }));
+
+        // serialize the request
+        const auto serialized = ::android::nn::serialize(request, MeasureTiming::YES, slots);
+
+        // validations
+        removeDatumTest(sender.get(), receiver.get(), serialized);
+        addDatumTest(sender.get(), receiver.get(), serialized);
+        mutateDatumTest(sender.get(), receiver.get(), serialized);
+    }
+}
+
+// This test validates that when the Result message size exceeds length of the
+// result FMQ, the service instance gracefully fails and returns an error.
+static void validateBurstFmqLength(const sp<IPreparedModel>& preparedModel,
+                                   const std::vector<Request>& requests) {
+    // create regular burst
+    std::shared_ptr<ExecutionBurstController> controllerRegular;
+    ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength(
+            preparedModel, kExecutionBurstChannelLength, &controllerRegular));
+    ASSERT_NE(nullptr, controllerRegular.get());
+
+    // create burst with small output channel
+    std::shared_ptr<ExecutionBurstController> controllerSmall;
+    ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength(
+            preparedModel, kExecutionBurstChannelSmallLength, &controllerSmall));
+    ASSERT_NE(nullptr, controllerSmall.get());
+
+    // 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));
+    }
+}
+
+///////////////////////////// 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));
+}
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_2
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index 7f4d385..acf3cb6 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -33,6 +33,7 @@
 
 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 /////////////////////////
 
@@ -54,7 +55,8 @@
     sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
     ASSERT_NE(nullptr, preparedModelCallback.get());
     Return<ErrorStatus> prepareLaunchStatus =
-        device->prepareModel_1_2(model, preference, preparedModelCallback);
+            device->prepareModel_1_2(model, preference, hidl_vec<hidl_handle>(),
+                                     hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
 
@@ -388,8 +390,9 @@
             case OperationType::GROUPED_CONV_2D:
             case OperationType::DEPTHWISE_CONV_2D:
             case OperationType::CONV_2D: {
-                if (operand == 1 && (type == OperandType::TENSOR_QUANT8_ASYMM ||
-                                     type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) {
+                if (operand == operation.inputs[1] &&
+                    (type == OperandType::TENSOR_QUANT8_ASYMM ||
+                     type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) {
                     return true;
                 }
             } break;
@@ -505,14 +508,15 @@
                 }
             }
         }
-        // BIDIRECTIONAL_SEQUENCE_RNN can have either on or two outputs
-        // depending on a mergeOutputs parameter
-        if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) {
-            for (const size_t outOprand : operation.outputs) {
-                if (operand == outOprand) {
-                    return true;
-                }
+        // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have
+        // either one or two outputs depending on their mergeOutputs parameter.
+        if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM ||
+            operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) {
+          for (const size_t outOprand : operation.outputs) {
+            if (operand == outOprand) {
+              return true;
             }
+          }
         }
     }
     return false;
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index d411da4..9703c2d 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -35,7 +35,6 @@
 namespace functional {
 
 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::for_all;
 using test_helper::MixedTyped;
@@ -47,54 +46,6 @@
     return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX;
 }
 
-static void createPreparedModel(const sp<IDevice>& device, const Model& model,
-                                sp<IPreparedModel>* preparedModel) {
-    ASSERT_NE(nullptr, preparedModel);
-
-    // see if service can handle model
-    bool fullySupportsModel = false;
-    Return<void> supportedOpsLaunchStatus = device->getSupportedOperations_1_2(
-        model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
-            ASSERT_EQ(ErrorStatus::NONE, status);
-            ASSERT_NE(0ul, supported.size());
-            fullySupportsModel =
-                std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
-        });
-    ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
-
-    // 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, preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk());
-    ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
-
-    // retrieve prepared model
-    preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
-    *preparedModel = getPreparedModel_1_2(preparedModelCallback);
-
-    // The getSupportedOperations_1_2 call returns a list of operations that are
-    // guaranteed not to fail if prepareModel_1_2 is called, and
-    // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
-    // If a driver has any doubt that it can prepare an operation, it must
-    // return false. So here, if a driver isn't sure if it can support an
-    // operation, but reports that it successfully prepared the model, the test
-    // can continue.
-    if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
-        ASSERT_EQ(nullptr, preparedModel->get());
-        LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
-                     "prepare model that it does not support.";
-        std::cout << "[          ]   Unable to test Request validation because vendor service "
-                     "cannot prepare model that it does not support."
-                  << std::endl;
-        return;
-    }
-    ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
-    ASSERT_NE(nullptr, preparedModel->get());
-}
-
 // Primary validation function. This function will take a valid request, apply a
 // mutation to it to invalidate the request, then pass it to interface calls
 // that use the request. Note that the request here is passed by value, and any
@@ -153,8 +104,8 @@
         SCOPED_TRACE(message + " [burst]");
 
         // create burst
-        std::unique_ptr<::android::nn::ExecutionBurstController> burst =
-                ::android::nn::createExecutionBurstController(preparedModel, /*blocking=*/true);
+        std::shared_ptr<::android::nn::ExecutionBurstController> burst =
+                ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
         ASSERT_NE(nullptr, burst.get());
 
         // create memory keys
@@ -314,14 +265,8 @@
     return requests;
 }
 
-void ValidationTest::validateRequests(const Model& model, const std::vector<Request>& requests) {
-    // create IPreparedModel
-    sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
-
+void ValidationTest::validateRequests(const sp<IPreparedModel>& preparedModel,
+                                      const std::vector<Request>& requests) {
     // validate each request
     for (const Request& request : requests) {
         removeInputTest(preparedModel, request);
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
index 4728c28..4ddefe8 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
@@ -18,6 +18,10 @@
 
 #include "VtsHalNeuralnetworks.h"
 
+#include <android-base/logging.h>
+
+#include "Callbacks.h"
+
 namespace android {
 namespace hardware {
 namespace neuralnetworks {
@@ -25,6 +29,60 @@
 namespace vts {
 namespace functional {
 
+using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+using V1_1::ExecutionPreference;
+
+// internal helper function
+static void createPreparedModel(const sp<IDevice>& device, const Model& model,
+                                sp<IPreparedModel>* preparedModel) {
+    ASSERT_NE(nullptr, preparedModel);
+
+    // see if service can handle model
+    bool fullySupportsModel = false;
+    Return<void> supportedOpsLaunchStatus = device->getSupportedOperations_1_2(
+            model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
+                ASSERT_EQ(ErrorStatus::NONE, status);
+                ASSERT_NE(0ul, supported.size());
+                fullySupportsModel = std::all_of(supported.begin(), supported.end(),
+                                                 [](bool valid) { return valid; });
+            });
+    ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
+
+    // launch prepare model
+    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+    ASSERT_NE(nullptr, preparedModelCallback.get());
+    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2(
+            model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(),
+            hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
+    ASSERT_TRUE(prepareLaunchStatus.isOk());
+    ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+    // retrieve prepared model
+    preparedModelCallback->wait();
+    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    *preparedModel = getPreparedModel_1_2(preparedModelCallback);
+
+    // The getSupportedOperations_1_2 call returns a list of operations that are
+    // guaranteed not to fail if prepareModel_1_2 is called, and
+    // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
+    // If a driver has any doubt that it can prepare an operation, it must
+    // return false. So here, if a driver isn't sure if it can support an
+    // operation, but reports that it successfully prepared the model, the test
+    // can continue.
+    if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
+        ASSERT_EQ(nullptr, preparedModel->get());
+        LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
+                     "prepare model that it does not support.";
+        std::cout << "[          ]   Unable to test Request validation because vendor service "
+                     "cannot prepare model that it does not support."
+                  << std::endl;
+        return;
+    }
+    ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+    ASSERT_NE(nullptr, preparedModel->get());
+}
+
 // A class for test environment setup
 NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
 
@@ -68,6 +126,20 @@
     ::testing::VtsHalHidlTargetTestBase::TearDown();
 }
 
+void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
+    validateModel(model);
+
+    // create IPreparedModel
+    sp<IPreparedModel> preparedModel;
+    ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
+    if (preparedModel == nullptr) {
+        return;
+    }
+
+    validateRequests(preparedModel, requests);
+    validateBurst(preparedModel, requests);
+}
+
 sp<IPreparedModel> getPreparedModel_1_2(
     const sp<V1_2::implementation::PreparedModelCallback>& callback) {
     sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
index 404eec0..8d1acbe 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
@@ -72,8 +72,14 @@
 // Tag for the validation tests
 class ValidationTest : public NeuralnetworksHidlTest {
    protected:
-    void validateModel(const Model& model);
-    void validateRequests(const Model& model, const std::vector<Request>& request);
+     void validateEverything(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 validateBurst(const sp<IPreparedModel>& preparedModel,
+                        const std::vector<Request>& requests);
 };
 
 // Tag for the generated tests
diff --git a/nfc/1.0/Android.bp b/nfc/1.0/Android.bp
index e0625d0..bd64907 100644
--- a/nfc/1.0/Android.bp
+++ b/nfc/1.0/Android.bp
@@ -17,4 +17,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/nfc/1.1/Android.bp b/nfc/1.1/Android.bp
index bbf49b2..1f8789f 100644
--- a/nfc/1.1/Android.bp
+++ b/nfc/1.1/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/nfc/1.2/Android.bp b/nfc/1.2/Android.bp
index cfb8b85..aa68d2f 100644
--- a/nfc/1.2/Android.bp
+++ b/nfc/1.2/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/nfc/1.2/vts/OWNERS b/nfc/1.2/vts/OWNERS
new file mode 100644
index 0000000..21d4df1
--- /dev/null
+++ b/nfc/1.2/vts/OWNERS
@@ -0,0 +1,3 @@
+zachoverflow@google.com
+jackcwyu@google.com
+georgekgchang@google.com
diff --git a/oemlock/1.0/Android.bp b/oemlock/1.0/Android.bp
index 894188b..e784be0 100644
--- a/oemlock/1.0/Android.bp
+++ b/oemlock/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/power/1.0/Android.bp b/power/1.0/Android.bp
index dbc0a36..6ba1d78 100644
--- a/power/1.0/Android.bp
+++ b/power/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/power/1.1/Android.bp b/power/1.1/Android.bp
index de55396..6b133cc 100644
--- a/power/1.1/Android.bp
+++ b/power/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/power/1.2/Android.bp b/power/1.2/Android.bp
index 284e736..296965b 100644
--- a/power/1.2/Android.bp
+++ b/power/1.2/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/power/1.3/Android.bp b/power/1.3/Android.bp
index 320f1e6..00ca750 100644
--- a/power/1.3/Android.bp
+++ b/power/1.3/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/power/stats/1.0/Android.bp b/power/stats/1.0/Android.bp
index 9cf24cf..c592006 100644
--- a/power/stats/1.0/Android.bp
+++ b/power/stats/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/prebuilt_hashes/28.txt b/prebuilt_hashes/28.txt
index cc15322..8a45ca5 100644
--- a/prebuilt_hashes/28.txt
+++ b/prebuilt_hashes/28.txt
@@ -348,6 +348,8 @@
 5e278fcaa3287d397d8eebe1c22aaa28150f5caae1cf9381cd6dc32cb37899c5 android.hardware.nfc@1.1::types
 163e115e833fc1d77cdd4a8cf0c833bb8b8d74fe35c880fe693101d17774926f android.hardware.power@1.2::IPower
 7899b9305587b2d5cd74a3cc87e9090f58bf4ae74256ce3ee36e7ec011822840 android.hardware.power@1.2::types
+5a464e6db53fad223986d655028a18185b73db8e2bfa9663f9042c9623eb0aa0 android.hardware.power@1.3::IPower
+a54a28d39b892d27a3cb06829181c038edcdd9e8eef359543b01e4313ae59aa0 android.hardware.power@1.3::types
 ab132c990a62f0aca35871c092c22fb9c85d478e22124ef6a4d0a2302da76a9f android.hardware.radio@1.2::IRadio
 cda752aeabaabc20486a82ac57a3dd107785c006094a349bc5e224e8aa22a17c android.hardware.radio@1.2::IRadioIndication
 da8c6ae991c6a4b284cc6e445332e064e28ee8a09482ed5afff9d159ec6694b7 android.hardware.radio@1.2::IRadioResponse
diff --git a/radio/1.0/Android.bp b/radio/1.0/Android.bp
index f023471..6765b4d 100644
--- a/radio/1.0/Android.bp
+++ b/radio/1.0/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/1.1/Android.bp b/radio/1.1/Android.bp
index 4375d8c..28388b0 100644
--- a/radio/1.1/Android.bp
+++ b/radio/1.1/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/1.2/Android.bp b/radio/1.2/Android.bp
index b7364a8..28e6b26 100644
--- a/radio/1.2/Android.bp
+++ b/radio/1.2/Android.bp
@@ -20,4 +20,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/1.2/types.hal b/radio/1.2/types.hal
index 2dceeb1..dffebd3 100644
--- a/radio/1.2/types.hal
+++ b/radio/1.2/types.hal
@@ -193,7 +193,8 @@
      * the client (in seconds).
      * Expected range for the input is
      * [IncrementalResultsPeriodicityRange:MIN - IncrementalResultsPeriodicityRange:MAX]
-     * This value must be less than or equal to maxSearchTime.
+     * This value must be less than or equal to maxSearchTime. If incremental results are
+     * not requested, implementations may ignore this value.
      */
     int32_t incrementalResultsPeriodicity;
 
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
index 730d969..63d3187 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
@@ -19,19 +19,25 @@
 
 #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
 
+namespace {
+const RadioAccessSpecifier GERAN_SPECIFIER_P900 = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                                   .geranBands = {GeranBands::BAND_P900},
+                                                   .channels = {1, 2}};
+const RadioAccessSpecifier GERAN_SPECIFIER_850 = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
+                                                  .geranBands = {GeranBands::BAND_850},
+                                                  .channels = {128, 129}};
+}  // namespace
+
 /*
  * Test IRadio.startNetworkScan() for the response returned.
  */
 TEST_F(RadioHidlTest_v1_2, startNetworkScan) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifier specifier = {
-        .radioAccessNetwork = RadioAccessNetworks::GERAN,
-        .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-        .channels = {1,2}};
-
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-        .type = ScanType::ONE_SHOT, .interval = 60, .specifiers = {specifier}};
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850}};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
@@ -89,18 +95,13 @@
 TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidInterval1) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifier specifier = {
-        .radioAccessNetwork = RadioAccessNetworks::GERAN,
-        .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-        .channels = {1,2}};
-
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-        .type = ScanType::ONE_SHOT,
-        .interval = 4,
-        .specifiers = {specifier},
-        .maxSearchTime = 60,
-        .incrementalResults = false,
-        .incrementalResultsPeriodicity = 1};
+            .type = ScanType::ONE_SHOT,
+            .interval = 4,
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
@@ -126,18 +127,13 @@
 TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidInterval2) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifier specifier = {
-        .radioAccessNetwork = RadioAccessNetworks::GERAN,
-        .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-        .channels = {1,2}};
-
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-        .type = ScanType::ONE_SHOT,
-        .interval = 301,
-        .specifiers = {specifier},
-        .maxSearchTime = 60,
-        .incrementalResults = false,
-        .incrementalResultsPeriodicity = 1};
+            .type = ScanType::ONE_SHOT,
+            .interval = 301,
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
@@ -163,18 +159,13 @@
 TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidMaxSearchTime1) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifier specifier = {
-        .radioAccessNetwork = RadioAccessNetworks::GERAN,
-        .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-        .channels = {1,2}};
-
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-        .type = ScanType::ONE_SHOT,
-        .interval = 60,
-        .specifiers = {specifier},
-        .maxSearchTime = 59,
-        .incrementalResults = false,
-        .incrementalResultsPeriodicity = 1};
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850},
+            .maxSearchTime = 59,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
@@ -200,18 +191,13 @@
 TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidMaxSearchTime2) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifier specifier = {
-        .radioAccessNetwork = RadioAccessNetworks::GERAN,
-        .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-        .channels = {1,2}};
-
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-        .type = ScanType::ONE_SHOT,
-        .interval = 60,
-        .specifiers = {specifier},
-        .maxSearchTime = 3601,
-        .incrementalResults = false,
-        .incrementalResultsPeriodicity = 1};
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850},
+            .maxSearchTime = 3601,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
@@ -237,18 +223,13 @@
 TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidPeriodicity1) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifier specifier = {
-        .radioAccessNetwork = RadioAccessNetworks::GERAN,
-        .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-        .channels = {1,2}};
-
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-        .type = ScanType::ONE_SHOT,
-        .interval = 60,
-        .specifiers = {specifier},
-        .maxSearchTime = 600,
-        .incrementalResults = false,
-        .incrementalResultsPeriodicity = 0};
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850},
+            .maxSearchTime = 600,
+            .incrementalResults = true,
+            .incrementalResultsPeriodicity = 0};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
@@ -274,18 +255,13 @@
 TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidPeriodicity2) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifier specifier = {
-        .radioAccessNetwork = RadioAccessNetworks::GERAN,
-        .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-        .channels = {1,2}};
-
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-        .type = ScanType::ONE_SHOT,
-        .interval = 60,
-        .specifiers = {specifier},
-        .maxSearchTime = 600,
-        .incrementalResults = false,
-        .incrementalResultsPeriodicity = 11};
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850},
+            .maxSearchTime = 600,
+            .incrementalResults = true,
+            .incrementalResultsPeriodicity = 11};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
@@ -311,20 +287,15 @@
 TEST_F(RadioHidlTest_v1_2, startNetworkScan_GoodRequest1) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifier specifier = {
-        .radioAccessNetwork = RadioAccessNetworks::GERAN,
-        .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-        .channels = {1,2}};
-
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-        .type = ScanType::ONE_SHOT,
-        .interval = 60,
-        .specifiers = {specifier},
-        // Some vendor may not support max search time of 360s.
-        // This issue is tracked in b/112205669.
-        .maxSearchTime = 300,
-        .incrementalResults = false,
-        .incrementalResultsPeriodicity = 10};
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850},
+            // Some vendor may not support max search time of 360s.
+            // This issue is tracked in b/112205669.
+            .maxSearchTime = 300,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 10};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
@@ -350,21 +321,16 @@
 TEST_F(RadioHidlTest_v1_2, startNetworkScan_GoodRequest2) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifier specifier = {
-        .radioAccessNetwork = RadioAccessNetworks::GERAN,
-        .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-        .channels = {1,2}};
-
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-        .type = ScanType::ONE_SHOT,
-        .interval = 60,
-        .specifiers = {specifier},
-        // Some vendor may not support max search time of 360s.
-        // This issue is tracked in b/112205669.
-        .maxSearchTime = 300,
-        .incrementalResults = false,
-        .incrementalResultsPeriodicity = 10,
-        .mccMncs = {"310410"}};
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850},
+            // Some vendor may not support max search time of 360s.
+            // This issue is tracked in b/112205669.
+            .maxSearchTime = 300,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 10,
+            .mccMncs = {"310410"}};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
@@ -757,6 +723,7 @@
     // Check the mcc [0, 999] and mnc [0, 999].
     string hidl_mcc;
     string hidl_mnc;
+    bool checkMccMnc = true;
     int totalIdentitySizeExpected = 1;
     ::android::hardware::radio::V1_2::CellIdentity cellIdentities =
         radioRsp_v1_2->dataRegResp.cellIdentity;
@@ -765,6 +732,7 @@
     if (cellInfoType == CellInfoType::NONE) {
         // All the fields are 0
         totalIdentitySizeExpected = 0;
+        checkMccMnc = false;
     } else if (cellInfoType == CellInfoType::GSM) {
         EXPECT_EQ(1, cellIdentities.cellIdentityGsm.size());
         ::android::hardware::radio::V1_2::CellIdentityGsm cig = cellIdentities.cellIdentityGsm[0];
@@ -791,6 +759,7 @@
         // CellIndentityCdma has no mcc and mnc.
         EXPECT_EQ(CellInfoType::CDMA, cellInfoType);
         EXPECT_EQ(1, cellIdentities.cellIdentityCdma.size());
+        checkMccMnc = false;
     }
 
     // Check only one CellIdentity is size 1, and others must be 0.
@@ -799,10 +768,13 @@
                   cellIdentities.cellIdentityLte.size() + cellIdentities.cellIdentityWcdma.size() +
                   cellIdentities.cellIdentityTdscdma.size());
 
-    int mcc = stoi(hidl_mcc);
-    int mnc = stoi(hidl_mnc);
-    EXPECT_TRUE(mcc >= 0 && mcc <= 999);
-    EXPECT_TRUE(mnc >= 0 && mnc <= 999);
+    // 32 bit system might return invalid mcc and mnc hidl string "\xff\xff..."
+    if (checkMccMnc && hidl_mcc.size() < 4 && hidl_mnc.size() < 4) {
+        int mcc = stoi(hidl_mcc);
+        int mnc = stoi(hidl_mnc);
+        EXPECT_TRUE(mcc >= 0 && mcc <= 999);
+        EXPECT_TRUE(mnc >= 0 && mnc <= 999);
+    }
 }
 
 /*
diff --git a/radio/1.3/Android.bp b/radio/1.3/Android.bp
index de2a3e5..b6af874 100644
--- a/radio/1.3/Android.bp
+++ b/radio/1.3/Android.bp
@@ -20,4 +20,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/1.3/IRadioResponse.hal b/radio/1.3/IRadioResponse.hal
index c3bbe65..85085e2 100644
--- a/radio/1.3/IRadioResponse.hal
+++ b/radio/1.3/IRadioResponse.hal
@@ -44,6 +44,9 @@
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
+     *   RadioError:INVALID_STATE: this is for the case that the API is called in a single-sim
+     *              mode, or when there is only one modem available, as this API should only
+     *              be called in multi sim status.
      */
     oneway enableModemResponse(RadioResponseInfo info);
 
diff --git a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
index 1bebae7..7fb8995 100644
--- a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
@@ -33,9 +33,9 @@
     EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial);
     ALOGI("getModemStackStatus, rspInfo.error = %s\n",
           toString(radioRsp_v1_3->rspInfo.error).c_str());
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_v1_3->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_3->rspInfo.error,
+                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::INVALID_STATE}));
 
     // checking if getModemStackStatus returns true, as modem was enabled above
     if (RadioError::NONE == radioRsp_v1_3->rspInfo.error) {
@@ -50,9 +50,9 @@
         EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial);
         ALOGI("getModemStackStatus, rspInfo.error = %s\n",
               toString(radioRsp_v1_3->rspInfo.error).c_str());
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_v1_3->rspInfo.error,
-                {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_3->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::MODEM_ERR, RadioError::INVALID_STATE}));
         // verify that enableModem did set isEnabled correctly
         EXPECT_EQ(true, radioRsp_v1_3->isModemEnabled);
     }
diff --git a/radio/1.4/Android.bp b/radio/1.4/Android.bp
index 9f5f2f9..ff2e0d6 100644
--- a/radio/1.4/Android.bp
+++ b/radio/1.4/Android.bp
@@ -22,4 +22,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
index ac78462..2093c25 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
@@ -676,3 +676,122 @@
         }
     }
 }
+
+TEST_F(RadioHidlTest_v1_4, setDataProfile_1_4) {
+    serial = GetRandomSerialNumber();
+
+    // Create a dataProfileInfo
+    android::hardware::radio::V1_4::DataProfileInfo dataProfileInfo;
+    memset(&dataProfileInfo, 0, sizeof(dataProfileInfo));
+    dataProfileInfo.profileId = DataProfileId::DEFAULT;
+    dataProfileInfo.apn = hidl_string("internet");
+    dataProfileInfo.protocol = PdpProtocolType::IPV4V6;
+    dataProfileInfo.roamingProtocol = PdpProtocolType::IPV4V6;
+    dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP;
+    dataProfileInfo.user = hidl_string("username");
+    dataProfileInfo.password = hidl_string("password");
+    dataProfileInfo.type = DataProfileInfoType::THREE_GPP;
+    dataProfileInfo.maxConnsTime = 300;
+    dataProfileInfo.maxConns = 20;
+    dataProfileInfo.waitTime = 0;
+    dataProfileInfo.enabled = true;
+    dataProfileInfo.supportedApnTypesBitmap = 320;
+    dataProfileInfo.bearerBitmap = 161543;
+    dataProfileInfo.mtu = 0;
+    dataProfileInfo.preferred = true;
+    dataProfileInfo.persistent = true;
+
+    // Create a dataProfileInfoList
+    android::hardware::hidl_vec<android::hardware::radio::V1_4::DataProfileInfo>
+            dataProfileInfoList = {dataProfileInfo};
+
+    radio_v1_4->setDataProfile_1_4(serial, dataProfileInfoList);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_4->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_4->rspInfo.serial);
+
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
+    }
+}
+
+TEST_F(RadioHidlTest_v1_4, setInitialAttachApn_1_4) {
+    serial = GetRandomSerialNumber();
+
+    // Create a dataProfileInfo
+    android::hardware::radio::V1_4::DataProfileInfo dataProfileInfo;
+    memset(&dataProfileInfo, 0, sizeof(dataProfileInfo));
+    dataProfileInfo.profileId = DataProfileId::DEFAULT;
+    dataProfileInfo.apn = hidl_string("internet");
+    dataProfileInfo.protocol = PdpProtocolType::IPV4V6;
+    dataProfileInfo.roamingProtocol = PdpProtocolType::IPV4V6;
+    dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP;
+    dataProfileInfo.user = hidl_string("username");
+    dataProfileInfo.password = hidl_string("password");
+    dataProfileInfo.type = DataProfileInfoType::THREE_GPP;
+    dataProfileInfo.maxConnsTime = 300;
+    dataProfileInfo.maxConns = 20;
+    dataProfileInfo.waitTime = 0;
+    dataProfileInfo.enabled = true;
+    dataProfileInfo.supportedApnTypesBitmap = 320;
+    dataProfileInfo.bearerBitmap = 161543;
+    dataProfileInfo.mtu = 0;
+    dataProfileInfo.preferred = true;
+    dataProfileInfo.persistent = false;
+
+    radio_v1_4->setInitialAttachApn_1_4(serial, dataProfileInfo);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_4->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_4->rspInfo.serial);
+
+    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE}));
+    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
+    }
+}
+
+/*
+ * Test IRadio.getDataRegistrationStateResponse_1_4() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_4, getDataRegistrationState_1_4) {
+    int rat;
+    serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_4->getDataRegistrationState(serial);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_4->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_4->rspInfo.serial);
+
+    ALOGI("getDataRegistrationStateResponse_1_4, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+
+    ASSERT_TRUE(CheckAnyOfErrors(
+        radioRsp_v1_4->rspInfo.error,
+        {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::NOT_PROVISIONED}));
+
+    rat = radioRsp_v1_4->dataRegResp.base.rat;
+    /*
+     *  - Expect Valid vopsinfo when device is on LTE
+     *  - Expect empty vopsInfo when device is not on LTE
+     */
+    if (rat == ((int )::android::hardware::radio::V1_4::RadioTechnology::LTE)
+        || (rat == (int )::android::hardware::radio::V1_4::RadioTechnology::LTE_CA)) {
+
+        EXPECT_EQ(::android::hardware::radio::V1_4::DataRegStateResult::VopsInfo::hidl_discriminator
+                  ::lteVopsInfo, radioRsp_v1_4->dataRegResp.vopsInfo.getDiscriminator());
+    } else {
+
+        EXPECT_EQ(::android::hardware::radio::V1_4::DataRegStateResult::VopsInfo::hidl_discriminator
+                  ::noinit, radioRsp_v1_4->dataRegResp.vopsInfo.getDiscriminator());
+    }
+}
diff --git a/radio/config/1.0/Android.bp b/radio/config/1.0/Android.bp
index 7fb0ea1..387f953 100644
--- a/radio/config/1.0/Android.bp
+++ b/radio/config/1.0/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/config/1.1/Android.bp b/radio/config/1.1/Android.bp
index 5c9ad7c..1e9071a 100644
--- a/radio/config/1.1/Android.bp
+++ b/radio/config/1.1/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/config/1.2/Android.bp b/radio/config/1.2/Android.bp
index e69be40..812f166 100644
--- a/radio/config/1.2/Android.bp
+++ b/radio/config/1.2/Android.bp
@@ -19,4 +19,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/radio/deprecated/1.0/Android.bp b/radio/deprecated/1.0/Android.bp
index c9f86f0..cb13b86 100644
--- a/radio/deprecated/1.0/Android.bp
+++ b/radio/deprecated/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/renderscript/1.0/Android.bp b/renderscript/1.0/Android.bp
index 1d7efad..feae9f7 100644
--- a/renderscript/1.0/Android.bp
+++ b/renderscript/1.0/Android.bp
@@ -18,4 +18,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/secure_element/1.0/Android.bp b/secure_element/1.0/Android.bp
index c6fa6a9..32b752b 100644
--- a/secure_element/1.0/Android.bp
+++ b/secure_element/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/secure_element/1.1/Android.bp b/secure_element/1.1/Android.bp
index e16bc3d..3ea2de9 100644
--- a/secure_element/1.1/Android.bp
+++ b/secure_element/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/sensors/1.0/Android.bp b/sensors/1.0/Android.bp
index 3a41f9c..509f72f 100644
--- a/sensors/1.0/Android.bp
+++ b/sensors/1.0/Android.bp
@@ -16,4 +16,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/soundtrigger/2.0/Android.bp b/soundtrigger/2.0/Android.bp
index b805be8..5613abd 100644
--- a/soundtrigger/2.0/Android.bp
+++ b/soundtrigger/2.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/soundtrigger/2.0/ISoundTriggerHwCallback.hal b/soundtrigger/2.0/ISoundTriggerHwCallback.hal
index 90132d9..84b11c8 100644
--- a/soundtrigger/2.0/ISoundTriggerHwCallback.hal
+++ b/soundtrigger/2.0/ISoundTriggerHwCallback.hal
@@ -46,7 +46,6 @@
         int32_t           captureSession;
         /**
          * Delay in ms between end of model detection and start of audio
-        /**
          * available for capture. A negative value is possible
          * (e.g. if key phrase is also available for capture */
         int32_t           captureDelayMs;
diff --git a/soundtrigger/2.1/Android.bp b/soundtrigger/2.1/Android.bp
index ed1ec3d..68e425b 100644
--- a/soundtrigger/2.1/Android.bp
+++ b/soundtrigger/2.1/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/bar/1.0/Android.bp b/tests/bar/1.0/Android.bp
index a1b6b88..0aeccd6 100644
--- a/tests/bar/1.0/Android.bp
+++ b/tests/bar/1.0/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/baz/1.0/Android.bp b/tests/baz/1.0/Android.bp
index 618f4f8..ed18876 100644
--- a/tests/baz/1.0/Android.bp
+++ b/tests/baz/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/expression/1.0/Android.bp b/tests/expression/1.0/Android.bp
index 61ca6ac..4bc3848 100644
--- a/tests/expression/1.0/Android.bp
+++ b/tests/expression/1.0/Android.bp
@@ -12,4 +12,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/extension/light/2.0/Android.bp b/tests/extension/light/2.0/Android.bp
index 916af71..e19a913 100644
--- a/tests/extension/light/2.0/Android.bp
+++ b/tests/extension/light/2.0/Android.bp
@@ -13,4 +13,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/foo/1.0/Android.bp b/tests/foo/1.0/Android.bp
index 1c3b3c5..2f97fca 100644
--- a/tests/foo/1.0/Android.bp
+++ b/tests/foo/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/hash/1.0/Android.bp b/tests/hash/1.0/Android.bp
index 20334cd..1095576 100644
--- a/tests/hash/1.0/Android.bp
+++ b/tests/hash/1.0/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/inheritance/1.0/Android.bp b/tests/inheritance/1.0/Android.bp
index 1d36d07..0042b57 100644
--- a/tests/inheritance/1.0/Android.bp
+++ b/tests/inheritance/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/libhwbinder/1.0/Android.bp b/tests/libhwbinder/1.0/Android.bp
index d561002..13af77c 100644
--- a/tests/libhwbinder/1.0/Android.bp
+++ b/tests/libhwbinder/1.0/Android.bp
@@ -12,4 +12,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/memory/1.0/Android.bp b/tests/memory/1.0/Android.bp
index cbee247..29f6be7 100644
--- a/tests/memory/1.0/Android.bp
+++ b/tests/memory/1.0/Android.bp
@@ -13,4 +13,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/msgq/1.0/Android.bp b/tests/msgq/1.0/Android.bp
index 2d8d565..eea1ce6 100644
--- a/tests/msgq/1.0/Android.bp
+++ b/tests/msgq/1.0/Android.bp
@@ -12,4 +12,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/multithread/1.0/Android.bp b/tests/multithread/1.0/Android.bp
index 0d21b1b..ed3a687 100644
--- a/tests/multithread/1.0/Android.bp
+++ b/tests/multithread/1.0/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/pointer/1.0/.hidl_for_test b/tests/pointer/1.0/.hidl_for_test
deleted file mode 100644
index e69de29..0000000
--- a/tests/pointer/1.0/.hidl_for_test
+++ /dev/null
diff --git a/tests/pointer/1.0/Android.bp b/tests/pointer/1.0/Android.bp
deleted file mode 100644
index 3dc8e8a..0000000
--- a/tests/pointer/1.0/Android.bp
+++ /dev/null
@@ -1,15 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-hidl_interface {
-    name: "android.hardware.tests.pointer@1.0",
-    root: "android.hardware",
-    srcs: [
-        "IGraph.hal",
-        "IPointer.hal",
-    ],
-    interfaces: [
-        "android.hidl.base@1.0",
-    ],
-    gen_java: false,
-}
-
diff --git a/tests/pointer/1.0/IGraph.hal b/tests/pointer/1.0/IGraph.hal
deleted file mode 100644
index 0853745..0000000
--- a/tests/pointer/1.0/IGraph.hal
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.tests.pointer@1.0;
-
-interface IGraph {
-
-  struct Node {
-    int32_t data;
-  };
-  struct Edge {
-    ref<Node> left;
-    ref<Node> right;
-  };
-  struct Graph {
-    vec<Node> nodes;
-    vec<Edge> edges;
-  };
-
-  struct Theta {
-    int32_t data;
-  };
-  struct Alpha {
-    ref<Theta> s_ptr;
-  };
-  struct Beta {
-    ref<Theta> s_ptr;
-  };
-  struct Gamma {
-    ref<Alpha> a_ptr;
-    ref<Beta> b_ptr;
-  };
-
-  passANode(Node n);
-  passAGraph(Graph g);
-  passTwoGraphs(ref<Graph> g1, ref<Graph> g2);
-  giveAGraph() generates (Graph g);
-  passAGamma(Gamma c);
-  passASimpleRef(ref<Alpha> a);
-  passASimpleRefS(ref<Theta> s);
-  giveASimpleRef() generates (ref<Alpha> a);
-
-  getErrors() generates (int32_t errors);
-};
diff --git a/tests/pointer/1.0/IPointer.hal b/tests/pointer/1.0/IPointer.hal
deleted file mode 100644
index 4560a4a..0000000
--- a/tests/pointer/1.0/IPointer.hal
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.tests.pointer@1.0;
-
-interface IPointer {
-  struct S { int32_t data; };
-  struct A { S s; };
-  // type declarations
-  struct Sam { int32_t data; };
-  struct Ada { ref<Sam> s_ptr; };
-  struct Bob { ref<Ada> a_ptr; ref<Sam> s_ptr; };
-  struct Cin { Ada a; ref<Bob> b_ptr; };
-  struct Dom { Cin c; };
-
-  typedef ref<int32_t> Int32Ptr;
-  typedef ref<Sam>     SamPtr;
-
-  struct Ptr {
-    ref<Ada>[5] ptr_array;
-    ref<Ada[5]> array_ptr;
-    Int32Ptr int_ptr;
-    ref<int32_t[5]> int_array_ptr;
-    ref<int32_t>[5] int_ptr_array;
-    ref<string> str_ref;
-    vec<ref<Ada>> a_ptr_vec;
-    ref<vec<Ada>> a_vec_ptr;
-  };
-
-  // test cases
-  foo1(Sam s, SamPtr s_ptr);
-  foo2(Sam s, Ada a);
-  foo3(Sam s, Ada a, Bob b);
-  foo4(ref<Sam> s_ptr);
-  foo5(Ada a, Bob b);
-  foo6(ref<Ada> a_ptr);
-  foo7(ref<Ada> a_ptr, ref<Bob> b_ptr);
-  foo8(Dom d);
-  foo9(ref<string> str_ref);
-  foo10(vec<ref<Sam>> s_ptr_vec);
-  foo11(ref<vec<Sam>> s_vec_ptr);
-  foo12(ref<Sam[5]> s_array_ref);
-  foo13(ref<Sam>[5] s_ref_array);
-  foo14(ref<ref<ref<Sam>>> s_3ptr);
-  foo15(ref<ref<ref<int32_t>>> i_3ptr);
-  foo16(Ptr p);
-  foo17(ref<Ptr> p);
-  foo18(ref<string> str_ref, ref<string> str_ref2, string str);
-  foo19(ref<vec<Ada>> a_vec_ref, vec<Ada> a_vec, ref<vec<Ada>> a_vec_ref2);
-  foo20(vec<ref<Sam>> s_ptr_vec);
-  foo21(ref<Ada[1][2][3]> a_array_ptr);
-  foo22(ref<Ada>[1][2][3] a_ptr_array);
-
-  bar1() generates (Sam s, ref<Sam> s_ptr);
-  bar2() generates (Sam s, Ada a);
-  bar3() generates (Sam s, Ada a, Bob b);
-  bar4() generates (ref<Sam> s_ptr);
-  bar5() generates (Ada a, Bob b);
-  bar6() generates (ref<Ada> a_ptr);
-  bar7() generates (ref<Ada> a_ptr, ref<Bob> b_ptr);
-  bar8() generates (Dom d);
-  bar9() generates (ref<string> str_ref);
-  bar10() generates (vec<ref<Sam>> s_ptr_vec);
-  bar11() generates (ref<vec<Sam>> s_vec_ptr);
-  bar12() generates (ref<Sam[5]> s_array_ref);
-  bar13() generates (ref<Sam>[5] s_ref_array);
-  bar14() generates (ref<ref<ref<Sam>>> s_3ptr);
-  bar15() generates (ref<ref<ref<int32_t>>> i_3ptr);
-  bar16() generates (Ptr p);
-  bar17() generates (ref<Ptr> p);
-  bar18() generates (ref<string> str_ref, ref<string> str_ref2, string str);
-  bar19() generates (ref<vec<Ada>> a_vec_ref, vec<Ada> a_vec, ref<vec<Ada>> a_vec_ref2);
-  bar20() generates (vec<ref<Sam>> s_ptr_vec);
-  bar21() generates (ref<Ada[1][2][3]> a_array_ptr);
-  bar22() generates (ref<Ada>[1][2][3] a_ptr_array);
-
-  getErrors() generates(int32_t errors);
-};
diff --git a/tests/pointer/1.0/default/Android.bp b/tests/pointer/1.0/default/Android.bp
deleted file mode 100644
index 4825ac7..0000000
--- a/tests/pointer/1.0/default/Android.bp
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-cc_library {
-    name: "android.hardware.tests.pointer@1.0-impl",
-    defaults: ["hidl_defaults"],
-    relative_install_path: "hw",
-    srcs: [
-        "Graph.cpp",
-        "Pointer.cpp",
-    ],
-
-    shared_libs: [
-        "libbase",
-        "libcutils",
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "libpointertest",
-        "liblog",
-        "libutils",
-    ],
-
-    // These are static libs only for testing purposes and portability. Shared
-    // libs should be used on device.
-    static_libs: ["android.hardware.tests.pointer@1.0"],
-
-}
diff --git a/tests/pointer/1.0/default/Graph.cpp b/tests/pointer/1.0/default/Graph.cpp
deleted file mode 100644
index 5c8098b..0000000
--- a/tests/pointer/1.0/default/Graph.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#define LOG_TAG "hidl_test"
-
-#include "Graph.h"
-
-#include <log/log.h>
-
-#include <hidl-test/PointerHelper.h>
-
-#define PUSH_ERROR_IF(__cond__) if(__cond__) { errors.push_back(std::to_string(__LINE__) + ": " + #__cond__); }
-
-namespace android {
-namespace hardware {
-namespace tests {
-namespace pointer {
-namespace V1_0 {
-namespace implementation {
-
-// Methods from ::android::hardware::tests::pointer::V1_0::IGraph follow.
-Return<void> Graph::passAGraph(const IGraph::Graph& g) {
-    ALOGI("SERVER(Graph) passAGraph start.");
-    PUSH_ERROR_IF(!isSimpleGraph(g));
-    // logSimpleGraph("SERVER(Graph) passAGraph:", g);
-    return Void();
-}
-
-Return<void> Graph::giveAGraph(giveAGraph_cb _cb) {
-    IGraph::Graph g;
-    simpleGraph(g);
-    _cb(g);
-    return Void();
-}
-
-Return<void> Graph::passANode(const IGraph::Node& n) {
-    PUSH_ERROR_IF(n.data != 10);
-    return Void();
-}
-
-Return<void> Graph::passTwoGraphs(IGraph::Graph const* g1, IGraph::Graph const* g2) {
-    PUSH_ERROR_IF(g1 != g2);
-    PUSH_ERROR_IF(!isSimpleGraph(*g1));
-    logSimpleGraph("SERVER(Graph): passTwoGraphs", *g2);
-    return Void();
-}
-
-Return<void> Graph::passAGamma(const IGraph::Gamma& c) {
-    if(c.a_ptr == nullptr && c.b_ptr == nullptr)
-      return Void();
-    ALOGI("SERVER(Graph) passAGamma received c.a = %p, c.b = %p, c.a->s = %p, c.b->s = %p",
-        c.a_ptr, c.b_ptr, c.a_ptr->s_ptr, c.b_ptr->s_ptr);
-    ALOGI("SERVER(Graph) passAGamma received data %d, %d",
-        (int)c.a_ptr->s_ptr->data, (int)c.b_ptr->s_ptr->data);
-    PUSH_ERROR_IF(c.a_ptr->s_ptr != c.b_ptr->s_ptr);
-    return Void();
-}
-Return<void> Graph::passASimpleRef(const IGraph::Alpha * a_ptr) {
-    ALOGI("SERVER(Graph) passASimpleRef received %d", a_ptr->s_ptr->data);
-    PUSH_ERROR_IF(a_ptr->s_ptr->data != 500);
-    return Void();
-}
-Return<void> Graph::passASimpleRefS(const IGraph::Theta * s_ptr) {
-    ALOGI("SERVER(Graph) passASimpleRefS received %d @ %p", s_ptr->data, s_ptr);
-    PUSH_ERROR_IF(s_ptr->data == 10);
-    return Void();
-}
-Return<void> Graph::giveASimpleRef(giveASimpleRef_cb _cb) {
-    IGraph::Theta s; s.data = 500;
-    IGraph::Alpha a; a.s_ptr = &s;
-    _cb(&a);
-    return Void();
-}
-
-Return<int32_t> Graph::getErrors() {
-    if(!errors.empty()) {
-        for(const auto& e : errors)
-            ALOGW("SERVER(Graph) error: %s", e.c_str());
-    }
-    return errors.size();
-}
-
-IGraph* HIDL_FETCH_IGraph(const char* /* name */) {
-    return new Graph();
-}
-
-} // namespace implementation
-}  // namespace V1_0
-}  // namespace pointer
-}  // namespace tests
-}  // namespace hardware
-}  // namespace android
diff --git a/tests/pointer/1.0/default/Graph.h b/tests/pointer/1.0/default/Graph.h
deleted file mode 100644
index 03bd163..0000000
--- a/tests/pointer/1.0/default/Graph.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef ANDROID_HARDWARE_TESTS_POINTER_V1_0_GRAPH_H
-#define ANDROID_HARDWARE_TESTS_POINTER_V1_0_GRAPH_H
-
-#include <android/hardware/tests/pointer/1.0/IGraph.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
-namespace android {
-namespace hardware {
-namespace tests {
-namespace pointer {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::tests::pointer::V1_0::IGraph;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct Graph : public IGraph {
-    // Methods from ::android::hardware::tests::pointer::V1_0::IGraph follow.
-    Return<void> passANode(const IGraph::Node& n)  override;
-    Return<void> passAGraph(const IGraph::Graph& g)  override;
-    Return<void> passTwoGraphs(::android::hardware::tests::pointer::V1_0::IGraph::Graph const* g1, ::android::hardware::tests::pointer::V1_0::IGraph::Graph const* g2)  override;
-    Return<void> giveAGraph(giveAGraph_cb _hidl_cb)  override;
-    Return<void> passAGamma(const IGraph::Gamma& c)  override;
-    Return<void> passASimpleRef(::android::hardware::tests::pointer::V1_0::IGraph::Alpha const* a)  override;
-    Return<void> passASimpleRefS(::android::hardware::tests::pointer::V1_0::IGraph::Theta const* s)  override;
-    Return<void> giveASimpleRef(giveASimpleRef_cb _hidl_cb)  override;
-    Return<int32_t> getErrors()  override;
-private:
-    std::vector<std::string> errors;
-
-};
-
-extern "C" IGraph* HIDL_FETCH_IGraph(const char* name);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace pointer
-}  // namespace tests
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_TESTS_POINTER_V1_0_GRAPH_H
diff --git a/tests/pointer/1.0/default/Pointer.cpp b/tests/pointer/1.0/default/Pointer.cpp
deleted file mode 100644
index 52712d4..0000000
--- a/tests/pointer/1.0/default/Pointer.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#define LOG_TAG "hidl_test"
-
-#include "Pointer.h"
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace tests {
-namespace pointer {
-namespace V1_0 {
-namespace implementation {
-
-Return<int32_t> Pointer::getErrors() {
-    if(!errors.empty()) {
-        for(const auto& e : errors)
-            ALOGW("SERVER(Pointer) error: %s", e.c_str());
-    }
-    return errors.size();
-}
-
-IPointer* HIDL_FETCH_IPointer(const char* /* name */) {
-    return new Pointer();
-}
-
-} // namespace implementation
-}  // namespace V1_0
-}  // namespace pointer
-}  // namespace tests
-}  // namespace hardware
-}  // namespace android
diff --git a/tests/pointer/1.0/default/Pointer.h b/tests/pointer/1.0/default/Pointer.h
deleted file mode 100644
index d6e3e48..0000000
--- a/tests/pointer/1.0/default/Pointer.h
+++ /dev/null
@@ -1,338 +0,0 @@
-#ifndef ANDROID_HARDWARE_TESTS_POINTER_V1_0_POINTER_H
-#define ANDROID_HARDWARE_TESTS_POINTER_V1_0_POINTER_H
-
-#include <android/hardware/tests/pointer/1.0/IPointer.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
-
-// TODO move to Pointer.cpp so that I won't have weird macros in headers
-#define PUSH_ERROR_IF(__cond__) if(__cond__) { errors.push_back(std::to_string(__LINE__) + ": " + #__cond__); }
-
-namespace android {
-namespace hardware {
-namespace tests {
-namespace pointer {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::tests::pointer::V1_0::IPointer;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct Pointer : public IPointer {
-private:
-    std::vector<std::string> errors;
-public:
-    Return<int32_t> getErrors() override;
-    Return<void> foo1(const IPointer::Sam& s, IPointer::Sam const* s_ptr) override {
-        PUSH_ERROR_IF(!(&s == s_ptr));
-        return Void();
-    }
-    Return<void> foo2(const IPointer::Sam& s, const IPointer::Ada& a) override {
-        PUSH_ERROR_IF(!(&s == a.s_ptr));
-        return Void();
-    }
-    Return<void> foo3(const IPointer::Sam& s, const IPointer::Ada& a, const IPointer::Bob& b) override {
-        PUSH_ERROR_IF(!(&a == b.a_ptr && a.s_ptr == b.s_ptr && a.s_ptr == &s));
-        return Void();
-    }
-    Return<void> foo4(IPointer::Sam const* s_ptr) override {
-        PUSH_ERROR_IF(!(s_ptr->data == 500));
-        return Void();
-    }
-    Return<void> foo5(const IPointer::Ada& a, const IPointer::Bob& b) override {
-        PUSH_ERROR_IF(!(a.s_ptr == b.s_ptr && b.a_ptr == &a));
-        return Void();
-    }
-    Return<void> foo6(IPointer::Ada const* a_ptr) override {
-        PUSH_ERROR_IF(!(a_ptr->s_ptr->data == 500));
-        return Void();
-    }
-    Return<void> foo7(IPointer::Ada const* a_ptr, IPointer::Bob const* b_ptr) override {
-        PUSH_ERROR_IF(!(a_ptr->s_ptr == b_ptr->s_ptr && a_ptr == b_ptr->a_ptr && a_ptr->s_ptr->data == 500));
-        return Void();
-    }
-    Return<void> foo8(const IPointer::Dom& d) override {
-        const IPointer::Cin& c = d.c;
-        PUSH_ERROR_IF(&c.a != c.b_ptr->a_ptr);
-        PUSH_ERROR_IF(c.a.s_ptr != c.b_ptr->s_ptr);
-        PUSH_ERROR_IF(c.a.s_ptr->data != 500);
-        return Void();
-    }
-    Return<void> foo9(::android::hardware::hidl_string const* str_ref) override {
-        PUSH_ERROR_IF(!(strcmp(str_ref->c_str(), "meowmeowmeow") == 0));
-        return Void();
-    }
-    Return<void> foo10(const ::android::hardware::hidl_vec<IPointer::Sam const*>& s_ptr_vec) override {
-        PUSH_ERROR_IF(s_ptr_vec[0]->data != 500);
-        if(s_ptr_vec.size() != 5) {
-            errors.push_back("foo10: s_ptr_vec.size() != 5");
-            return Void();
-        }
-        for(size_t i = 0; i < s_ptr_vec.size(); i++)
-            PUSH_ERROR_IF(s_ptr_vec[0] != s_ptr_vec[i]);
-        return Void();
-    }
-    Return<void> foo11(::android::hardware::hidl_vec<IPointer::Sam> const* s_vec_ptr) override {
-        if(s_vec_ptr->size() != 5) {
-            errors.push_back("foo11: s_vec_ptr->size() != 5");
-            return Void();
-        }
-        for(size_t i = 0; i < 5; i++)
-            PUSH_ERROR_IF((*s_vec_ptr)[i].data != 500);
-        return Void();
-    }
-    Return<void> foo12(hidl_array<IPointer::Sam, 5> const* s_array_ref) override {
-        for(size_t i = 0; i < 5; ++i)
-            PUSH_ERROR_IF((*s_array_ref)[i].data != 500);
-        return Void();
-    }
-    Return<void> foo13(const hidl_array<IPointer::Sam const*, 5>& s_ref_array) override {
-        PUSH_ERROR_IF(s_ref_array[0]->data != 500)
-        for(size_t i = 0; i < 5; i++)
-            PUSH_ERROR_IF(s_ref_array[i] != s_ref_array[0])
-        return Void();
-    }
-    Return<void> foo14(IPointer::Sam const* const* const* s_3ptr) override {
-        PUSH_ERROR_IF(!((***s_3ptr).data == 500))
-        return Void();
-    }
-    Return<void> foo15(int32_t const* const* const* i_3ptr) override {
-        PUSH_ERROR_IF(!((***i_3ptr) == 500))
-        return Void();
-    }
-
-    Return<void> foo16(const IPointer::Ptr& p) override {
-        PUSH_ERROR_IF((*p.array_ptr)[0].s_ptr->data != 500);
-        for(size_t i = 0; i < 5; i++) PUSH_ERROR_IF((*p.array_ptr)[i].s_ptr != (*p.array_ptr)[0].s_ptr);
-        PUSH_ERROR_IF(*(p.int_ptr) != 500);
-        for(size_t i = 0; i < 5; i++) PUSH_ERROR_IF((*p.int_array_ptr)[i] != 500);
-        for(size_t i = 0; i < 5; i++) PUSH_ERROR_IF(p.int_ptr_array[i] != p.int_ptr);
-        PUSH_ERROR_IF(p.a_ptr_vec.size() != 5);
-        PUSH_ERROR_IF(p.a_ptr_vec[0]->s_ptr->data != 500);
-        for(size_t i = 0; i < 5; i++) PUSH_ERROR_IF(p.a_ptr_vec[i]->s_ptr != p.a_ptr_vec[0]->s_ptr);
-        PUSH_ERROR_IF(strcmp(p.str_ref->c_str(), "meowmeowmeow") != 0);
-        PUSH_ERROR_IF(p.a_vec_ptr->size() != 5);
-        PUSH_ERROR_IF((*p.a_vec_ptr)[0].s_ptr->data != 500);
-        for(size_t i = 0; i < 5; i++) PUSH_ERROR_IF((*p.a_vec_ptr)[i].s_ptr != (*p.a_vec_ptr)[0].s_ptr);
-        return Void();
-    };
-    Return<void> foo17(IPointer::Ptr const* p) override {
-        return foo16(*p);
-    };
-    Return<void> foo18(hidl_string const* str_ref, hidl_string const* str_ref2, const hidl_string& str) override {
-        PUSH_ERROR_IF(&str != str_ref);
-        PUSH_ERROR_IF(str_ref != str_ref2);
-        PUSH_ERROR_IF(strcmp(str.c_str(), "meowmeowmeow") != 0)
-        return Void();
-    };
-    Return<void> foo19(
-                hidl_vec<IPointer::Ada> const* a_vec_ref,
-                const hidl_vec<IPointer::Ada>& a_vec,
-                hidl_vec<IPointer::Ada> const* a_vec_ref2) {
-        PUSH_ERROR_IF(&a_vec != a_vec_ref);
-        PUSH_ERROR_IF(a_vec_ref2 != a_vec_ref);
-        PUSH_ERROR_IF(a_vec.size() != 5);
-        PUSH_ERROR_IF(a_vec[0].s_ptr->data != 500);
-        for(size_t i = 0; i < 5; i++)
-            PUSH_ERROR_IF(a_vec[i].s_ptr != a_vec[0].s_ptr);
-        return Void();
-    };
-
-    Return<void> foo20(const hidl_vec<IPointer::Sam const*>&) override {
-        return Void();
-    }
-    Return<void> foo21(hidl_array<IPointer::Ada, 1, 2, 3> const* a_array_ptr) override {
-        const hidl_array<IPointer::Ada, 1, 2, 3>& a_array = *a_array_ptr;
-        PUSH_ERROR_IF(a_array[0][0][0].s_ptr->data != 500);
-        for(size_t i = 0; i < 1; i++)
-            for(size_t j = 0; j < 2; j++)
-                for(size_t k = 0; k < 3; k++)
-                    PUSH_ERROR_IF(a_array[i][j][k].s_ptr != a_array[0][0][0].s_ptr);
-        return Void();
-    }
-    Return<void> foo22(const hidl_array<IPointer::Ada const*, 1, 2, 3>& a_ptr_array) override {
-        PUSH_ERROR_IF(a_ptr_array[0][0][0]->s_ptr->data != 500);
-        for(size_t i = 0; i < 1; i++)
-            for(size_t j = 0; j < 2; j++)
-                for(size_t k = 0; k < 3; k++)
-                    PUSH_ERROR_IF(a_ptr_array[i][j][k] != a_ptr_array[0][0][0]);
-        return Void();
-    }
-
-    IPointer::Sam *s;
-    IPointer::Ada *a;
-    IPointer::Bob *b;
-    IPointer::Cin *c;
-    IPointer::Dom *d;
-
-    IPointer::Ptr p;
-    hidl_array<IPointer::Ada, 5> a_array;
-    int32_t someInt;
-    hidl_array<int32_t, 5> someIntArray;
-    hidl_string str;
-    hidl_vec<IPointer::Ada> a_vec;
-    Pointer() {
-        d = new IPointer::Dom();
-        s = new IPointer::Sam();
-        b = new IPointer::Bob();
-        c = &d->c;
-        a = &c->a;
-        b->s_ptr = a->s_ptr = s;
-        b->a_ptr = a;
-        c->b_ptr = b;
-        s->data = 500;
-
-        someInt = 500;
-        for(size_t i = 0; i < 5; i++) someIntArray[i] = 500;
-
-        for(size_t i = 0; i < 5; i++) a_array[i] = *a;
-
-        for(size_t i = 0; i < 5; i++) p.ptr_array[i] = a;
-        p.array_ptr = &a_array;
-        p.int_ptr = &someInt;
-        p.int_array_ptr = &someIntArray;
-        for(size_t i = 0; i < 5; i++) p.int_ptr_array[i] = &someInt;
-        p.a_ptr_vec.resize(5);
-        for(size_t i = 0; i < 5; i++) p.a_ptr_vec[i] = a;
-        str = "meowmeowmeow";
-        p.str_ref = &str;
-        a_vec.resize(5);
-        for(size_t i = 0; i < 5; i++) a_vec[i].s_ptr = s;
-        p.a_vec_ptr = &a_vec;
-    }
-    ~Pointer() {
-        delete d; delete s; delete b;
-    }
-    Return<void> bar1(bar1_cb _cb) override {
-        _cb(*s, s);
-        return Void();
-    }
-    Return<void> bar2(bar2_cb _cb) override {
-        _cb(*s, *a);
-        return Void();
-    }
-    Return<void> bar3(bar3_cb _cb) override {
-        _cb(*s, *a, *b);
-        return Void();
-    }
-    Return<void> bar4(bar4_cb _cb) override {
-        _cb(s);
-        return Void();
-    }
-    Return<void> bar5(bar5_cb _cb) override {
-        _cb(*a, *b);
-        return Void();
-    }
-    Return<void> bar6(bar6_cb _cb) override {
-        _cb(a);
-        return Void();
-    }
-    Return<void> bar7(bar7_cb _cb) override {
-        _cb(a, b);
-        return Void();
-    }
-    Return<void> bar8(bar8_cb _cb) override {
-        _cb(*d);
-        return Void();
-    }
-    Return<void> bar9(bar9_cb _cb) override {
-        _cb(&str);
-        return Void();
-    }
-    Return<void> bar10(bar10_cb _cb) override {
-        hidl_vec<const IPointer::Sam *> v; v.resize(5);
-        for(size_t i = 0; i < 5; i++) v[i] = s;
-        _cb(v);
-        return Void();
-    }
-    Return<void> bar11(bar11_cb _cb) override {
-        hidl_vec<IPointer::Sam> v; v.resize(5);
-        for(size_t i = 0; i < 5; i++) v[i].data = 500;
-            _cb(&v);
-        return Void();
-    }
-    Return<void> bar12(bar12_cb _cb) override {
-        hidl_array<IPointer::Sam, 5> array;
-        for(size_t i = 0; i < 5; i++) array[i] = *s;
-        _cb(&array);
-        return Void();
-    }
-    Return<void> bar13(bar13_cb _cb) override {
-        hidl_array<const IPointer::Sam *, 5> array;
-        for(size_t i = 0; i < 5; i++) array[i] = s;
-        _cb(array);
-        return Void();
-    }
-    Return<void> bar14(bar14_cb _cb) override {
-        IPointer::Sam const* p1 = s;
-        IPointer::Sam const* const* p2 = &p1;
-        _cb(&p2);
-        return Void();
-    }
-    Return<void> bar15(bar15_cb _cb) override {
-        int32_t const* p1 = &someInt;
-        int32_t const* const* p2 = &p1;
-        _cb(&p2);
-        return Void();
-    }
-    Return<void> bar16(bar16_cb _cb) override {
-        _cb(p);
-        return Void();
-    }
-    Return<void> bar17(bar17_cb _cb) override {
-        _cb(&p);
-        return Void();
-    }
-    Return<void> bar18(bar18_cb _cb) override {
-        _cb(&str, &str, str);
-        return Void();
-    }
-    Return<void> bar19(bar19_cb _cb) override {
-        _cb(&a_vec, a_vec, &a_vec);
-        return Void();
-    }
-    Return<void> bar20(bar20_cb _cb) override {
-        // 1026 == PARCEL_REF_CAP + 2.
-        // 1026 means 1 writeBuffer and 1025 writeReferences. 1025 > PARCEL_REF_CAP.
-        hidl_vec<const IPointer::Sam *> v; v.resize(1026);
-        for(size_t i = 0; i < 1026; i++) v[i] = s;
-        _cb(v);
-        return Void();
-    }
-    Return<void> bar21(bar21_cb _cb) override {
-        hidl_array<IPointer::Ada, 1, 2, 3> a_array;
-        for(size_t i = 0; i < 1; i++)
-            for(size_t j = 0; j < 2; j++)
-                for(size_t k = 0; k < 3; k++)
-                    a_array[i][j][k] = *a;
-        _cb(&a_array);
-        return Void();
-    }
-    Return<void> bar22(bar22_cb _cb) override {
-        hidl_array<const IPointer::Ada *, 1, 2, 3> a_ptr_array;
-        for(size_t i = 0; i < 1; i++)
-            for(size_t j = 0; j < 2; j++)
-                for(size_t k = 0; k < 3; k++)
-                    a_ptr_array[i][j][k] = a;
-        _cb(a_ptr_array);
-        return Void();
-    }
-};
-
-extern "C" IPointer* HIDL_FETCH_IPointer(const char* name);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace pointer
-}  // namespace tests
-}  // namespace hardware
-}  // namespace android
-
-#undef PUSH_ERROR_IF
-
-#endif  // ANDROID_HARDWARE_TESTS_POINTER_V1_0_POINTER_H
diff --git a/tests/pointer/1.0/default/lib/Android.bp b/tests/pointer/1.0/default/lib/Android.bp
deleted file mode 100644
index 180906b..0000000
--- a/tests/pointer/1.0/default/lib/Android.bp
+++ /dev/null
@@ -1,19 +0,0 @@
-cc_library {
-    name: "libpointertest",
-    defaults: ["hidl_defaults"],
-    srcs: [
-        "PointerHelper.cpp"
-    ],
-
-    shared_libs: [
-        "libbase",
-        "libhidlbase",
-        "libhidltransport",
-        "liblog",
-    ],
-    static_libs: ["android.hardware.tests.pointer@1.0"],
-
-    local_include_dirs: ["include/hidl-test"],
-    export_include_dirs: ["include"],
-
-}
diff --git a/tests/pointer/1.0/default/lib/PointerHelper.cpp b/tests/pointer/1.0/default/lib/PointerHelper.cpp
deleted file mode 100644
index 0a64cc3..0000000
--- a/tests/pointer/1.0/default/lib/PointerHelper.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#define LOG_TAG "hidl_test"
-
-#include <log/log.h>
-
-#include "PointerHelper.h"
-
-namespace android {
-
-void simpleGraph(IGraph::Graph& g) {
-    g.nodes.resize(2);
-    g.edges.resize(1);
-    g.nodes[0].data = 10;
-    g.nodes[1].data = 20;
-    g.edges[0].left = &g.nodes[0];
-    g.edges[0].right = &g.nodes[1];
-}
-
-bool isSimpleGraph(const IGraph::Graph &g) {
-    if(g.nodes.size() != 2) return false;
-    if(g.edges.size() != 1) return false;
-    if(g.nodes[0].data != 10) return false;
-    if(g.nodes[1].data != 20) return false;
-    if(g.edges[0].left != &g.nodes[0]) return false;
-    if(g.edges[0].right != &g.nodes[1]) return false;
-    return true;
-}
-
-void logSimpleGraph(const char *prefix, const IGraph::Graph& g) {
-    ALOGI("%s Graph %p, %d nodes, %d edges", prefix, &g, (int)g.nodes.size(), (int)g.edges.size());
-    std::ostringstream os;
-    for(size_t i = 0; i < g.nodes.size(); i++)
-      os << &g.nodes[i] << " = " << g.nodes[i].data << ", ";
-    ALOGI("%s Nodes: [%s]", prefix, os.str().c_str());
-    os.str("");
-    os.clear();
-    for(size_t i = 0; i < g.edges.size(); i++)
-      os << g.edges[i].left << " -> " << g.edges[i].right << ", ";
-    ALOGI("%s Edges: [%s]", prefix, os.str().c_str());
-}
-} // namespace android
diff --git a/tests/pointer/1.0/default/lib/include/hidl-test/PointerHelper.h b/tests/pointer/1.0/default/lib/include/hidl-test/PointerHelper.h
deleted file mode 100644
index cd2edcb..0000000
--- a/tests/pointer/1.0/default/lib/include/hidl-test/PointerHelper.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef ANDROID_HIDL_TEST_POINTER_HELPER_H
-#define ANDROID_HIDL_TEST_POINTER_HELPER_H
-
-#include <android/hardware/tests/pointer/1.0/IGraph.h>
-
-using ::android::hardware::tests::pointer::V1_0::IGraph;
-
-namespace android {
-
-void simpleGraph(IGraph::Graph& g);
-bool isSimpleGraph(const IGraph::Graph &g);
-void logSimpleGraph(const char *prefix, const IGraph::Graph& g);
-
-} // namespace android
-#endif // ANDROID_HIDL_TEST_POINTER_HELPER_H
diff --git a/tests/safeunion/1.0/Android.bp b/tests/safeunion/1.0/Android.bp
index 87edd53..2937832 100644
--- a/tests/safeunion/1.0/Android.bp
+++ b/tests/safeunion/1.0/Android.bp
@@ -13,4 +13,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tests/safeunion/cpp/1.0/Android.bp b/tests/safeunion/cpp/1.0/Android.bp
index 1111719..221643a 100644
--- a/tests/safeunion/cpp/1.0/Android.bp
+++ b/tests/safeunion/cpp/1.0/Android.bp
@@ -11,4 +11,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/trie/1.0/Android.bp b/tests/trie/1.0/Android.bp
index 0795f66..5a33aea 100644
--- a/tests/trie/1.0/Android.bp
+++ b/tests/trie/1.0/Android.bp
@@ -12,4 +12,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/tests/trie/1.0/types.hal b/tests/trie/1.0/types.hal
index c626909..889d3b2 100644
--- a/tests/trie/1.0/types.hal
+++ b/tests/trie/1.0/types.hal
@@ -29,16 +29,16 @@
 // Some forward reference tests.
 
 struct A {
-    ref<B> b;
+    vec<B> b;
 };
 
 struct B {
-    ref<A> a;
+    vec<A> a;
 };
 
-typedef ref<S> refS;
+typedef vec<S> vecS;
 struct S {
-    refS f;
+    vecS f;
 };
 
 enum E2 : E1 {
diff --git a/tetheroffload/config/1.0/Android.bp b/tetheroffload/config/1.0/Android.bp
index f20d77c..321224a 100644
--- a/tetheroffload/config/1.0/Android.bp
+++ b/tetheroffload/config/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tetheroffload/control/1.0/Android.bp b/tetheroffload/control/1.0/Android.bp
index dc2487b..f894448 100644
--- a/tetheroffload/control/1.0/Android.bp
+++ b/tetheroffload/control/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/thermal/1.0/Android.bp b/thermal/1.0/Android.bp
index 8428977..de168d8 100644
--- a/thermal/1.0/Android.bp
+++ b/thermal/1.0/Android.bp
@@ -16,4 +16,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/thermal/1.1/Android.bp b/thermal/1.1/Android.bp
index 8c0f1f9..f38ed3b 100644
--- a/thermal/1.1/Android.bp
+++ b/thermal/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tv/cec/1.0/Android.bp b/tv/cec/1.0/Android.bp
index 7626dc0..d41a7e7 100644
--- a/tv/cec/1.0/Android.bp
+++ b/tv/cec/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/tv/input/1.0/Android.bp b/tv/input/1.0/Android.bp
index a6c1959..7288558 100644
--- a/tv/input/1.0/Android.bp
+++ b/tv/input/1.0/Android.bp
@@ -18,4 +18,3 @@
     gen_java: false,
     gen_java_constants: true,
 }
-
diff --git a/usb/1.0/Android.bp b/usb/1.0/Android.bp
index a00b671..c0e883f 100644
--- a/usb/1.0/Android.bp
+++ b/usb/1.0/Android.bp
@@ -17,4 +17,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/usb/1.1/Android.bp b/usb/1.1/Android.bp
index fb2cc4e..6f2abae 100644
--- a/usb/1.1/Android.bp
+++ b/usb/1.1/Android.bp
@@ -18,4 +18,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/usb/gadget/1.0/Android.bp b/usb/gadget/1.0/Android.bp
index 7ee432b..4921abf 100644
--- a/usb/gadget/1.0/Android.bp
+++ b/usb/gadget/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/vibrator/1.0/Android.bp b/vibrator/1.0/Android.bp
index acc97d4..792e130 100644
--- a/vibrator/1.0/Android.bp
+++ b/vibrator/1.0/Android.bp
@@ -16,4 +16,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/vibrator/1.1/Android.bp b/vibrator/1.1/Android.bp
index 2055e5a..0d04a87 100644
--- a/vibrator/1.1/Android.bp
+++ b/vibrator/1.1/Android.bp
@@ -17,4 +17,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/vibrator/1.2/Android.bp b/vibrator/1.2/Android.bp
index 481adee..290a0cf 100644
--- a/vibrator/1.2/Android.bp
+++ b/vibrator/1.2/Android.bp
@@ -17,4 +17,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/vr/1.0/Android.bp b/vr/1.0/Android.bp
index ca47a6e..f91f874 100644
--- a/vr/1.0/Android.bp
+++ b/vr/1.0/Android.bp
@@ -14,4 +14,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/weaver/1.0/Android.bp b/weaver/1.0/Android.bp
index 7f93b10..7d5b8fe 100644
--- a/weaver/1.0/Android.bp
+++ b/weaver/1.0/Android.bp
@@ -15,4 +15,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/1.0/Android.bp b/wifi/1.0/Android.bp
index c5ee1bb..958ff3f 100644
--- a/wifi/1.0/Android.bp
+++ b/wifi/1.0/Android.bp
@@ -28,4 +28,3 @@
     gen_java: true,
     gen_java_constants: true,
 }
-
diff --git a/wifi/1.1/Android.bp b/wifi/1.1/Android.bp
index a4499c8..a34ac44 100644
--- a/wifi/1.1/Android.bp
+++ b/wifi/1.1/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/1.2/Android.bp b/wifi/1.2/Android.bp
index 1863eaf..c28d09b 100644
--- a/wifi/1.2/Android.bp
+++ b/wifi/1.2/Android.bp
@@ -22,4 +22,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp
index 3bd0557..8c2d3cb 100644
--- a/wifi/1.2/default/wifi_chip.cpp
+++ b/wifi/1.2/default/wifi_chip.cpp
@@ -113,7 +113,7 @@
     const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
     DIR* dir_dump = opendir(kTombstoneFolderPath);
     if (!dir_dump) {
-        LOG(ERROR) << "Failed to open directory: " << strerror(errno);
+        PLOG(ERROR) << "Failed to open directory";
         return false;
     }
     unique_fd dir_auto_closer(dirfd(dir_dump));
@@ -128,8 +128,7 @@
         struct stat cur_file_stat;
         std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
         if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
-            LOG(ERROR) << "Failed to get file stat for " << cur_file_path
-                       << ": " << strerror(errno);
+            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
             success = false;
             continue;
         }
@@ -144,7 +143,7 @@
         if (cur_file_count > kMaxRingBufferFileNum ||
             cur_file.first < delete_files_before) {
             if (unlink(cur_file.second.c_str()) != 0) {
-                LOG(ERROR) << "Error deleting file " << strerror(errno);
+                PLOG(ERROR) << "Error deleting file";
                 success = false;
             }
             cur_file_count--;
@@ -168,13 +167,11 @@
                 major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
                 minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
     if (write(out_fd, read_buf.data(), llen) == -1) {
-        LOG(ERROR) << "Error writing cpio header to file " << file_name << " "
-                   << strerror(errno);
+        PLOG(ERROR) << "Error writing cpio header to file " << file_name;
         return false;
     }
     if (write(out_fd, file_name, file_name_len) == -1) {
-        LOG(ERROR) << "Error writing filename to file " << file_name << " "
-                   << strerror(errno);
+        PLOG(ERROR) << "Error writing filename to file " << file_name;
         return false;
     }
 
@@ -183,8 +180,7 @@
     if (llen != 0) {
         const uint32_t zero = 0;
         if (write(out_fd, &zero, 4 - llen) == -1) {
-            LOG(ERROR) << "Error padding 0s to file " << file_name << " "
-                       << strerror(errno);
+            PLOG(ERROR) << "Error padding 0s to file " << file_name;
             return false;
         }
     }
@@ -200,17 +196,17 @@
     while (llen > 0) {
         ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
         if (bytes_read == -1) {
-            LOG(ERROR) << "Error reading file " << strerror(errno);
+            PLOG(ERROR) << "Error reading file";
             return ++n_error;
         }
         llen -= bytes_read;
         if (write(out_fd, read_buf.data(), bytes_read) == -1) {
-            LOG(ERROR) << "Error writing data to file " << strerror(errno);
+            PLOG(ERROR) << "Error writing data to file";
             return ++n_error;
         }
         if (bytes_read == 0) {  // this should never happen, but just in case
                                 // to unstuck from while loop
-            LOG(ERROR) << "Unexpected read result for " << strerror(errno);
+            PLOG(ERROR) << "Unexpected read result";
             n_error++;
             break;
         }
@@ -219,7 +215,7 @@
     if (llen != 0) {
         const uint32_t zero = 0;
         if (write(out_fd, &zero, 4 - llen) == -1) {
-            LOG(ERROR) << "Error padding 0s to file " << strerror(errno);
+            PLOG(ERROR) << "Error padding 0s to file";
             return ++n_error;
         }
     }
@@ -234,7 +230,7 @@
               sprintf(read_buf.data(), "070701%040X%056X%08XTRAILER!!!", 1,
                       0x0b, 0) +
                   4) == -1) {
-        LOG(ERROR) << "Error writing trailing bytes " << strerror(errno);
+        PLOG(ERROR) << "Error writing trailing bytes";
         return false;
     }
     return true;
@@ -248,7 +244,7 @@
     size_t n_error = 0;
     DIR* dir_dump = opendir(input_dir);
     if (!dir_dump) {
-        LOG(ERROR) << "Failed to open directory: " << strerror(errno);
+        PLOG(ERROR) << "Failed to open directory";
         return ++n_error;
     }
     unique_fd dir_auto_closer(dirfd(dir_dump));
@@ -263,15 +259,13 @@
         struct stat st;
         const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
         if (stat(cur_file_path.c_str(), &st) == -1) {
-            LOG(ERROR) << "Failed to get file stat for " << cur_file_path
-                       << ": " << strerror(errno);
+            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
             n_error++;
             continue;
         }
         const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
         if (fd_read == -1) {
-            LOG(ERROR) << "Failed to open file " << cur_file_path << " "
-                       << strerror(errno);
+            PLOG(ERROR) << "Failed to open file " << cur_file_path;
             n_error++;
             continue;
         }
@@ -1400,14 +1394,14 @@
             kTombstoneFolderPath + item.first + "XXXXXXXXXX";
         const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
         if (dump_fd == -1) {
-            LOG(ERROR) << "create file failed: " << strerror(errno);
+            PLOG(ERROR) << "create file failed";
             return false;
         }
         unique_fd file_auto_closer(dump_fd);
         for (const auto& cur_block : cur_buffer.getData()) {
             if (write(dump_fd, cur_block.data(),
                       sizeof(cur_block[0]) * cur_block.size()) == -1) {
-                LOG(ERROR) << "Error writing to file " << strerror(errno);
+                PLOG(ERROR) << "Error writing to file";
             }
         }
     }
diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.2/default/wifi_legacy_hal.cpp
index 55ec96d..375204c 100644
--- a/wifi/1.2/default/wifi_legacy_hal.cpp
+++ b/wifi/1.2/default/wifi_legacy_hal.cpp
@@ -550,7 +550,6 @@
                 }
                 // Fall through if failed. Failure to retrieve cached scan
                 // results should trigger a background scan failure.
-                [[fallthrough]];
                 case WIFI_SCAN_FAILED:
                     on_failure_user_callback(id);
                     on_gscan_event_internal_callback = nullptr;
diff --git a/wifi/hostapd/1.0/Android.bp b/wifi/hostapd/1.0/Android.bp
index 9ee976e..cce1182 100644
--- a/wifi/hostapd/1.0/Android.bp
+++ b/wifi/hostapd/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/offload/1.0/Android.bp b/wifi/offload/1.0/Android.bp
index 1a9ae73..110bb70 100644
--- a/wifi/offload/1.0/Android.bp
+++ b/wifi/offload/1.0/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: false,
 }
-
diff --git a/wifi/supplicant/1.0/Android.bp b/wifi/supplicant/1.0/Android.bp
index c99706d..d91512f 100644
--- a/wifi/supplicant/1.0/Android.bp
+++ b/wifi/supplicant/1.0/Android.bp
@@ -26,4 +26,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/wifi/supplicant/1.1/Android.bp b/wifi/supplicant/1.1/Android.bp
index 832d1ad..6d940d1 100644
--- a/wifi/supplicant/1.1/Android.bp
+++ b/wifi/supplicant/1.1/Android.bp
@@ -18,4 +18,3 @@
     ],
     gen_java: true,
 }
-