Merge "Update doc in Gnss Hal v1.1" into pi-dev
diff --git a/audio/4.0/config/audio_policy_configuration.xsd b/audio/4.0/config/audio_policy_configuration.xsd
index e5b4449..34c2b11 100644
--- a/audio/4.0/config/audio_policy_configuration.xsd
+++ b/audio/4.0/config/audio_policy_configuration.xsd
@@ -104,7 +104,7 @@
                         <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
                         <xs:element name="routes" type="routes" minOccurs="0"/>
                     </xs:sequence>
-                    <xs:attribute name="name" type="xsd:string" use="required"/>
+                    <xs:attribute name="name" type="xs:string" use="required"/>
                     <xs:attribute name="halVersion" type="halVersion" use="required"/>
                 </xs:complexType>
                 <xs:unique name="mixPortNameUniqueness">
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Conversions.h b/audio/core/all-versions/default/include/core/all-versions/default/Conversions.h
index fa05350..b38eca3 100644
--- a/audio/core/all-versions/default/include/core/all-versions/default/Conversions.h
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Conversions.h
@@ -30,6 +30,11 @@
 
 std::string deviceAddressToHal(const DeviceAddress& address);
 
+#ifdef AUDIO_HAL_VERSION_4_0
+bool halToMicrophoneCharacteristics(MicrophoneInfo* pDst,
+                                    const struct audio_microphone_characteristic_t& src);
+#endif
+
 }  // namespace implementation
 }  // namespace AUDIO_HAL_VERSION
 }  // namespace audio
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Conversions.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/Conversions.impl.h
index 3f3f936..004a99e 100644
--- a/audio/core/all-versions/default/include/core/all-versions/default/Conversions.impl.h
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Conversions.impl.h
@@ -24,6 +24,8 @@
 namespace AUDIO_HAL_VERSION {
 namespace implementation {
 
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+
 std::string deviceAddressToHal(const DeviceAddress& address) {
     // HAL assumes that the address is NUL-terminated.
     char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
@@ -54,6 +56,132 @@
     return halAddress;
 }
 
+#ifdef AUDIO_HAL_VERSION_4_0
+status_t deviceAddressFromHal(audio_devices_t device, const char* halAddress,
+                              DeviceAddress* address) {
+    if (address == nullptr) {
+        return BAD_VALUE;
+    }
+    address->device = AudioDevice(device);
+    if (halAddress == nullptr || strnlen(halAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
+        return OK;
+    }
+
+    const bool isInput = (device & AUDIO_DEVICE_BIT_IN) != 0;
+    if (isInput) device &= ~AUDIO_DEVICE_BIT_IN;
+    if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) ||
+        (isInput && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+        int status =
+            sscanf(halAddress, "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", &address->address.mac[0],
+                   &address->address.mac[1], &address->address.mac[2], &address->address.mac[3],
+                   &address->address.mac[4], &address->address.mac[5]);
+        return status == 6 ? OK : BAD_VALUE;
+    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_IP) != 0) ||
+               (isInput && (device & AUDIO_DEVICE_IN_IP) != 0)) {
+        int status =
+            sscanf(halAddress, "%hhu.%hhu.%hhu.%hhu", &address->address.ipv4[0],
+                   &address->address.ipv4[1], &address->address.ipv4[2], &address->address.ipv4[3]);
+        return status == 4 ? OK : BAD_VALUE;
+    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_USB)) != 0 ||
+               (isInput && (device & AUDIO_DEVICE_IN_ALL_USB)) != 0) {
+        int status = sscanf(halAddress, "card=%d;device=%d", &address->address.alsa.card,
+                            &address->address.alsa.device);
+        return status == 2 ? OK : BAD_VALUE;
+    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_BUS) != 0) ||
+               (isInput && (device & AUDIO_DEVICE_IN_BUS) != 0)) {
+        address->busAddress = halAddress;
+        return OK;
+    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 ||
+               (isInput && (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
+        address->rSubmixAddress = halAddress;
+        return OK;
+    }
+    address->busAddress = halAddress;
+    return OK;
+}
+
+AudioMicrophoneChannelMapping halToChannelMapping(audio_microphone_channel_mapping_t mapping) {
+    switch (mapping) {
+        case AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED:
+            return AudioMicrophoneChannelMapping::UNUSED;
+        case AUDIO_MICROPHONE_CHANNEL_MAPPING_DIRECT:
+            return AudioMicrophoneChannelMapping::DIRECT;
+        case AUDIO_MICROPHONE_CHANNEL_MAPPING_PROCESSED:
+            return AudioMicrophoneChannelMapping::PROCESSED;
+    }
+}
+
+AudioMicrophoneLocation halToLocation(audio_microphone_location_t location) {
+    switch (location) {
+        default:
+        case AUDIO_MICROPHONE_LOCATION_UNKNOWN:
+            return AudioMicrophoneLocation::UNKNOWN;
+        case AUDIO_MICROPHONE_LOCATION_MAINBODY:
+            return AudioMicrophoneLocation::MAINBODY;
+        case AUDIO_MICROPHONE_LOCATION_MAINBODY_MOVABLE:
+            return AudioMicrophoneLocation::MAINBODY_MOVABLE;
+        case AUDIO_MICROPHONE_LOCATION_PERIPHERAL:
+            return AudioMicrophoneLocation::PERIPHERAL;
+    }
+}
+
+AudioMicrophoneDirectionality halToDirectionality(audio_microphone_directionality_t dir) {
+    switch (dir) {
+        default:
+        case AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN:
+            return AudioMicrophoneDirectionality::UNKNOWN;
+        case AUDIO_MICROPHONE_DIRECTIONALITY_OMNI:
+            return AudioMicrophoneDirectionality::OMNI;
+        case AUDIO_MICROPHONE_DIRECTIONALITY_BI_DIRECTIONAL:
+            return AudioMicrophoneDirectionality::BI_DIRECTIONAL;
+        case AUDIO_MICROPHONE_DIRECTIONALITY_CARDIOID:
+            return AudioMicrophoneDirectionality::CARDIOID;
+        case AUDIO_MICROPHONE_DIRECTIONALITY_HYPER_CARDIOID:
+            return AudioMicrophoneDirectionality::HYPER_CARDIOID;
+        case AUDIO_MICROPHONE_DIRECTIONALITY_SUPER_CARDIOID:
+            return AudioMicrophoneDirectionality::SUPER_CARDIOID;
+    }
+}
+
+bool halToMicrophoneCharacteristics(MicrophoneInfo* pDst,
+                                    const struct audio_microphone_characteristic_t& src) {
+    bool status = false;
+    if (pDst != NULL) {
+        pDst->deviceId = src.device_id;
+
+        if (deviceAddressFromHal(src.device, src.address, &pDst->deviceAddress) != OK) {
+            return false;
+        }
+        pDst->channelMapping.resize(AUDIO_CHANNEL_COUNT_MAX);
+        for (size_t ch = 0; ch < pDst->channelMapping.size(); ch++) {
+            pDst->channelMapping[ch] = halToChannelMapping(src.channel_mapping[ch]);
+        }
+        pDst->location = halToLocation(src.location);
+        pDst->group = (AudioMicrophoneGroup)src.group;
+        pDst->indexInTheGroup = (uint32_t)src.index_in_the_group;
+        pDst->sensitivity = src.sensitivity;
+        pDst->maxSpl = src.max_spl;
+        pDst->minSpl = src.min_spl;
+        pDst->directionality = halToDirectionality(src.directionality);
+        pDst->frequencyResponse.resize(src.num_frequency_responses);
+        for (size_t k = 0; k < src.num_frequency_responses; k++) {
+            pDst->frequencyResponse[k].frequency = src.frequency_responses[0][k];
+            pDst->frequencyResponse[k].level = src.frequency_responses[1][k];
+        }
+        pDst->position.x = src.geometric_location.x;
+        pDst->position.y = src.geometric_location.y;
+        pDst->position.z = src.geometric_location.z;
+
+        pDst->orientation.x = src.orientation.x;
+        pDst->orientation.y = src.orientation.y;
+        pDst->orientation.z = src.orientation.z;
+
+        status = true;
+    }
+    return status;
+}
+#endif
+
 }  // namespace implementation
 }  // namespace AUDIO_HAL_VERSION
 }  // namespace audio
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h
index fb4b686..581e1dc 100644
--- a/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h
@@ -332,8 +332,20 @@
 
 #ifdef AUDIO_HAL_VERSION_4_0
 Return<void> Device::getMicrophones(getMicrophones_cb _hidl_cb) {
-    // TODO return device microphones
-    _hidl_cb(Result::NOT_SUPPORTED, {});
+    Result retval = Result::NOT_SUPPORTED;
+    size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT;
+    audio_microphone_characteristic_t mic_array[AUDIO_MICROPHONE_MAX_COUNT];
+
+    hidl_vec<MicrophoneInfo> microphones;
+    if (mDevice->get_microphones != NULL &&
+        mDevice->get_microphones(mDevice, &mic_array[0], &actual_mics) == 0) {
+        microphones.resize(actual_mics);
+        for (size_t i = 0; i < actual_mics; ++i) {
+            halToMicrophoneCharacteristics(&microphones[i], mic_array[i]);
+        }
+        retval = Result::OK;
+    }
+    _hidl_cb(retval, microphones);
     return Void();
 }
 
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.impl.h
index dcd3df1..8774be9 100644
--- a/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.impl.h
+++ b/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.impl.h
@@ -26,6 +26,8 @@
 
 using ::android::hardware::audio::AUDIO_HAL_VERSION::MessageQueueFlagBits;
 using ::android::hardware::audio::all_versions::implementation::isGainNormalized;
+#include "Conversions.h"
+#include "Util.h"
 
 namespace android {
 namespace hardware {
@@ -449,12 +451,39 @@
 }
 
 #ifdef AUDIO_HAL_VERSION_4_0
-Return<void> StreamIn::updateSinkMetadata(const SinkMetadata& /*sinkMetadata*/) {
-    return Void();  // TODO: propagate to legacy
+Return<void> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
+    if (mStream->update_sink_metadata == nullptr) {
+        return Void();  // not supported by the HAL
+    }
+    std::vector<record_track_metadata> halTracks;
+    halTracks.reserve(sinkMetadata.tracks.size());
+    for (auto& metadata : sinkMetadata.tracks) {
+        halTracks.push_back(
+            {.source = static_cast<audio_source_t>(metadata.source), .gain = metadata.gain});
+    }
+    const sink_metadata_t halMetadata = {
+        .track_count = halTracks.size(), .tracks = halTracks.data(),
+    };
+    mStream->update_sink_metadata(mStream, &halMetadata);
+    return Void();
 }
 
 Return<void> StreamIn::getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) {
-    _hidl_cb(Result::NOT_SUPPORTED, {});  // TODO: retrieve from legacy
+    Result retval = Result::NOT_SUPPORTED;
+    size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT;
+    audio_microphone_characteristic_t mic_array[AUDIO_MICROPHONE_MAX_COUNT];
+
+    hidl_vec<MicrophoneInfo> microphones;
+    if (mStream->get_active_microphones != NULL &&
+        mStream->get_active_microphones(mStream, &mic_array[0], &actual_mics) == 0) {
+        microphones.resize(actual_mics);
+        for (size_t i = 0; i < actual_mics; ++i) {
+            halToMicrophoneCharacteristics(&microphones[i], mic_array[i]);
+        }
+        retval = Result::OK;
+    }
+
+    _hidl_cb(retval, microphones);
     return Void();
 }
 #endif
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.impl.h
index 605b824..77098a8 100644
--- a/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.impl.h
+++ b/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.impl.h
@@ -547,8 +547,24 @@
 }
 
 #ifdef AUDIO_HAL_VERSION_4_0
-Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& /*sourceMetadata*/) {
-    return Void();  // TODO: propagate to legacy
+Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
+    if (mStream->update_source_metadata == nullptr) {
+        return Void();  // not supported by the HAL
+    }
+    std::vector<playback_track_metadata> halTracks;
+    halTracks.reserve(sourceMetadata.tracks.size());
+    for (auto& metadata : sourceMetadata.tracks) {
+        halTracks.push_back({
+            .usage = static_cast<audio_usage_t>(metadata.usage),
+            .content_type = static_cast<audio_content_type_t>(metadata.contentType),
+            .gain = metadata.gain,
+        });
+    }
+    const source_metadata_t halMetadata = {
+        .track_count = halTracks.size(), .tracks = halTracks.data(),
+    };
+    mStream->update_source_metadata(mStream, &halMetadata);
+    return Void();
 }
 Return<Result> StreamOut::selectPresentation(int32_t /*presentationId*/, int32_t /*programId*/) {
     return Result::NOT_SUPPORTED;  // TODO: propagate to legacy
diff --git a/audio/effect/4.0/xml/audio_effects_conf_V4_0.xsd b/audio/effect/4.0/xml/audio_effects_conf_V4_0.xsd
new file mode 120000
index 0000000..82d569a
--- /dev/null
+++ b/audio/effect/4.0/xml/audio_effects_conf_V4_0.xsd
@@ -0,0 +1 @@
+../../2.0/xml/audio_effects_conf_V2_0.xsd
\ No newline at end of file
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp
index 902a4e8..3e32b3e 100644
--- a/automotive/vehicle/2.0/Android.bp
+++ b/automotive/vehicle/2.0/Android.bp
@@ -43,7 +43,6 @@
         "VehicleAreaWindow",
         "VehicleAreaZone",
         "VehicleDisplay",
-        "VehicleDrivingStatus",
         "VehicleGear",
         "VehicleHvacFanDirection",
         "VehicleHwKeyInputAction",
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h
index eda94b7..0a243fe 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h
@@ -67,7 +67,7 @@
 
     /* Stores provided value. Returns true if value was written returns false if config for
      * example wasn't registered. */
-    bool writeValue(const VehiclePropValue& propValue);
+    bool writeValue(const VehiclePropValue& propValue, bool updateStatus);
 
     void removeValue(const VehiclePropValue& propValue);
     void removeValuesForProperty(int32_t propId);
diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
index f2aa421..94ace45 100644
--- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -41,7 +41,8 @@
     mConfigs.insert({ config.prop, RecordConfig { config, tokenFunc } });
 }
 
-bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue) {
+bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue,
+                                        bool updateStatus) {
     MuxGuard g(mLock);
     if (!mConfigs.count(propValue.prop)) return false;
 
@@ -52,7 +53,9 @@
     } else {
         valueToUpdate->timestamp = propValue.timestamp;
         valueToUpdate->value = propValue.value;
-        valueToUpdate->status = propValue.status;
+        if (updateStatus) {
+            valueToUpdate->status = propValue.status;
+        }
     }
     return true;
 }
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index e54de00..479f8af 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -46,18 +46,35 @@
  *
  * It has the following format:
  *
- * int32Values[0] - command (1 - start fake data generation, 0 - stop)
+ * int32Values[0] - command (see FakeDataCommand below for possible values)
  * int32Values[1] - VehicleProperty to which command applies
- *
- * For start command, additional data should be provided:
- *   int64Values[0] - periodic interval in nanoseconds
- *   floatValues[0] - initial value
- *   floatValues[1] - dispersion defines min and max range relative to initial value
- *   floatValues[2] - increment, with every timer tick the value will be incremented by this amount
  */
 const int32_t kGenerateFakeDataControllingProperty =
     0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
 
+enum class FakeDataCommand : int32_t {
+    /** Stops generating of fake data that was triggered by Start command */
+    Stop = 0,
+
+    /**
+     * Starts fake data generation.  Caller must provide additional data:
+     *     int64Values[0] - periodic interval in nanoseconds
+     *     floatValues[0] - initial value
+     *     floatValues[1] - dispersion defines min and max range relative to initial value
+     *     floatValues[2] - increment, with every timer tick the value will be incremented by this
+     * amount
+     */
+    Start = 1,
+
+    /**
+     * Injects key press event (HAL incorporates UP/DOWN acction and triggers 2 HAL events for every
+     * key-press). Caller must provide the following data: int32Values[2] - Android key code
+     *     int32Values[3] - target display (0 - for main display, 1 - for instrument cluster, see
+     * VehicleDisplay)
+     */
+    KeyPress = 2,
+};
+
 const int32_t kHvacPowerProperties[] = {
     toInt(VehicleProperty::HVAC_FAN_SPEED),
     toInt(VehicleProperty::HVAC_FAN_DIRECTION),
@@ -329,14 +346,6 @@
 
     {.config =
          {
-             .prop = toInt(VehicleProperty::DRIVING_STATUS),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-         },
-     .initialValue = {.int32Values = {toInt(VehicleDrivingStatus::UNRESTRICTED)}}},
-
-    {.config =
-         {
              .prop = toInt(VehicleProperty::GEAR_SELECTION),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index dc34a50..3979ac2 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -85,11 +85,6 @@
     return sensorStore;
 }
 
-enum class FakeDataCommand : int32_t {
-    Stop = 0,
-    Start = 1,
-};
-
 EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
     : mPropStore(propStore),
       mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
@@ -132,6 +127,8 @@
 }
 
 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
+    static constexpr bool shouldUpdateStatus = false;
+
     if (propValue.prop == kGenerateFakeDataControllingProperty) {
         StatusCode status = handleGenerateFakeDataRequest(propValue);
         if (status != StatusCode::OK) {
@@ -182,7 +179,7 @@
         return StatusCode::NOT_AVAILABLE;
     }
 
-    if (!mPropStore->writeValue(propValue)) {
+    if (!mPropStore->writeValue(propValue, shouldUpdateStatus)) {
         return StatusCode::INVALID_ARG;
     }
 
@@ -204,6 +201,8 @@
 
 // Parse supported properties list and generate vector of property values to hold current values.
 void EmulatedVehicleHal::onCreate() {
+    static constexpr bool shouldUpdateStatus = true;
+
     for (auto& it : kVehicleProperties) {
         VehiclePropConfig cfg = it.config;
         int32_t numAreas = cfg.areaConfigs.size();
@@ -245,7 +244,7 @@
             } else {
                 prop.value = it.initialValue;
             }
-            mPropStore->writeValue(prop);
+            mPropStore->writeValue(prop, shouldUpdateStatus);
         }
     }
     initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
@@ -305,6 +304,8 @@
 }
 
 bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
+    static constexpr bool shouldUpdateStatus = true;
+
     if (propValue.prop == kGenerateFakeDataControllingProperty) {
         StatusCode status = handleGenerateFakeDataRequest(propValue);
         if (status != StatusCode::OK) {
@@ -312,7 +313,7 @@
         }
     }
 
-    if (mPropStore->writeValue(propValue)) {
+    if (mPropStore->writeValue(propValue, shouldUpdateStatus)) {
         doHalEvent(getValuePool()->obtain(propValue));
         return true;
     } else {
@@ -360,10 +361,20 @@
             break;
         }
         case FakeDataCommand::Stop: {
-            ALOGI("%s, FakeDataCommandStop", __func__);
+            ALOGI("%s, FakeDataCommand::Stop", __func__);
             mFakeValueGenerator.stopGeneratingHalEvents(propId);
             break;
         }
+        case FakeDataCommand::KeyPress: {
+            ALOGI("%s, FakeDataCommand::KeyPress", __func__);
+            int32_t keyCode = request.value.int32Values[2];
+            int32_t display = request.value.int32Values[3];
+            doHalEvent(
+                createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
+            doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
+            break;
+        }
+
         default: {
             ALOGE("%s: unexpected command: %d", __func__, command);
             return StatusCode::INVALID_ARG;
@@ -372,7 +383,22 @@
     return StatusCode::OK;
 }
 
+VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp(
+    VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
+    auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
+    keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
+    keyEvent->areaId = 0;
+    keyEvent->timestamp = elapsedRealtimeNano();
+    keyEvent->status = VehiclePropertyStatus::AVAILABLE;
+    keyEvent->value.int32Values[0] = toInt(action);
+    keyEvent->value.int32Values[1] = keyCode;
+    keyEvent->value.int32Values[2] = targetDisplay;
+    return keyEvent;
+}
+
 void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) {
+    static constexpr bool shouldUpdateStatus = false;
+
     VehiclePropValuePtr updatedPropValue {};
     switch (getPropType(propId)) {
         case VehiclePropertyType::FLOAT:
@@ -392,7 +418,7 @@
         updatedPropValue->areaId = 0;  // Add area support if necessary.
         updatedPropValue->timestamp = elapsedRealtimeNano();
         updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
-        mPropStore->writeValue(*updatedPropValue);
+        mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
         auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode;
         if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
             doHalEvent(move(updatedPropValue));
@@ -421,16 +447,20 @@
 }
 
 void EmulatedVehicleHal::initObd2LiveFrame(const VehiclePropConfig& propConfig) {
+    static constexpr bool shouldUpdateStatus = true;
+
     auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
     auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
                                             static_cast<size_t>(propConfig.configArray[1]));
     sensorStore->fillPropValue("", liveObd2Frame.get());
     liveObd2Frame->prop = OBD2_LIVE_FRAME;
 
-    mPropStore->writeValue(*liveObd2Frame);
+    mPropStore->writeValue(*liveObd2Frame, shouldUpdateStatus);
 }
 
 void EmulatedVehicleHal::initObd2FreezeFrame(const VehiclePropConfig& propConfig) {
+    static constexpr bool shouldUpdateStatus = true;
+
     auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
                                             static_cast<size_t>(propConfig.configArray[1]));
 
@@ -442,7 +472,7 @@
         sensorStore->fillPropValue(dtc, freezeFrame.get());
         freezeFrame->prop = OBD2_FREEZE_FRAME;
 
-        mPropStore->writeValue(*freezeFrame);
+        mPropStore->writeValue(*freezeFrame, shouldUpdateStatus);
     }
 }
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index 62fc126..d291dba 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -67,6 +67,8 @@
 
     StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
     void onFakeValueGenerated(int32_t propId, float value);
+    VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
+                                             int32_t targetDisplay);
 
     void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
     bool isContinuousProperty(int32_t propId) const;
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 87daedc..93a903f 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -467,19 +467,6 @@
         | VehicleArea:GLOBAL),
 
     /**
-     * Driving status policy.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ
-     * @data_enum VehicleDrivingStatus
-     */
-    DRIVING_STATUS = (
-        0x0404
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32
-        | VehicleArea:GLOBAL),
-
-    /**
      * Warning for fuel low level.
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
@@ -2169,20 +2156,6 @@
 };
 
 /**
- * Car states.
- *
- * The driving states determine what features of the UI will be accessible.
- */
-enum VehicleDrivingStatus : int32_t {
-    UNRESTRICTED = 0x00,
-    NO_VIDEO = 0x01,
-    NO_KEYBOARD_INPUT = 0x02,
-    NO_VOICE_INPUT = 0x04,
-    NO_CONFIG = 0x08,
-    LIMIT_MESSAGE_LEN = 0x10,
-};
-
-/**
  * Various gears which can be selected by user and chosen in system.
  */
 enum VehicleGear: int32_t {
diff --git a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
index e1f5faa..a634441 100644
--- a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
+++ b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
@@ -1,5 +1,6 @@
 service vendor.bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service
     class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
     user bluetooth
     group bluetooth
     writepid /dev/stune/foreground/tasks
diff --git a/broadcastradio/1.1/default/Tuner.cpp b/broadcastradio/1.1/default/Tuner.cpp
index ae01879..4b49b59 100644
--- a/broadcastradio/1.1/default/Tuner.cpp
+++ b/broadcastradio/1.1/default/Tuner.cpp
@@ -86,6 +86,7 @@
 
     mIsAmfmConfigSet = true;
     mCallback->configChange(Result::OK, mAmfmConfig);
+    if (mCallback1_1 != nullptr) mCallback1_1->programListChanged();
 }
 
 bool Tuner::autoConfigureLocked(uint64_t frequency) {
diff --git a/broadcastradio/2.0/ITunerCallback.hal b/broadcastradio/2.0/ITunerCallback.hal
index ede8350..b20a0b2 100644
--- a/broadcastradio/2.0/ITunerCallback.hal
+++ b/broadcastradio/2.0/ITunerCallback.hal
@@ -17,12 +17,14 @@
 
 interface ITunerCallback {
     /**
-     * Method called by the HAL when a tuning operation fails
+     * Method called by the HAL when a tuning operation fails asynchronously
      * following a step(), scan() or tune() command.
      *
-     * @param result OK if tune succeeded;
-     *               TIMEOUT in case of time out.
-     * @param selector A ProgramSelector structure passed from tune(),
+     * This callback is only called when the step(), scan() or tune() command
+     * returned OK at first.
+     *
+     * @param result TIMEOUT in case of time out.
+     * @param selector A ProgramSelector structure passed from tune() call;
      *                 empty for step() and scan().
      */
     oneway onTuneFailed(Result result, ProgramSelector selector);
diff --git a/broadcastradio/2.0/types.hal b/broadcastradio/2.0/types.hal
index a9b9600..1ce61df 100644
--- a/broadcastradio/2.0/types.hal
+++ b/broadcastradio/2.0/types.hal
@@ -351,10 +351,16 @@
      * related content (i.e. DAB soft-links). This field is a list of pointers
      * to other programs on the program list.
      *
-     * Please note, that these identifiers does not have to exist on the program
+     * This is not a list of programs that carry the same content (i.e.
+     * DAB hard-links, RDS AF). Switching to programs from this list usually
+     * require user action.
+     *
+     * Please note, that these identifiers do not have to exist on the program
      * list - i.e. DAB tuner may provide information on FM RDS alternatives
      * despite not supporting FM RDS. If the system has multiple tuners, another
      * one may have it on its list.
+     *
+     * This field is optional (can be empty).
      */
     vec<ProgramIdentifier> relatedContent;
 
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
index ad7f6f5..550d65a 100644
--- a/camera/device/3.4/default/CameraDeviceSession.cpp
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -51,6 +51,32 @@
             }
         }
     }
+
+    camera_metadata_entry_t capabilities =
+            mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    bool isLogicalMultiCamera = false;
+    for (size_t i = 0; i < capabilities.count; i++) {
+        if (capabilities.data.u8[i] ==
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+            isLogicalMultiCamera = true;
+            break;
+        }
+    }
+    if (isLogicalMultiCamera) {
+        camera_metadata_entry entry =
+                mDeviceInfo.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
+        const uint8_t* ids = entry.data.u8;
+        size_t start = 0;
+        for (size_t i = 0; i < entry.count; ++i) {
+            if (ids[i] == '\0') {
+                if (start != i) {
+                    const char* physicalId = reinterpret_cast<const char*>(ids+start);
+                    mPhysicalCameraIds.emplace(physicalId);
+                }
+                start = i + 1;
+            }
+        }
+    }
 }
 
 CameraDeviceSession::~CameraDeviceSession() {
@@ -456,9 +482,19 @@
         return;
     }
 
+    if (hal_result->num_physcam_metadata > d->mPhysicalCameraIds.size()) {
+        ALOGE("%s: Fatal: Invalid num_physcam_metadata %u", __FUNCTION__,
+                hal_result->num_physcam_metadata);
+        return;
+    }
     result.physicalCameraMetadata.resize(hal_result->num_physcam_metadata);
     for (uint32_t i = 0; i < hal_result->num_physcam_metadata; i++) {
         std::string physicalId = hal_result->physcam_ids[i];
+        if (d->mPhysicalCameraIds.find(physicalId) == d->mPhysicalCameraIds.end()) {
+            ALOGE("%s: Fatal: Invalid physcam_ids[%u]: %s", __FUNCTION__,
+                  i, hal_result->physcam_ids[i]);
+            return;
+        }
         V3_2::CameraMetadata physicalMetadata;
         V3_2::implementation::convertToHidl(hal_result->physcam_metadata[i], &physicalMetadata);
         PhysicalCameraMetadata physicalCameraMetadata = {
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
index 6e90ed4..5d6a112 100644
--- a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
@@ -27,6 +27,7 @@
 #include <hidl/Status.h>
 #include <deque>
 #include <map>
+#include <unordered_set>
 #include <unordered_map>
 #include "CameraMetadata.h"
 #include "HandleImporter.h"
@@ -110,6 +111,10 @@
 
     // Whether this camera device session is created with version 3.4 callback.
     bool mHasCallback_3_4;
+
+    // Physical camera ids for the logical multi-camera. Empty if this
+    // is not a logical multi-camera.
+    std::unordered_set<std::string> mPhysicalCameraIds;
 private:
 
     struct TrampolineSessionInterface_3_4 : public ICameraDeviceSession {
diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal
index 4f3f678..04edfe9 100644
--- a/camera/metadata/3.3/types.hal
+++ b/camera/metadata/3.3/types.hal
@@ -33,6 +33,8 @@
     ANDROID_LOGICAL_MULTI_CAMERA =
         android.hardware.camera.metadata@3.2::CameraMetadataSection:ANDROID_SECTION_COUNT,
 
+    ANDROID_DISTORTION_CORRECTION,
+
     ANDROID_SECTION_COUNT_3_3,
 
     VENDOR_SECTION_3_3 = 0x8000,
@@ -46,6 +48,8 @@
 enum CameraMetadataSectionStart : android.hardware.camera.metadata@3.2::CameraMetadataSectionStart {
     ANDROID_LOGICAL_MULTI_CAMERA_START = CameraMetadataSection:ANDROID_LOGICAL_MULTI_CAMERA << 16,
 
+    ANDROID_DISTORTION_CORRECTION_START = CameraMetadataSection:ANDROID_DISTORTION_CORRECTION << 16,
+
     VENDOR_SECTION_START_3_3 = CameraMetadataSection:VENDOR_SECTION_3_3 << 16,
 
 };
@@ -164,6 +168,23 @@
 
     ANDROID_LOGICAL_MULTI_CAMERA_END_3_3,
 
+    /** android.distortionCorrection.mode [dynamic, enum, public]
+     *
+     * <p>Mode of operation for the lens distortion correction block.</p>
+     */
+    ANDROID_DISTORTION_CORRECTION_MODE = CameraMetadataSectionStart:ANDROID_DISTORTION_CORRECTION_START,
+
+    /** android.distortionCorrection.availableModes [static, byte[], public]
+     *
+     * <p>List of distortion correction modes for ANDROID_DISTORTION_CORRECTION_MODE that are
+     * supported by this camera device.</p>
+     *
+     * @see ANDROID_DISTORTION_CORRECTION_MODE
+     */
+    ANDROID_DISTORTION_CORRECTION_AVAILABLE_MODES,
+
+    ANDROID_DISTORTION_CORRECTION_END_3_3,
+
 };
 
 /*
@@ -209,6 +230,7 @@
         @3.2::CameraMetadataEnumAndroidRequestAvailableCapabilities {
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING,
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA,
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME,
 };
 
 /** android.statistics.oisDataMode enumeration values
@@ -234,3 +256,12 @@
     ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE,
     ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED,
 };
+
+/** android.distortionCorrection.mode enumeration values
+ * @see ANDROID_DISTORTION_CORRECTION_MODE
+ */
+enum CameraMetadataEnumAndroidDistortionCorrectionMode : uint32_t {
+    ANDROID_DISTORTION_CORRECTION_MODE_OFF,
+    ANDROID_DISTORTION_CORRECTION_MODE_FAST,
+    ANDROID_DISTORTION_CORRECTION_MODE_HIGH_QUALITY,
+};
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index 71253da..23be7de 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -21,6 +21,8 @@
 # Clear potential input variables to BUILD_FRAMEWORK_COMPATIBILITY_MATRIX
 LOCAL_ADD_VBMETA_VERSION :=
 LOCAL_ASSEMBLE_VINTF_ENV_VARS :=
+LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE :=
+LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE :=
 LOCAL_ASSEMBLE_VINTF_FLAGS :=
 LOCAL_KERNEL_VERSIONS :=
 LOCAL_GEN_FILE_DEPENDENCIES :=
@@ -29,18 +31,21 @@
 
 
 include $(CLEAR_VARS)
+LOCAL_MODULE := framework_compatibility_matrix.legacy.xml
 LOCAL_MODULE_STEM := compatibility_matrix.legacy.xml
 LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
 LOCAL_KERNEL_VERSIONS := 3.18.0 4.4.0 4.9.0
 include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
 
 include $(CLEAR_VARS)
+LOCAL_MODULE := framework_compatibility_matrix.1.xml
 LOCAL_MODULE_STEM := compatibility_matrix.1.xml
 LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
 LOCAL_KERNEL_VERSIONS := 3.18.0 4.4.0 4.9.0
 include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
 
 include $(CLEAR_VARS)
+LOCAL_MODULE := framework_compatibility_matrix.2.xml
 LOCAL_MODULE_STEM := compatibility_matrix.2.xml
 LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
 LOCAL_KERNEL_VERSIONS := 3.18.0 4.4.0 4.9.0
@@ -49,6 +54,7 @@
 # TODO(b/72409164): STOPSHIP: update kernel version requirements
 
 include $(CLEAR_VARS)
+LOCAL_MODULE := framework_compatibility_matrix.current.xml
 LOCAL_MODULE_STEM := compatibility_matrix.current.xml
 LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
 LOCAL_KERNEL_VERSIONS := 4.4.0 4.9.0
@@ -57,14 +63,47 @@
 # Framework Compatibility Matrix (common to all FCM versions)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE_STEM := compatibility_matrix.empty.xml
-LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
+LOCAL_MODULE := framework_compatibility_matrix.device.xml
+LOCAL_MODULE_STEM := compatibility_matrix.device.xml
+# define LOCAL_MODULE_CLASS for local-generated-sources-dir.
+LOCAL_MODULE_CLASS := ETC
+
+ifndef DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE
+LOCAL_SRC_FILES := compatibility_matrix.empty.xml
+else
+
+# DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE specify an absolute path
+LOCAL_GENERATED_SOURCES := $(DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE)
+
+# Enforce that DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE does not specify required HALs
+# by checking it against an empty manifest. But the empty manifest needs to contain
+# BOARD_SEPOLICY_VERS to be compatible with DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE.
+my_manifest_src_file := $(LOCAL_PATH)/manifest.empty.xml
+my_gen_check_manifest := $(local-generated-sources-dir)/manifest.check.xml
+$(my_gen_check_manifest): PRIVATE_SRC_FILE := $(my_manifest_src_file)
+$(my_gen_check_manifest): $(my_manifest_src_file) $(HOST_OUT_EXECUTABLES)/assemble_vintf
+	BOARD_SEPOLICY_VERS=$(BOARD_SEPOLICY_VERS) \
+	VINTF_IGNORE_TARGET_FCM_VERSION=true \
+		$(HOST_OUT_EXECUTABLES)/assemble_vintf -i $(PRIVATE_SRC_FILE) -o $@
+
+LOCAL_GEN_FILE_DEPENDENCIES += $(my_gen_check_manifest)
+LOCAL_ASSEMBLE_VINTF_FLAGS += -c "$(my_gen_check_manifest)"
+
+my_gen_check_manifest :=
+my_manifest_src_file :=
+
+endif # DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE
+
 LOCAL_ADD_VBMETA_VERSION := true
 LOCAL_ASSEMBLE_VINTF_ENV_VARS := \
     POLICYVERS \
     PLATFORM_SEPOLICY_VERSION \
     PLATFORM_SEPOLICY_COMPAT_VERSIONS
 
+LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE := PRODUCT_ENFORCE_VINTF_MANIFEST=true
+LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE := \
+    "Error: DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX cannot contain required HALs."
+
 include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
 
 # Framework Compatibility Matrix
@@ -78,7 +117,7 @@
     framework_compatibility_matrix.1.xml \
     framework_compatibility_matrix.2.xml \
     framework_compatibility_matrix.current.xml \
-    framework_compatibility_matrix.empty.xml
+    framework_compatibility_matrix.device.xml
 LOCAL_GENERATED_SOURCES := $(call module-installed-files,$(LOCAL_REQUIRED_MODULES))
 
 ifdef BUILT_VENDOR_MANIFEST
@@ -88,6 +127,14 @@
 
 LOCAL_ASSEMBLE_VINTF_ENV_VARS := PRODUCT_ENFORCE_VINTF_MANIFEST
 
+# TODO(b/65028233): Enforce no "unused HALs" for devices that does not define
+# DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE as well
+ifeq (true,$(strip $(PRODUCT_ENFORCE_VINTF_MANIFEST)))
+ifdef DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE
+LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE := VINTF_ENFORCE_NO_UNUSED_HALS=true
+endif
+endif
+
 include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
 BUILT_SYSTEM_COMPATIBILITY_MATRIX := $(LOCAL_BUILT_MODULE)
 
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 370ffdd..f2a93f2 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -56,6 +56,14 @@
         </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.boot</name>
         <version>1.0</version>
         <interface>
@@ -76,7 +84,7 @@
         <version>2.4</version>
         <interface>
             <name>ICameraProvider</name>
-            <instance>legacy/0</instance>
+            <regex-instance>[^/]+/[0-9]+</regex-instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
@@ -103,16 +111,28 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <hal format="hidl" optional="true">
         <name>android.hardware.drm</name>
         <version>1.0</version>
         <interface>
             <name>ICryptoFactory</name>
-            <instance>default</instance>
+            <regex-instance>.*</regex-instance>
         </interface>
         <interface>
             <name>IDrmFactory</name>
-            <instance>default</instance>
+            <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">
@@ -133,7 +153,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.gnss</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IGnss</name>
             <instance>default</instance>
@@ -225,13 +245,12 @@
         <version>1.0</version>
         <interface>
             <name>IDevice</name>
-            <!-- TODO(b/73738616): This should be * (match any) -->
-            <instance>hvx</instance>
+            <regex-instance>.*</regex-instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.nfc</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>INfc</name>
             <instance>default</instance>
@@ -255,10 +274,12 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.radio</name>
-        <version>1.0-1</version>
+        <version>1.0-2</version>
         <interface>
             <name>IRadio</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
         </interface>
         <interface>
             <name>ISap</name>
@@ -266,6 +287,14 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.radio.config</name>
+        <version>1.0</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>
@@ -278,7 +307,8 @@
         <version>1.0</version>
         <interface>
             <name>ISecureElement</name>
-            <instance>eSE1</instance>
+            <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">
diff --git a/compatibility_matrices/compatibility_matrix.mk b/compatibility_matrices/compatibility_matrix.mk
index 96815b8..6dc2b4f 100644
--- a/compatibility_matrices/compatibility_matrix.mk
+++ b/compatibility_matrices/compatibility_matrix.mk
@@ -25,12 +25,38 @@
 
 # $(warning $(call remove-minor-revision,3.18.0))
 
-ifndef LOCAL_MODULE_STEM
-$(error LOCAL_MODULE_STEM must be defined.)
+##### Input Variables:
+# LOCAL_MODULE: required. Module name for the build system.
+# LOCAL_MODULE_CLASS: optional. Default is ETC.
+# LOCAL_MODULE_PATH: optional. Path of output file. Default is $(TARGET_OUT)/etc/vintf.
+# LOCAL_MODULE_STEM: optional. Name of output file. Default is $(LOCAL_MODULE).
+# LOCAL_SRC_FILES: required. Local source files provided to assemble_vintf
+#       (command line argument -i).
+# LOCAL_GENERATED_SOURCES: optional. Global source files provided to assemble_vintf
+#       (command line argument -i).
+#
+# LOCAL_ADD_VBMETA_VERSION: Use AVBTOOL to add avb version to the output matrix
+#       (corresponds to <avb><vbmeta-version> tag)
+# LOCAL_ASSEMBLE_VINTF_ENV_VARS: Add a list of environment variable names from global variables in
+#       the build system that is lazily evaluated (e.g. PRODUCT_ENFORCE_VINTF_MANIFEST).
+# LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE: Add a list of environment variables that is local to
+#       assemble_vintf invocation. Format is "VINTF_ENFORCE_NO_UNUSED_HALS=true".
+# LOCAL_ASSEMBLE_VINTF_FLAGS: Add additional command line arguments to assemble_vintf invocation.
+# LOCAL_KERNEL_VERSIONS: Parse kernel configurations and add to the output matrix
+#       (corresponds to <kernel> tags.)
+# LOCAL_GEN_FILE_DEPENDENCIES: A list of additional dependencies for the generated file.
+
+ifndef LOCAL_MODULE
+$(error LOCAL_MODULE must be defined.)
 endif
 
-LOCAL_MODULE := framework_$(LOCAL_MODULE_STEM)
+ifndef LOCAL_MODULE_STEM
+LOCAL_MODULE_STEM := $(LOCAL_MODULE)
+endif
+
+ifndef LOCAL_MODULE_CLASS
 LOCAL_MODULE_CLASS := ETC
+endif
 
 ifndef LOCAL_MODULE_PATH
 LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
@@ -76,13 +102,23 @@
 	$(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES)) \
 	$(LOCAL_GENERATED_SOURCES)
 
+$(GEN): PRIVATE_ADDITIONAL_ENV_VARS := $(LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE)
+
+ifneq (,$(strip $(LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE)))
+$(GEN): PRIVATE_COMMAND_TAIL := || (echo $(strip $(LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE)) && false)
+endif
+
 $(GEN): PRIVATE_SRC_FILES := $(my_matrix_src_files)
 $(GEN): $(my_matrix_src_files) $(HOST_OUT_EXECUTABLES)/assemble_vintf
+	$(foreach varname,$(PRIVATE_ENV_VARS),\
+		$(if $(findstring $(varname),$(PRIVATE_ADDITIONAL_ENV_VARS)),\
+			$(error $(varname) should not be overridden by LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE.)))
 	$(foreach varname,$(PRIVATE_ENV_VARS),$(varname)="$($(varname))") \
+		$(PRIVATE_ADDITIONAL_ENV_VARS) \
 		$(HOST_OUT_EXECUTABLES)/assemble_vintf \
 		-i $(call normalize-path-list,$(PRIVATE_SRC_FILES)) \
 		-o $@ \
-		$(PRIVATE_FLAGS)
+		$(PRIVATE_FLAGS) $(PRIVATE_COMMAND_TAIL)
 
 LOCAL_PREBUILT_MODULE_FILE := $(GEN)
 LOCAL_SRC_FILES :=
@@ -90,6 +126,8 @@
 
 LOCAL_ADD_VBMETA_VERSION :=
 LOCAL_ASSEMBLE_VINTF_ENV_VARS :=
+LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE :=
+LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE :=
 LOCAL_ASSEMBLE_VINTF_FLAGS :=
 LOCAL_KERNEL_VERSIONS :=
 LOCAL_GEN_FILE_DEPENDENCIES :=
diff --git a/compatibility_matrices/manifest.empty.xml b/compatibility_matrices/manifest.empty.xml
new file mode 100644
index 0000000..e50e0e5
--- /dev/null
+++ b/compatibility_matrices/manifest.empty.xml
@@ -0,0 +1 @@
+<manifest version="1.0" type="device" />
diff --git a/current.txt b/current.txt
index 9b0828b..cfe0d22 100644
--- a/current.txt
+++ b/current.txt
@@ -250,12 +250,15 @@
 c8bc853546dd55584611def2a9fa1d99f657e3366c976d2f60fe6b8aa6d2cb87 android.hardware.thermal@1.1::IThermalCallback
 
 # ABI preserving changes to HALs during Android P
+eaeb3e4f3237430a7fdc206bffdf844713f5682990b2d49ea24392e15b5d343f android.hardware.broadcastradio@2.0::ITunerCallback
+2804120c1f8522ad15feb7695fe5eece527d399b406c671ea99618194118c316 android.hardware.broadcastradio@2.0::types
 cf72ff5a52bfa4d08e9e1000cf3ab5952a2d280c7f13cdad5ab7905c08050766 android.hardware.camera.metadata@3.2::types
 3902efc42097cba55f0655aa389e052ea70164e99ced1a6d1ef53dafc13f7650 android.hardware.camera.provider@2.4::ICameraProvider
 6fa9804a17a8bb7923a56bd10493a5483c20007e4c9026fd04287bee7c945a8c android.hardware.gnss@1.0::IGnssCallback
 fb92e2b40f8e9d494e8fd3b4ac18499a3216342e7cff160714c3bbf3660b6e79 android.hardware.gnss@1.0::IGnssConfiguration
 251594ea9b27447bfa005ebd806e58fb0ae4aad84a69938129c9800ec0c64eda android.hardware.gnss@1.0::IGnssMeasurementCallback
 4e7169919d24fbe5573e5bcd683d0bd7abf553a4e6c34c41f9dfc1e12050db07 android.hardware.gnss@1.0::IGnssNavigationMessageCallback
+08ae9fc24f21f809e9b8501dfbc803662fcd6a8d8e1fb71d9dd7c0c4c6f5d556 android.hardware.neuralnetworks@1.0::types
 d4840db8efabdf1e4b344fc981cd36e5fe81a39aff6e199f6d06c1c8da413efd android.hardware.radio@1.0::types
 b280c4704dfcc548a9bf127b59b7c3578f460c50cce70a06b66fe0df8b27cff0 android.hardware.wifi@1.0::types
 
@@ -294,7 +297,7 @@
 3b17c1fdfc389e0abe626c37054954b07201127d890c2bc05d47613ec1f4de4f android.hardware.automotive.evs@1.0::types
 b3caf524c46a47d67e6453a34419e1881942d059e146cda740502670e9a752c3 android.hardware.automotive.vehicle@2.0::IVehicle
 80fb4156fa91ce86e49bd2cabe215078f6b69591d416a09e914532eae6712052 android.hardware.automotive.vehicle@2.0::IVehicleCallback
-4ff0dcfb938a5df283eef47de33b4e1284fab73f584cfc0c94e97317bdb7bf26 android.hardware.automotive.vehicle@2.0::types
+a7ac51f419107020b9544efb25e030485e5dc4914c5138c2b8d83a1f52a76825 android.hardware.automotive.vehicle@2.0::types
 32cc50cc2a7658ec613c0c2dd2accbf6a05113b749852879e818b8b7b438db19 android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioHost
 ff4be64d7992f8bec97dff37f35450e79b3430c61f85f54322ce45bef229dc3b android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioOffload
 27f22d2e873e6201f9620cf4d8e2facb25bd0dd30a2b911e441b4600d560fa62 android.hardware.bluetooth.a2dp@1.0::types
@@ -307,7 +310,7 @@
 4fb0725c36ed4f77a42b42e3f18d8b5f7919cb62b90098b23143a555aa7dd96d android.hardware.camera.device@3.4::ICameraDeviceCallback
 812fa66aa10ba0cba27cfddc2fd7f0ee27a8ab65a1f15aa79fdad97d403e6a14 android.hardware.camera.device@3.4::ICameraDeviceSession
 cc288f1f78d1e643eb3d3dbc16e1401d44033d8e6856761f5156814a29986ec7 android.hardware.camera.device@3.4::types
-26462f5a29bef30485f9264115e79e5f5eb6234951dfeb47424709a1b8936030 android.hardware.camera.metadata@3.3::types
+f9278c8beb9d42d96e26d73ecabe1dff1d7e2fb301ab7f737d93e5ffae8d3312 android.hardware.camera.metadata@3.3::types
 1a46aeae45b7a0e47f79b7207300532986f9d9cd7060779afc7a529f54d712ab android.hardware.confirmationui@1.0::IConfirmationResultCallback
 6d8347ff3cd7de471065ac3e8e68385073630cdeebe9f8fa58cb91cf44436c95 android.hardware.confirmationui@1.0::IConfirmationUI
 a3ff916784dce87a56c757ab5c86433f0cdf562280999a5f978a6e8a0f3f19e7 android.hardware.confirmationui@1.0::types
@@ -320,15 +323,15 @@
 3c5183d7506010be57e0f748e3640fc2ded1ba955784b6256ba427f4c399591c android.hardware.gnss@1.1::IGnssConfiguration
 1a07d1383e847c3deb696ec7a2c9e33b9683772945660448a010b18063da67a4 android.hardware.gnss@1.1::IGnssMeasurement
 83e7a10ff3702147bd7ffa04567b20d407a3b16bbb7705644af44d919afe9103 android.hardware.gnss@1.1::IGnssMeasurementCallback
-82da7e7624f72ff1927f48738913e20bee3a513adfe5dc7c4f888176e20376e6 android.hardware.graphics.common@1.1::types
+0b96e0254e2168cfecb30c1ed5fb42681652cc00faa68c6e07568fafe64d1d50 android.hardware.graphics.common@1.1::types
 d9b40a5b09962a5a0780b10fe33a4e607e69e2e088fc83de88a584115b7cb1c0 android.hardware.graphics.composer@2.2::IComposer
-d6ce042995239712bc1d0970fa9d512c15c0b1ac9bcb048bd8b69f617b45c25e android.hardware.graphics.composer@2.2::IComposerClient
+da3979dd97093cdc4ffc2e2427e848f4ba07ddcd181f31f2cb494ad0d2fa58ad android.hardware.graphics.composer@2.2::IComposerClient
 dd83be076b6b3f10ed62ab34d8c8b95f2415961fb785200eb842e7bfb2b0ee92 android.hardware.graphics.mapper@2.1::IMapper
 675682dd3007805c985eaaec91612abc88f4c25b3431fb84070b7584a1a741fb android.hardware.health@2.0::IHealth
 434c4c32c00b0e54bb05e40c79503208b40f786a318029a2a4f66e34f10f2a76 android.hardware.health@2.0::IHealthInfoCallback
 c9e498f1ade5e26f00d290b4763a9671ec6720f915e7d592844b62e8cb1f9b5c android.hardware.health@2.0::types
 a6cf986593c6ad15fe2ae3a1995d2cae233500bc32c055912a42723bdc076868 android.hardware.keymaster@4.0::IKeymasterDevice
-3ce01f7a38013f15d2ffc9c66a81eb85061ab6585fb1e659fe6da36bdcbfa9cf android.hardware.keymaster@4.0::types
+e15ebdf1e0a326ff5b8a59668d4d8cd3852bd88388eae91de13f5f7e1af50ed1 android.hardware.keymaster@4.0::types
 6d5c646a83538f0f9d8438c259932509f4353410c6c76e56db0d6ca98b69c3bb android.hardware.media.bufferpool@1.0::IAccessor
 b8c7ed58aa8740361e63d0ce9e7c94227572a629f356958840b34809d2393a7c android.hardware.media.bufferpool@1.0::IClientManager
 4a2c0dc82780e6c90731725a103feab8ab6ecf85a64e049b9cbd2b2c61620fe1 android.hardware.media.bufferpool@1.0::IConnection
@@ -342,9 +345,9 @@
 7899b9305587b2d5cd74a3cc87e9090f58bf4ae74256ce3ee36e7ec011822840 android.hardware.power@1.2::types
 ab132c990a62f0aca35871c092c22fb9c85d478e22124ef6a4d0a2302da76a9f android.hardware.radio@1.2::IRadio
 cda752aeabaabc20486a82ac57a3dd107785c006094a349bc5e224e8aa22a17c android.hardware.radio@1.2::IRadioIndication
-c38b7e1f808565a535ff19fd4c1b512b22dfa0b58ec91dce03f72a8f1eaf6957 android.hardware.radio@1.2::IRadioResponse
+da8c6ae991c6a4b284cc6e445332e064e28ee8a09482ed5afff9d159ec6694b7 android.hardware.radio@1.2::IRadioResponse
 b65332996eb39ba63300a1011404141fa59ce5c252bc17afae637be6eeca5f55 android.hardware.radio@1.2::ISap
-508ace7d4023b865b8b77c3ca3c86cc9525ef3803dc9c6b461b7c1f91b0fec00 android.hardware.radio@1.2::types
+a9361522cc97ef66209d39ba324095b2f08344054bb4d3481e803eee0480623a android.hardware.radio@1.2::types
 87385469cf4409f0f33b01508e7a477cf71f2a11e466dd7e3ab5971a1baaa72b android.hardware.radio.config@1.0::IRadioConfig
 228b2ee3c8c276c9f0afad2dc313ca3d6bbd9e482ddf313c7204c60ad9b636ab android.hardware.radio.config@1.0::IRadioConfigIndication
 a2e9b7aa09f79426f765838174e04b6f9a3e6c8b76b923fc1705632207bad44b android.hardware.radio.config@1.0::IRadioConfigResponse
@@ -364,9 +367,11 @@
 167af870fdb87e1cbbaa0fa62ef35e1031caad20dd1ba695983dedb1e9993486 android.hardware.wifi@1.2::IWifiChipEventCallback
 8c7ef32fc78d5ec6e6956de3784cc2c6f42614b5272d2e461f6d60534ba38ec2 android.hardware.wifi@1.2::IWifiNanIface
 1e6074efad9da333803fb7c1acdb719d51c30b2e1e92087b0420341631c30b60 android.hardware.wifi@1.2::IWifiNanIfaceEventCallback
-a9d733eb0d555f2a6cb79a212810e81b56ecba0e31a8ffe0916de086a29e4f88 android.hardware.wifi@1.2::IWifiStaIface
+f5682dbf19f712bef9cc3faa5fe3dc670b6ffbcb62a147a1d86b9d43574cd83f android.hardware.wifi@1.2::IWifiStaIface
 6db2e7d274be2dca9bf3087afd1f774a68c99d2b4dc7eeaf41690e5cebcbef7a android.hardware.wifi@1.2::types
 ee08280de21cb41e3ec26d6ed636c701b7f70516e71fb22f4fe60a13e603f406 android.hardware.wifi.hostapd@1.0::IHostapd
 b2479cd7a417a1cf4f3a22db4e4579e21bac38fdcaf381e2bf10176d05397e01 android.hardware.wifi.hostapd@1.0::types
 e362203b941f18bd4cba29a62adfa02453ed00d6be5b72cdb6c4d7e0bf394a40 android.hardware.wifi.supplicant@1.1::ISupplicant
+21757d0e5dd4b7e4bd981a4a20531bca3c32271ad9777b17b74eb5a1ea508384 android.hardware.wifi.supplicant@1.1::ISupplicantStaIface
+cd4330c3196bda1d642a32abfe23a7d64ebfbda721940643af6867af3b3f0aa9 android.hardware.wifi.supplicant@1.1::ISupplicantStaIfaceCallback
 10ff2fae516346b86121368ce5790d5accdfcb73983246b813f3d488b66db45a android.hardware.wifi.supplicant@1.1::ISupplicantStaNetwork
diff --git a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
index 061f2cd..1246616 100644
--- a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
@@ -43,7 +43,6 @@
 using ::android::hardware::drm::V1_0::ICryptoPlugin;
 using ::android::hardware::drm::V1_0::KeyedVector;
 using ::android::hardware::drm::V1_0::KeyValue;
-using ::android::hardware::drm::V1_0::KeyRequestType;
 using ::android::hardware::drm::V1_0::KeyType;
 using ::android::hardware::drm::V1_0::Mode;
 using ::android::hardware::drm::V1_0::Pattern;
@@ -60,6 +59,8 @@
 using ::android::hardware::drm::V1_1::ICryptoFactory;
 using ::android::hardware::drm::V1_1::IDrmFactory;
 using ::android::hardware::drm::V1_1::IDrmPlugin;
+using ::android::hardware::drm::V1_1::KeyRequestType;
+using ::android::hardware::drm::V1_1::SecureStopRelease;
 using ::android::hardware::drm::V1_1::SecurityLevel;
 using ::android::hardware::drm::V1_1::SecurityLevel;
 
@@ -167,7 +168,6 @@
     SessionId openSession(SecurityLevel level);
     void closeSession(const SessionId& sessionId);
     hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
-    sp<IMemory> getDecryptMemory(size_t size, size_t index);
 
   private:
     sp<IDrmPlugin> createDrmPlugin(sp<IDrmFactory> drmFactory) {
@@ -308,6 +308,125 @@
 }
 
 /**
+ * Helper method to load keys for subsequent decrypt tests.
+ * These tests use predetermined key request/response to
+ * avoid requiring a round trip to a license server.
+ */
+hidl_vec<uint8_t> DrmHalClearkeyTest::loadKeys(
+    const SessionId& sessionId, const KeyType& type = KeyType::STREAMING) {
+    hidl_vec<uint8_t> initData = {
+        // BMFF box header (4 bytes size + 'pssh')
+        0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
+        // full box header (version = 1 flags = 0)
+        0x01, 0x00, 0x00, 0x00,
+        // system id
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c,
+        0x1e, 0x52, 0xe2, 0xfb, 0x4b,
+        // number of key ids
+        0x00, 0x00, 0x00, 0x01,
+        // key id
+        0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87, 0x7e, 0x57, 0xd0,
+        0x0d, 0x1e, 0xd0, 0x0d, 0x1e,
+        // size of data, must be zero
+        0x00, 0x00, 0x00, 0x00};
+
+    hidl_vec<uint8_t> expectedKeyRequest = {
+        0x7b, 0x22, 0x6b, 0x69, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x59, 0x41, 0x59, 0x65,
+        0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2d, 0x56, 0x39, 0x41, 0x4e, 0x48, 0x74,
+        0x41, 0x4e, 0x48, 0x67, 0x22, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a,
+        0x22, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x22, 0x7d};
+
+    hidl_vec<uint8_t> knownKeyResponse = {
+        0x7b, 0x22, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6b, 0x74, 0x79, 0x22,
+        0x3a, 0x22, 0x6f, 0x63, 0x74, 0x22, 0x2c, 0x22, 0x6b, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x59,
+        0x41, 0x59, 0x65, 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2d, 0x56, 0x39, 0x41, 0x4e,
+        0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x22, 0x47, 0x6f,
+        0x6f, 0x67, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x73, 0x65,
+        0x36, 0x34, 0x67, 0x67, 0x67, 0x22, 0x7d, 0x5d, 0x7d, 0x0a};
+
+    hidl_string mimeType = "video/mp4";
+    KeyedVector optionalParameters;
+    auto res = drmPlugin->getKeyRequest_1_1(
+        sessionId, initData, mimeType, type, optionalParameters,
+        [&](Status status, const hidl_vec<uint8_t>& request,
+            KeyRequestType requestType, const hidl_string&) {
+            EXPECT_EQ(Status::OK, status);
+            EXPECT_EQ(KeyRequestType::INITIAL, requestType);
+            EXPECT_EQ(request, expectedKeyRequest);
+        });
+    EXPECT_OK(res);
+
+    hidl_vec<uint8_t> keySetId;
+    res = drmPlugin->provideKeyResponse(
+        sessionId, knownKeyResponse,
+        [&](Status status, const hidl_vec<uint8_t>& myKeySetId) {
+            EXPECT_EQ(Status::OK, status);
+            EXPECT_EQ(0u, myKeySetId.size());
+            keySetId = myKeySetId;
+        });
+    EXPECT_OK(res);
+    return keySetId;
+}
+
+/**
+ * Test openSession negative case: security level higher than supported
+ */
+TEST_F(DrmHalClearkeyTest, OpenSessionBadLevel) {
+    auto res = drmPlugin->openSession_1_1(SecurityLevel::HW_SECURE_ALL,
+            [&](Status status, const SessionId& /* id */) {
+                EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Test getKeyRequest_1_1 via loadKeys
+ */
+TEST_F(DrmHalClearkeyTest, GetKeyRequest) {
+    auto sessionId = openSession();
+    loadKeys(sessionId);
+    closeSession(sessionId);
+}
+
+/**
+ * A get key request should fail if no sessionId is provided
+ */
+TEST_F(DrmHalClearkeyTest, GetKeyRequestNoSession) {
+    SessionId invalidSessionId;
+    hidl_vec<uint8_t> initData;
+    hidl_string mimeType = "video/mp4";
+    KeyedVector optionalParameters;
+    auto res = drmPlugin->getKeyRequest_1_1(
+            invalidSessionId, initData, mimeType, KeyType::STREAMING,
+            optionalParameters,
+            [&](Status status, const hidl_vec<uint8_t>&, KeyRequestType,
+                const hidl_string&) { EXPECT_EQ(Status::BAD_VALUE, status); });
+    EXPECT_OK(res);
+}
+
+/**
+ * The clearkey plugin doesn't support offline key requests.
+ * Test that the plugin returns the expected error code in
+ * this case.
+ */
+TEST_F(DrmHalClearkeyTest, GetKeyRequestOfflineKeyTypeNotSupported) {
+    auto sessionId = openSession();
+    hidl_vec<uint8_t> initData;
+    hidl_string mimeType = "video/mp4";
+    KeyedVector optionalParameters;
+
+    auto res = drmPlugin->getKeyRequest_1_1(
+            sessionId, initData, mimeType, KeyType::OFFLINE, optionalParameters,
+            [&](Status status, const hidl_vec<uint8_t>&, KeyRequestType,
+                const hidl_string&) {
+                // Clearkey plugin doesn't support offline key type
+                EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
+            });
+    EXPECT_OK(res);
+    closeSession(sessionId);
+}
+
+/**
  * Test that the plugin returns valid connected and max HDCP levels
  */
 TEST_F(DrmHalClearkeyTest, GetHdcpLevels) {
@@ -322,6 +441,11 @@
 }
 
 /**
+ * Since getHdcpLevels only queries information there are no
+ * negative cases.
+ */
+
+/**
  * Test that the plugin returns default open and max session counts
  */
 TEST_F(DrmHalClearkeyTest, GetDefaultSessionCounts) {
@@ -373,6 +497,11 @@
 }
 
 /**
+ * Since getNumberOfSessions only queries information there are no
+ * negative cases.
+ */
+
+/**
  * Test that the plugin returns the same security level
  * by default as when it is requested explicitly
  */
@@ -428,7 +557,7 @@
 /**
  * Test metrics are set appropriately for open and close operations.
  */
-TEST_F(DrmHalClearkeyTest, GetMetricsSuccess) {
+TEST_F(DrmHalClearkeyTest, GetMetricsOpenClose) {
     SessionId sessionId = openSession();
     // The first close should be successful.
     closeSession(sessionId);
@@ -449,8 +578,292 @@
                                                     (int64_t)Status::ERROR_DRM_SESSION_NOT_OPENED,
                                                     "count", (int64_t)1));
     });
+    EXPECT_OK(res);
 }
 
+/**
+ * Since getMetrics only queries information there are no
+ * negative cases.
+ */
+
+/**
+ * Test that there are no secure stop ids after clearing them
+ */
+TEST_F(DrmHalClearkeyTest, GetSecureStopIdsCleared) {
+    auto stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    bool ok = drmPlugin->getSecureStopIds(
+            [&](Status status, const hidl_vec<SecureStopId>& ids) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(0u, ids.size());
+            }).isOk();
+    EXPECT_TRUE(ok);
+}
+
+/**
+ * Test that there are secure stop ids after loading keys once
+ */
+TEST_F(DrmHalClearkeyTest, GetSecureStopIdsOnce) {
+    auto stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    auto sessionId = openSession();
+    loadKeys(sessionId);
+    closeSession(sessionId);
+
+    auto res = drmPlugin->getSecureStopIds(
+            [&](Status status, const hidl_vec<SecureStopId>& ids) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(1u, ids.size());
+            });
+    EXPECT_OK(res);
+
+    stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    res = drmPlugin->getSecureStopIds(
+            [&](Status status, const hidl_vec<SecureStopId>& ids) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(0u, ids.size());
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Since getSecureStopIds only queries information there are no
+ * negative cases.
+ */
+
+/**
+ * Test that the clearkey plugin reports no secure stops when
+ * there are none.
+ */
+TEST_F(DrmHalClearkeyTest, GetNoSecureStops) {
+    auto stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    auto res = drmPlugin->getSecureStops(
+            [&](Status status, const hidl_vec<SecureStop>& stops) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(0u, stops.size());
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Test get/remove of one secure stop
+ */
+TEST_F(DrmHalClearkeyTest, GetOneSecureStopAndRemoveIt) {
+    auto stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    auto sessionId = openSession();
+    loadKeys(sessionId);
+    closeSession(sessionId);
+
+    auto res = drmPlugin->getSecureStops(
+            [&](Status status, const hidl_vec<SecureStop>& stops) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(1u, stops.size());
+            });
+    EXPECT_OK(res);
+
+    stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    res = drmPlugin->getSecureStops(
+            [&](Status status, const hidl_vec<SecureStop>& stops) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(0u, stops.size());
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Since getSecureStops only queries information there are no
+ * negative cases.
+ */
+
+/**
+ * Test that there are no secure stops after clearing them
+ */
+TEST_F(DrmHalClearkeyTest, GetSecureStopsCleared) {
+    auto stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    auto res = drmPlugin->getSecureStops(
+            [&](Status status, const hidl_vec<SecureStop>& stops) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(0u, stops.size());
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Test that there are secure stops after loading keys once
+ */
+TEST_F(DrmHalClearkeyTest, GetSecureStopsOnce) {
+    auto stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    auto sessionId = openSession();
+    loadKeys(sessionId);
+    closeSession(sessionId);
+
+    auto res = drmPlugin->getSecureStops(
+            [&](Status status, const hidl_vec<SecureStop>& stops) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(1u, stops.size());
+            });
+    EXPECT_OK(res);
+
+    stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    res = drmPlugin->getSecureStops(
+            [&](Status status, const hidl_vec<SecureStop>& stops) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(0u, stops.size());
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Since getSecureStops only queries information there are no
+ * negative cases.
+ */
+
+/**
+ * Test that releasing a secure stop with empty
+ * release message fails with the documented error
+ */
+TEST_F(DrmHalClearkeyTest, ReleaseEmptySecureStop) {
+    SecureStopRelease emptyRelease = {.opaqueData = hidl_vec<uint8_t>()};
+    Status status = drmPlugin->releaseSecureStops(emptyRelease);
+    EXPECT_EQ(Status::BAD_VALUE, status);
+}
+
+/**
+ * Helper function to create a secure release message for
+ * a secure stop. The clearkey secure stop release format
+ * is just a count followed by the secure stop opaque data.
+ */
+SecureStopRelease makeSecureRelease(const SecureStop &stop) {
+    std::vector<uint8_t> stopData = stop.opaqueData;
+    std::vector<uint8_t> buffer;
+    std::string count = "0001";
+
+    auto it = buffer.insert(buffer.begin(), count.begin(), count.end());
+    buffer.insert(it + count.size(), stopData.begin(), stopData.end());
+    SecureStopRelease release = { .opaqueData = hidl_vec<uint8_t>(buffer) };
+    return release;
+}
+
+/**
+ * Test that releasing one secure stop works
+ */
+TEST_F(DrmHalClearkeyTest, ReleaseOneSecureStop) {
+
+    auto stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    auto sessionId = openSession();
+    loadKeys(sessionId);
+    closeSession(sessionId);
+
+    SecureStopRelease release;
+    auto res = drmPlugin->getSecureStops(
+            [&](Status status, const hidl_vec<SecureStop>& stops) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(1u, stops.size());
+                release = makeSecureRelease(stops[0]);
+            });
+    EXPECT_OK(res);
+
+    stat = drmPlugin->releaseSecureStops(release);
+    EXPECT_OK(stat);
+
+    res = drmPlugin->getSecureStops(
+            [&](Status status, const hidl_vec<SecureStop>& stops) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(0u, stops.size());
+            });
+    EXPECT_OK(res);
+}
+
+
+/**
+ * Test that removing a secure stop with an empty ID returns
+ * documented error
+ */
+TEST_F(DrmHalClearkeyTest, RemoveEmptySecureStopId) {
+    hidl_vec<uint8_t> emptyId;
+    auto stat = drmPlugin->removeSecureStop(emptyId);
+    EXPECT_OK(stat);
+    EXPECT_EQ(Status::BAD_VALUE, stat);
+}
+
+/**
+ * Test that removing a secure stop after it has already
+ * been removed fails with the documented error code.
+ */
+TEST_F(DrmHalClearkeyTest, RemoveRemovedSecureStopId) {
+    auto stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    auto sessionId = openSession();
+    loadKeys(sessionId);
+    closeSession(sessionId);
+    SecureStopId ssid;
+
+    auto res = drmPlugin->getSecureStopIds(
+            [&](Status status, const hidl_vec<SecureStopId>& ids) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(1u, ids.size());
+                ssid = ids[0];
+            });
+    EXPECT_OK(res);
+
+    stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    Status status = drmPlugin->removeSecureStop(ssid);
+    EXPECT_EQ(Status::BAD_VALUE, status);
+}
+
+/**
+ * Test that removing a secure stop by id works
+ */
+TEST_F(DrmHalClearkeyTest, RemoveSecureStopById) {
+    auto stat = drmPlugin->removeAllSecureStops();
+    EXPECT_OK(stat);
+
+    auto sessionId = openSession();
+    loadKeys(sessionId);
+    closeSession(sessionId);
+    SecureStopId ssid;
+
+    auto res = drmPlugin->getSecureStopIds(
+            [&](Status status, const hidl_vec<SecureStopId>& ids) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(1u, ids.size());
+                ssid = ids[0];
+            });
+    EXPECT_OK(res);
+
+    stat = drmPlugin->removeSecureStop(ssid);
+    EXPECT_OK(stat);
+
+    res = drmPlugin->getSecureStopIds(
+            [&](Status status, const hidl_vec<SecureStopId>& ids) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_EQ(0u, ids.size());
+            });
+    EXPECT_OK(res);
+}
+
+
 int main(int argc, char** argv) {
     ::testing::AddGlobalTestEnvironment(DrmHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
diff --git a/graphics/common/1.1/Android.bp b/graphics/common/1.1/Android.bp
index c319d80..8bc68f5 100644
--- a/graphics/common/1.1/Android.bp
+++ b/graphics/common/1.1/Android.bp
@@ -15,8 +15,10 @@
     ],
     types: [
         "BufferUsage",
+        "ColorMode",
         "Dataspace",
         "PixelFormat",
+        "RenderIntent",
     ],
     gen_java: true,
     gen_java_constants: true,
diff --git a/graphics/common/1.1/types.hal b/graphics/common/1.1/types.hal
index b917d5e..5dca482 100644
--- a/graphics/common/1.1/types.hal
+++ b/graphics/common/1.1/types.hal
@@ -16,9 +16,10 @@
 
 package android.hardware.graphics.common@1.1;
 
-import @1.0::PixelFormat;
 import @1.0::BufferUsage;
+import @1.0::ColorMode;
 import @1.0::Dataspace;
+import @1.0::PixelFormat;
 
 /**
  * Pixel formats for graphics buffers.
@@ -129,15 +130,165 @@
 @export(name="android_dataspace_v1_1_t", value_prefix="HAL_DATASPACE_",
         export_parent="false")
 enum Dataspace : @1.0::Dataspace {
+    /*
+     * @1.0::Dataspace defines six legacy dataspaces
+     *
+     *   SRGB_LINEAR = 0x200, // deprecated, use V0_SRGB_LINEAR
+     *   SRGB = 0x201, // deprecated, use V0_SRGB
+     *   JFIF = 0x101, // deprecated, use V0_JFIF
+     *   BT601_625 = 0x102, // deprecated, use V0_BT601_625
+     *   BT601_525 = 0x103, // deprecated, use V0_BT601_525
+     *   BT709 = 0x104, // deprecated, use V0_BT709
+     *
+     * The difference between the legacy dataspaces and their modern
+     * counterparts is that, with legacy dataspaces, the pixel values may have
+     * been desaturated by the content creator in an unspecified way.
+     *
+     * When colorimetric mapping is required, the legacy dataspaces must be
+     * treated as their modern counterparts (e.g., SRGB must be treated as
+     * V0_SRGB) and no re-saturation is allowed. When non-colorimetric mapping
+     * is allowed, the pixel values can be interpreted freely by
+     * implementations for the purpose of re-saturation, and the re-saturated
+     * pixel values are in the respective modern dataspaces.
+     *
+     * This is also true when UNKNOWN is treated as a legacy dataspace.
+     */
+
     /**
      * ITU-R Recommendation 2020 (BT.2020)
      *
      * Ultra High-definition television
      *
-     * Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard
-     * limited range is the preferred / normative definition for BT.2020
+     * Use limited range, BT.709 transfer and BT2020 standard
      */
     BT2020_ITU = STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_LIMITED,
 
+    /**
+     * ITU-R Recommendation 2100 (BT.2100)
+     *
+     * High dynamic range television
+     *
+     * Use limited/full range, PQ/HLG transfer, and BT2020 standard
+     * limited range is the preferred / normative definition for BT.2100
+     */
     BT2020_ITU_PQ = STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED,
+    BT2020_ITU_HLG = STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED,
+    BT2020_HLG = STANDARD_BT2020 | TRANSFER_HLG | RANGE_FULL,
+};
+
+@export(name="android_color_mode_v1_1_t", value_prefix="HAL_COLOR_MODE_",
+        export_parent="false")
+enum ColorMode : @1.0::ColorMode {
+    /**
+     * BT2020 corresponds with display settings that implement the ITU-R
+     * Recommendation BT.2020 / Rec. 2020 for UHDTV.
+     *
+     * Primaries:
+     *                  x       y
+     *  green           0.170   0.797
+     *  blue            0.131   0.046
+     *  red             0.708   0.292
+     *  white (D65)     0.3127  0.3290
+     *
+     * Inverse Gamma Correction (IGC): V represents normalized (with [0 to 1]
+     * range) value of R, G, or B.
+     *
+     *  if Vnonlinear < b * 4.5
+     *    Vlinear = Vnonlinear / 4.5
+     *  else
+     *    Vlinear = ((Vnonlinear + (a - 1)) / a) ^ (1/0.45)
+     *
+     * Gamma Correction (GC):
+     *
+     *  if Vlinear < b
+     *    Vnonlinear = 4.5 * Vlinear
+     *  else
+     *    Vnonlinear = a * Vlinear ^ 0.45 - (a - 1)
+     *
+     * where
+     *
+     *   a = 1.09929682680944, b = 0.018053968510807
+     *
+     * For practical purposes, these a/b values can be used instead
+     *
+     *   a = 1.099, b = 0.018 for 10-bit display systems
+     *   a = 1.0993, b = 0.0181 for 12-bit display systems
+     */
+    BT2020 = 10,
+
+    /**
+     * BT2100_PQ and BT2100_HLG correspond with display settings that
+     * implement the ITU-R Recommendation BT.2100 / Rec. 2100 for HDR TV.
+     *
+     * Primaries:
+     *                  x       y
+     *  green           0.170   0.797
+     *  blue            0.131   0.046
+     *  red             0.708   0.292
+     *  white (D65)     0.3127  0.3290
+     *
+     * For BT2100_PQ, the transfer function is Perceptual Quantizer (PQ). For
+     * BT2100_HLG, the transfer function is Hybrid Log-Gamma (HLG).
+     */
+    BT2100_PQ = 11,
+    BT2100_HLG = 12,
+};
+
+/**
+ * RenderIntent defines the mapping from color mode colors to display colors.
+ *
+ * A render intent must not change how it maps colors when the color mode
+ * changes. That is to say that when a render intent maps color C to color C',
+ * the fact that color C can have different pixel values in different color
+ * modes should not affect the mapping.
+ *
+ * RenderIntent overrides the render intents defined for individual color
+ * modes. It is ignored when the color mode is ColorMode::NATIVE, because
+ * ColorMode::NATIVE colors are already display colors.
+ */
+@export(name="android_render_intent_v1_1_t", value_prefix="HAL_RENDER_INTENT_",
+        export_parent="false")
+enum RenderIntent : int32_t {
+    /**
+     * Colors in the display gamut are unchanged. Colors out of the display
+     * gamut are hard-clipped.
+     *
+     * This implies that the display must have been calibrated unless
+     * ColorMode::NATIVE is the only supported color mode.
+     */
+    COLORIMETRIC = 0,
+
+    /**
+     * Enhance colors that are in the display gamut. Colors out of the display
+     * gamut are hard-clipped.
+     *
+     * The enhancement typically picks the biggest standard color space (e.g.
+     * DCI-P3) that is narrower than the display gamut and stretches it to the
+     * display gamut. The stretching is recommended to preserve skin tones.
+     */
+    ENHANCE = 1,
+
+    /**
+     * Tone map high-dynamic-range colors to the display's dynamic range. The
+     * dynamic range of the colors are communicated separately. After tone
+     * mapping, the mapping to the display gamut is as defined in
+     * COLORIMETRIC.
+     */
+    TONE_MAP_COLORIMETRIC = 2,
+
+    /**
+     * Tone map high-dynamic-range colors to the display's dynamic range. The
+     * dynamic range of the colors are communicated separately. After tone
+     * mapping, the mapping to the display gamut is as defined in ENHANCE.
+     *
+     * The tone mapping step and the enhancing step must match
+     * TONE_MAP_COLORIMETRIC and ENHANCE respectively when they are also
+     * supported.
+     */
+    TONE_MAP_ENHANCE = 3,
+
+    /*
+     * Vendors are recommended to use 0x100 - 0x1FF for their own values, and
+     * that must be done with subtypes defined by vendor extensions.
+     */
 };
diff --git a/graphics/composer/2.2/Android.bp b/graphics/composer/2.2/Android.bp
index 633a208..fe71e9e 100644
--- a/graphics/composer/2.2/Android.bp
+++ b/graphics/composer/2.2/Android.bp
@@ -12,6 +12,7 @@
     ],
     interfaces: [
         "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.composer@2.1",
         "android.hidl.base@1.0",
     ],
diff --git a/graphics/composer/2.2/IComposerClient.hal b/graphics/composer/2.2/IComposerClient.hal
index dcd9c8d..657bcac 100644
--- a/graphics/composer/2.2/IComposerClient.hal
+++ b/graphics/composer/2.2/IComposerClient.hal
@@ -16,8 +16,10 @@
 
 package android.hardware.graphics.composer@2.2;
 
-import android.hardware.graphics.common@1.0::PixelFormat;
 import android.hardware.graphics.common@1.0::Dataspace;
+import android.hardware.graphics.common@1.0::PixelFormat;
+import android.hardware.graphics.common@1.1::ColorMode;
+import android.hardware.graphics.common@1.1::RenderIntent;
 import @2.1::IComposerClient;
 import @2.1::Display;
 import @2.1::Error;
@@ -90,16 +92,20 @@
 
     enum Command : @2.1::IComposerClient.Command {
         /**
-         * setPerFrameMetadata(Display display, vec<PerFrameMetadata> data)
+         * SET_LAYER_PER_FRAME_METADATA has this pseudo prototype
+         *
+         *   setLayerPerFrameMetadata(Display display, Layer layer,
+         *                            vec<PerFrameMetadata> data);
+         *
          * Sets the PerFrameMetadata for the display. This metadata must be used
          * by the implementation to better tone map content to that display.
          *
          * This is a method that may be called every frame. Thus it's
          * implemented using buffered transport.
-         * SET_PER_FRAME_METADATA is the command used by the buffered transport
+         * SET_LAYER_PER_FRAME_METADATA is the command used by the buffered transport
          * mechanism.
          */
-        SET_PER_FRAME_METADATA = 0x207 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+        SET_LAYER_PER_FRAME_METADATA = 0x303 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
 
         /**
          * SET_LAYER_COLOR has this pseudo prototype
@@ -260,4 +266,118 @@
      */
     setPowerMode_2_2(Display display, PowerMode mode) generates (Error error);
 
+    /**
+     * Returns the color modes supported on this display.
+     *
+     * All devices must support at least ColorMode::NATIVE.
+     *
+     * @param display is the display to query.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     * @return modes is an array of color modes.
+     */
+    getColorModes_2_2(Display display)
+           generates (Error error,
+                      vec<ColorMode> modes);
+
+    /**
+     * Returns the render intents supported by the specified display and color
+     * mode.
+     *
+     * RenderIntent::COLORIMETRIC is always supported.
+     *
+     * @param display is the display to query.
+     * @param mode is the color mode to query.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         BAD_PARAMETER when an invalid color mode was passed in.
+     * @return intents is an array of render intents.
+     */
+    getRenderIntents(Display display, ColorMode mode)
+          generates (Error error,
+                     vec<RenderIntent> intents);
+
+    /**
+     * Sets the color mode and render intent of the given display.
+     *
+     * The color mode and render intent change must take effect on next
+     * presentDisplay.
+     *
+     * All devices must support at least ColorMode::NATIVE and
+     * RenderIntent::COLORIMETRIC, and displays are assumed to be in this mode
+     * upon hotplug.
+     *
+     * @param display is the display to which the color mode is set.
+     * @param mode is the color mode to set to.
+     * @param intent is the render intent to set to.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         BAD_PARAMETER when mode or intent is invalid
+     *         UNSUPPORTED when mode or intent is not supported on this
+     *                     display.
+     */
+    setColorMode_2_2(Display display, ColorMode mode, RenderIntent intent)
+          generates (Error error);
+
+    /*
+     * By default, layer dataspaces are mapped to the current color mode
+     * colorimetrically with a few exceptions.
+     *
+     * When the layer dataspace is a legacy sRGB dataspace
+     * (Dataspace::SRGB_LINEAR, Dataspace::SRGB, or Dataspace::UNKNOWN when
+     * treated as such) and the display render intent is
+     * RenderIntent::ENHANCE, the pixel values can go through an
+     * implementation-defined saturation transform before being mapped to the
+     * current color mode colorimetrically.
+     *
+     * Colors that are out of the gamut of the current color mode are
+     * hard-clipped.
+     */
+
+    /**
+     * Returns the saturation matrix of the specified legacy dataspace.
+     *
+     * The saturation matrix can be used to approximate the legacy dataspace
+     * saturation transform. It is to be applied on linear pixel values like
+     * this:
+     *
+     *   (in GLSL)
+     *   linearSrgb = clamp(saturationMatrix * linearSrgb, 0.0, 1.0);
+     *
+     * @param dataspace must be Dataspace::SRGB_LINEAR.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_PARAMETER when an invalid dataspace was passed in.
+     * @return matrix is the 4x4 column-major matrix used to approximate the
+     *         legacy dataspace saturation operation. The last row must be
+     *         [0.0, 0.0, 0.0, 1.0].
+     */
+    getDataspaceSaturationMatrix(Dataspace dataspace)
+                      generates (Error error,
+                                 float[4][4] matrix);
+
+    /**
+     * Executes commands from the input command message queue. Return values
+     * generated by the input commands are written to the output command
+     * message queue in the form of value commands.
+     *
+     * @param inLength is the length of input commands.
+     * @param inHandles is an array of handles referenced by the input
+     *        commands.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_PARAMETER when inLength is not equal to the length of
+     *                       commands in the input command message queue.
+     *         NO_RESOURCES when the output command message queue was not
+     *                      properly drained.
+     * @param outQueueChanged indicates whether the output command message
+     *        queue has changed.
+     * @param outLength is the length of output commands.
+     * @param outHandles is an array of handles referenced by the output
+     *        commands.
+     */
+    executeCommands_2_2(uint32_t inLength,
+                        vec<handle> inHandles)
+             generates (Error error,
+                        bool outQueueChanged,
+                        uint32_t outLength,
+                        vec<handle> outHandles);
 };
diff --git a/graphics/composer/2.2/default/Android.bp b/graphics/composer/2.2/default/Android.bp
deleted file mode 100644
index 906479e..0000000
--- a/graphics/composer/2.2/default/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-cc_binary {
-    name: "android.hardware.graphics.composer@2.2-service",
-    defaults: ["hidl_defaults"],
-    vendor: true,
-    relative_install_path: "hw",
-    srcs: ["service.cpp"],
-    init_rc: ["android.hardware.graphics.composer@2.2-service.rc"],
-    header_libs: [
-        "android.hardware.graphics.composer@2.2-passthrough",
-    ],
-    shared_libs: [
-        "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.composer@2.2",
-        "android.hardware.graphics.mapper@2.0",
-        "libbase",
-        "libbinder",
-        "libcutils",
-        "libfmq",
-        "libhardware",
-        "libhidlbase",
-        "libhidltransport",
-        "libhwc2on1adapter",
-        "libhwc2onfbadapter",
-        "liblog",
-        "libsync",
-        "libutils",
-    ],
-    cflags: [
-        "-DLOG_TAG=\"ComposerHal\""
-    ],
-}
diff --git a/graphics/composer/2.2/default/Android.mk b/graphics/composer/2.2/default/Android.mk
new file mode 100644
index 0000000..2f80f0c
--- /dev/null
+++ b/graphics/composer/2.2/default/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.graphics.composer@2.2-service
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_CFLAGS := -Wall -Werror -DLOG_TAG=\"ComposerHal\"
+LOCAL_SRC_FILES := service.cpp
+LOCAL_INIT_RC := android.hardware.graphics.composer@2.2-service.rc
+LOCAL_HEADER_LIBRARIES := android.hardware.graphics.composer@2.2-passthrough
+LOCAL_SHARED_LIBRARIES := \
+        android.hardware.graphics.composer@2.1 \
+        android.hardware.graphics.composer@2.2 \
+        android.hardware.graphics.mapper@2.0 \
+        libbase \
+        libbinder \
+        libcutils \
+        libfmq \
+        libhardware \
+        libhidlbase \
+        libhidltransport \
+        libhwc2on1adapter \
+        libhwc2onfbadapter \
+        liblog \
+        libsync \
+        libutils
+
+ifdef TARGET_USES_DISPLAY_RENDER_INTENTS
+LOCAL_CFLAGS += -DUSES_DISPLAY_RENDER_INTENTS
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
index c803d3c..b499ca9 100644
--- a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
+++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
@@ -72,8 +72,9 @@
         endCommand();
     }
 
-    void setPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
-        beginCommand_2_2(IComposerClient::Command::SET_PER_FRAME_METADATA, metadataVec.size() * 2);
+    void setLayerPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
+        beginCommand_2_2(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
+                         metadataVec.size() * 2);
         for (const auto& metadata : metadataVec) {
             writeSigned(static_cast<int32_t>(metadata.key));
             writeFloat(metadata.value);
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
index d550f83..ba6723d 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
@@ -103,6 +103,64 @@
         return mHal->setPowerMode_2_2(display, mode);
     }
 
+    Return<void> getColorModes_2_2(Display display,
+                                   IComposerClient::getColorModes_2_2_cb hidl_cb) override {
+        hidl_vec<ColorMode> modes;
+        Error err = mHal->getColorModes_2_2(display, &modes);
+        hidl_cb(err, modes);
+        return Void();
+    }
+
+    Return<void> getRenderIntents(Display display, ColorMode mode,
+                                  IComposerClient::getRenderIntents_cb hidl_cb) override {
+#ifdef USES_DISPLAY_RENDER_INTENTS
+        std::vector<RenderIntent> intents;
+        Error err = mHal->getRenderIntents(display, mode, &intents);
+        hidl_cb(err, intents);
+#else
+        (void)display;
+        (void)mode;
+        hidl_cb(Error::NONE, hidl_vec<RenderIntent>({RenderIntent::COLORIMETRIC}));
+#endif
+        return Void();
+    }
+
+    Return<Error> setColorMode_2_2(Display display, ColorMode mode, RenderIntent intent) override {
+#ifndef USES_DISPLAY_RENDER_INTENTS
+        if (intent != RenderIntent::COLORIMETRIC) {
+            return Error::BAD_PARAMETER;
+        }
+#endif
+        return mHal->setColorMode_2_2(display, mode, intent);
+    }
+
+    Return<void> getDataspaceSaturationMatrix(
+        Dataspace dataspace, IComposerClient::getDataspaceSaturationMatrix_cb hidl_cb) override {
+        if (dataspace != Dataspace::SRGB_LINEAR) {
+            hidl_cb(Error::BAD_PARAMETER, std::array<float, 16>{0.0f}.data());
+            return Void();
+        }
+
+        hidl_cb(Error::NONE, mHal->getDataspaceSaturationMatrix(dataspace).data());
+        return Void();
+    }
+
+    Return<void> executeCommands_2_2(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
+                                     IComposerClient::executeCommands_2_2_cb hidl_cb) override {
+        std::lock_guard<std::mutex> lock(mCommandEngineMutex);
+        bool outChanged = false;
+        uint32_t outLength = 0;
+        hidl_vec<hidl_handle> outHandles;
+        Error error =
+            mCommandEngine->execute(inLength, inHandles, &outChanged, &outLength, &outHandles);
+
+        hidl_cb(error, outChanged, outLength, outHandles);
+
+        mCommandEngine->reset();
+
+        return Void();
+    }
+
    protected:
     std::unique_ptr<V2_1::hal::ComposerResources> createResources() override {
         return ComposerResources::create();
@@ -146,6 +204,8 @@
 
    private:
     using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+    using BaseType2_1::mCommandEngine;
+    using BaseType2_1::mCommandEngineMutex;
     using BaseType2_1::mHal;
     using BaseType2_1::mResources;
 };
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
index adcac46..97e3a9e 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
@@ -40,8 +40,8 @@
    protected:
     bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
         switch (static_cast<IComposerClient::Command>(command)) {
-            case IComposerClient::Command::SET_PER_FRAME_METADATA:
-                return executeSetPerFrameMetadata(length);
+            case IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA:
+                return executeSetLayerPerFrameMetadata(length);
             case IComposerClient::Command::SET_LAYER_FLOAT_COLOR:
                 return executeSetLayerFloatColor(length);
             default:
@@ -49,7 +49,7 @@
         }
     }
 
-    bool executeSetPerFrameMetadata(uint16_t length) {
+    bool executeSetLayerPerFrameMetadata(uint16_t length) {
         // (key, value) pairs
         if (length % 2 != 0) {
             return false;
@@ -63,7 +63,7 @@
             length -= 2;
         }
 
-        auto err = mHal->setPerFrameMetadata(mCurrentDisplay, metadata);
+        auto err = mHal->setLayerPerFrameMetadata(mCurrentDisplay, mCurrentLayer, metadata);
         if (err != Error::NONE) {
             mWriter.setError(getCommandLoc(), err);
         }
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerHal.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerHal.h
index 30b3643..12191be 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerHal.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerHal.h
@@ -30,6 +30,8 @@
 
 using common::V1_0::Dataspace;
 using common::V1_0::PixelFormat;
+using common::V1_1::ColorMode;
+using common::V1_1::RenderIntent;
 using V2_1::Display;
 using V2_1::Error;
 using V2_1::Layer;
@@ -41,10 +43,21 @@
         return setPowerMode_2_2(display, static_cast<IComposerClient::PowerMode>(mode));
     }
 
+    // superceded by getColorModes_2_2
+    Error getColorModes(Display display, hidl_vec<common::V1_0::ColorMode>* outModes) override {
+        return getColorModes_2_2(display, reinterpret_cast<hidl_vec<ColorMode>*>(outModes));
+    }
+
+    // superceded by setColorMode_2_2
+    Error setColorMode(Display display, common::V1_0::ColorMode mode) override {
+        return setColorMode_2_2(display, static_cast<ColorMode>(mode), RenderIntent::COLORIMETRIC);
+    }
+
     virtual Error getPerFrameMetadataKeys(
         Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) = 0;
-    virtual Error setPerFrameMetadata(
-        Display display, const std::vector<IComposerClient::PerFrameMetadata>& metadata) = 0;
+    virtual Error setLayerPerFrameMetadata(
+        Display display, Layer layer,
+        const std::vector<IComposerClient::PerFrameMetadata>& metadata) = 0;
 
     virtual Error getReadbackBufferAttributes(Display display, PixelFormat* outFormat,
                                               Dataspace* outDataspace) = 0;
@@ -56,6 +69,13 @@
 
     virtual Error setLayerFloatColor(Display display, Layer layer,
                                      IComposerClient::FloatColor color) = 0;
+
+    virtual Error getColorModes_2_2(Display display, hidl_vec<ColorMode>* outModes) = 0;
+    virtual Error getRenderIntents(Display display, ColorMode mode,
+                                   std::vector<RenderIntent>* outIntents) = 0;
+    virtual Error setColorMode_2_2(Display display, ColorMode mode, RenderIntent intent) = 0;
+
+    virtual std::array<float, 16> getDataspaceSaturationMatrix(Dataspace dataspace) = 0;
 };
 
 }  // namespace hal
diff --git a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
index b251351..7e38a79 100644
--- a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
+++ b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
@@ -36,6 +36,8 @@
 
 using common::V1_0::Dataspace;
 using common::V1_0::PixelFormat;
+using common::V1_1::ColorMode;
+using common::V1_1::RenderIntent;
 using V2_1::Display;
 using V2_1::Error;
 using V2_1::Layer;
@@ -72,9 +74,10 @@
         return Error::NONE;
     }
 
-    Error setPerFrameMetadata(
-        Display display, const std::vector<IComposerClient::PerFrameMetadata>& metadata) override {
-        if (!mDispatch.setPerFrameMetadata) {
+    Error setLayerPerFrameMetadata(
+        Display display, Layer layer,
+        const std::vector<IComposerClient::PerFrameMetadata>& metadata) override {
+        if (!mDispatch.setLayerPerFrameMetadata) {
             return Error::UNSUPPORTED;
         }
 
@@ -87,8 +90,8 @@
             values.push_back(m.value);
         }
 
-        int32_t error = mDispatch.setPerFrameMetadata(mDevice, display, metadata.size(),
-                                                      keys.data(), values.data());
+        int32_t error = mDispatch.setLayerPerFrameMetadata(mDevice, display, layer, metadata.size(),
+                                                           keys.data(), values.data());
         return static_cast<Error>(error);
     }
 
@@ -149,6 +152,69 @@
         return static_cast<Error>(error);
     }
 
+    Error getColorModes_2_2(Display display, hidl_vec<ColorMode>* outModes) override {
+        return getColorModes(display,
+                             reinterpret_cast<hidl_vec<common::V1_0::ColorMode>*>(outModes));
+    }
+
+    Error getRenderIntents(Display display, ColorMode mode,
+                           std::vector<RenderIntent>* outIntents) override {
+        if (!mDispatch.getRenderIntents) {
+            *outIntents = std::vector<RenderIntent>({RenderIntent::COLORIMETRIC});
+            return Error::NONE;
+        }
+
+        uint32_t count = 0;
+        int32_t error =
+            mDispatch.getRenderIntents(mDevice, display, int32_t(mode), &count, nullptr);
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+
+        std::vector<RenderIntent> intents(count);
+        error = mDispatch.getRenderIntents(
+            mDevice, display, int32_t(mode), &count,
+            reinterpret_cast<std::underlying_type<RenderIntent>::type*>(intents.data()));
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+        intents.resize(count);
+
+        *outIntents = std::move(intents);
+        return Error::NONE;
+    }
+
+    Error setColorMode_2_2(Display display, ColorMode mode, RenderIntent intent) override {
+        if (!mDispatch.setColorModeWithRenderIntent) {
+            if (intent != RenderIntent::COLORIMETRIC) {
+                return Error::UNSUPPORTED;
+            }
+            return setColorMode(display, static_cast<common::V1_0::ColorMode>(mode));
+        }
+
+        int32_t err = mDispatch.setColorModeWithRenderIntent(
+            mDevice, display, static_cast<int32_t>(mode), static_cast<int32_t>(intent));
+        return static_cast<Error>(err);
+    }
+
+    std::array<float, 16> getDataspaceSaturationMatrix(Dataspace dataspace) override {
+        std::array<float, 16> matrix;
+
+        int32_t error = HWC2_ERROR_UNSUPPORTED;
+        if (mDispatch.getDataspaceSaturationMatrix) {
+            error = mDispatch.getDataspaceSaturationMatrix(mDevice, static_cast<int32_t>(dataspace),
+                                                           matrix.data());
+        }
+        if (error != HWC2_ERROR_NONE) {
+            return std::array<float, 16>{
+                1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+                0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+            };
+        }
+
+        return matrix;
+    }
+
    protected:
     template <typename T>
     bool initOptionalDispatch(hwc2_function_descriptor_t desc, T* outPfn) {
@@ -168,7 +234,8 @@
 
         initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_FLOAT_COLOR, &mDispatch.setLayerFloatColor);
 
-        initOptionalDispatch(HWC2_FUNCTION_SET_PER_FRAME_METADATA, &mDispatch.setPerFrameMetadata);
+        initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_PER_FRAME_METADATA,
+                             &mDispatch.setLayerPerFrameMetadata);
         initOptionalDispatch(HWC2_FUNCTION_GET_PER_FRAME_METADATA_KEYS,
                              &mDispatch.getPerFrameMetadataKeys);
 
@@ -178,21 +245,32 @@
         initOptionalDispatch(HWC2_FUNCTION_GET_READBACK_BUFFER_FENCE,
                              &mDispatch.getReadbackBufferFence);
 
+        initOptionalDispatch(HWC2_FUNCTION_GET_RENDER_INTENTS, &mDispatch.getRenderIntents);
+        initOptionalDispatch(HWC2_FUNCTION_SET_COLOR_MODE_WITH_RENDER_INTENT,
+                             &mDispatch.setColorModeWithRenderIntent);
+        initOptionalDispatch(HWC2_FUNCTION_GET_DATASPACE_SATURATION_MATRIX,
+                             &mDispatch.getDataspaceSaturationMatrix);
+
         return true;
     }
 
     struct {
         HWC2_PFN_SET_LAYER_FLOAT_COLOR setLayerFloatColor;
-        HWC2_PFN_SET_PER_FRAME_METADATA setPerFrameMetadata;
+        HWC2_PFN_SET_LAYER_PER_FRAME_METADATA setLayerPerFrameMetadata;
         HWC2_PFN_GET_PER_FRAME_METADATA_KEYS getPerFrameMetadataKeys;
         HWC2_PFN_SET_READBACK_BUFFER setReadbackBuffer;
         HWC2_PFN_GET_READBACK_BUFFER_ATTRIBUTES getReadbackBufferAttributes;
         HWC2_PFN_GET_READBACK_BUFFER_FENCE getReadbackBufferFence;
+        HWC2_PFN_GET_RENDER_INTENTS getRenderIntents;
+        HWC2_PFN_SET_COLOR_MODE_WITH_RENDER_INTENT setColorModeWithRenderIntent;
+        HWC2_PFN_GET_DATASPACE_SATURATION_MATRIX getDataspaceSaturationMatrix;
     } mDispatch = {};
 
    private:
     using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
+    using BaseType2_1::getColorModes;
     using BaseType2_1::mDevice;
+    using BaseType2_1::setColorMode;
     using BaseType2_1::setPowerMode;
 };
 
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 641fdcb..c6b524d 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -26,10 +26,17 @@
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
     ],
+    export_static_lib_headers: [
+        "android.hardware.graphics.composer@2.1-vts",
+    ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
     ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
     cflags: [
         "-O0",
         "-g",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index b536f67..9a035f6 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -119,6 +119,41 @@
     *outFence = 0;
 }
 
+std::vector<ColorMode> ComposerClient_v2_2::getColorModes(Display display) {
+    std::vector<ColorMode> modes;
+    mClient_v2_2->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get color modes";
+        modes = tmpModes;
+    });
+    return modes;
+}
+
+std::vector<RenderIntent> ComposerClient_v2_2::getRenderIntents(Display display, ColorMode mode) {
+    std::vector<RenderIntent> intents;
+    mClient_v2_2->getRenderIntents(
+        display, mode, [&](const auto& tmpError, const auto& tmpIntents) {
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to get render intents";
+            intents = tmpIntents;
+        });
+    return intents;
+}
+
+void ComposerClient_v2_2::setColorMode(Display display, ColorMode mode, RenderIntent intent) {
+    Error error = mClient_v2_2->setColorMode_2_2(display, mode, intent);
+    ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set color mode";
+}
+
+std::array<float, 16> ComposerClient_v2_2::getDataspaceSaturationMatrix(Dataspace dataspace) {
+    std::array<float, 16> matrix;
+    mClient_v2_2->getDataspaceSaturationMatrix(
+        dataspace, [&](const auto& tmpError, const auto& tmpMatrix) {
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to get datasapce saturation matrix";
+            std::copy_n(tmpMatrix.data(), matrix.size(), matrix.begin());
+        });
+
+    return matrix;
+}
+
 }  // namespace vts
 }  // namespace V2_2
 }  // namespace composer
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index eced69f..5467011 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -36,10 +36,11 @@
 namespace V2_2 {
 namespace vts {
 
-using android::hardware::graphics::common::V1_0::ColorMode;
 using android::hardware::graphics::common::V1_0::Dataspace;
 using android::hardware::graphics::common::V1_0::Hdr;
 using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::common::V1_1::ColorMode;
+using android::hardware::graphics::common::V1_1::RenderIntent;
 using android::hardware::graphics::composer::V2_2::IComposer;
 using android::hardware::graphics::composer::V2_2::IComposerClient;
 
@@ -72,6 +73,12 @@
                                      Dataspace* outDataspace);
     void getReadbackBufferFence(Display display, int32_t* outFence);
 
+    std::vector<ColorMode> getColorModes(Display display);
+    std::vector<RenderIntent> getRenderIntents(Display display, ColorMode mode);
+    void setColorMode(Display display, ColorMode mode, RenderIntent intent);
+
+    std::array<float, 16> getDataspaceSaturationMatrix(Dataspace dataspace);
+
    private:
     sp<V2_2::IComposerClient> mClient_v2_2;
 };
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index c494329..3103d10 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -33,11 +33,12 @@
 namespace {
 
 using android::hardware::graphics::common::V1_0::BufferUsage;
-using android::hardware::graphics::common::V1_0::ColorMode;
 using android::hardware::graphics::common::V1_0::ColorTransform;
 using android::hardware::graphics::common::V1_0::Dataspace;
 using android::hardware::graphics::common::V1_0::PixelFormat;
 using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::common::V1_1::ColorMode;
+using android::hardware::graphics::common::V1_1::RenderIntent;
 using android::hardware::graphics::composer::V2_2::IComposerClient;
 using android::hardware::graphics::mapper::V2_0::IMapper;
 using android::hardware::graphics::mapper::V2_0::vts::Gralloc;
@@ -146,9 +147,9 @@
 };
 
 /**
- * Test IComposerClient::Command::SET_PER_FRAME_METADATA.
+ * Test IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_PER_FRAME_METADATA) {
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -182,7 +183,7 @@
     hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0});
     hidlMetadata.push_back(
         {IComposerClient::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
-    mWriter->setPerFrameMetadata(hidlMetadata);
+    mWriter->setLayerPerFrameMetadata(hidlMetadata);
     execute();
 }
 
@@ -235,6 +236,56 @@
     mWriter->setLayerFloatColor(IComposerClient::FloatColor{0.0, 0.0, 0.0, 0.0});
 }
 
+/**
+ * Test IComposerClient::getDataspaceSaturationMatrix.
+ */
+TEST_F(GraphicsComposerHidlTest, getDataspaceSaturationMatrix) {
+    auto matrix = mComposerClient->getDataspaceSaturationMatrix(Dataspace::SRGB_LINEAR);
+    // the last row is known
+    ASSERT_EQ(0.0f, matrix[12]);
+    ASSERT_EQ(0.0f, matrix[13]);
+    ASSERT_EQ(0.0f, matrix[14]);
+    ASSERT_EQ(1.0f, matrix[15]);
+}
+
+/**
+ * Test IComposerClient::getColorMode_2_2.
+ */
+TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2) {
+    std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
+
+    auto nativeMode = std::find(modes.cbegin(), modes.cend(), ColorMode::NATIVE);
+    EXPECT_NE(modes.cend(), nativeMode);
+}
+
+/**
+ * Test IComposerClient::getRenderIntent.
+ */
+TEST_F(GraphicsComposerHidlTest, GetRenderIntent) {
+    std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
+    for (auto mode : modes) {
+        std::vector<RenderIntent> intents =
+            mComposerClient->getRenderIntents(mPrimaryDisplay, mode);
+        auto colorimetricIntent =
+            std::find(intents.cbegin(), intents.cend(), RenderIntent::COLORIMETRIC);
+        EXPECT_NE(intents.cend(), colorimetricIntent);
+    }
+}
+
+/**
+ * Test IComposerClient::setColorMode_2_2.
+ */
+TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2) {
+    std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
+    for (auto mode : modes) {
+        std::vector<RenderIntent> intents =
+            mComposerClient->getRenderIntents(mPrimaryDisplay, mode);
+        for (auto intent : intents) {
+            mComposerClient->setColorMode(mPrimaryDisplay, mode, intent);
+        }
+    }
+}
+
 }  // namespace
 }  // namespace vts
 }  // namespace V2_2
diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
index 3a181a9..fbe5237 100644
--- a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -2918,6 +2918,28 @@
 }
 
 /*
+ * EncryptionOperationsTest.AesEcbWithUserId
+ *
+ * Verifies that AES ECB mode works when Tag::USER_ID is specified.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbWithUserId) {
+    string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .Authorization(TAG_USER_ID, 0)
+                                           .AesEncryptionKey(key.size() * 8)
+                                           .EcbMode()
+                                           .Padding(PaddingMode::PKCS7),
+                                       KeyFormat::RAW, key));
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+    string ciphertext = EncryptMessage(message, params);
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
  * EncryptionOperationsTest.AesEcbRoundTripSuccess
  *
  * Verifies that AES encryption fails in the correct way when an unauthorized mode is specified.
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp
index bf52c47..fac0017 100644
--- a/keymaster/4.0/support/Keymaster.cpp
+++ b/keymaster/4.0/support/Keymaster.cpp
@@ -40,7 +40,7 @@
     serviceManager->listByInterface(descriptor, [&](const hidl_vec<hidl_string>& names) {
         for (auto& name : names) {
             if (name == "default") foundDefault = true;
-            auto device = Wrapper::WrappedIKeymasterDevice::getService();
+            auto device = Wrapper::WrappedIKeymasterDevice::getService(name);
             CHECK(device) << "Failed to get service for " << descriptor << " with interface name "
                           << name;
             result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, name)));
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index 9d6501b..ce213bc 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -142,24 +142,28 @@
 DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
 DECLARE_TYPED_TAG(TRUSTED_CONFIRMATION_REQUIRED);
 DECLARE_TYPED_TAG(UNIQUE_ID);
+DECLARE_TYPED_TAG(UNLOCKED_DEVICE_REQUIRED);
 DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
 DECLARE_TYPED_TAG(USER_AUTH_TYPE);
+DECLARE_TYPED_TAG(USER_ID);
 DECLARE_TYPED_TAG(USER_SECURE_ID);
 
 template <typename... Elems>
 struct MetaList {};
 
-using all_tags_t = MetaList<
-    TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t,
-    TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t, TAG_ACTIVE_DATETIME_t,
-    TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, TAG_MIN_SECONDS_BETWEEN_OPS_t,
-    TAG_MAX_USES_PER_BOOT_t, TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t,
-    TAG_ALLOW_WHILE_ON_BODY_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t,
-    TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t,
-    TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t,
-    TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t,
-    TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
-    TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t>;
+using all_tags_t =
+    MetaList<TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t,
+             TAG_MIN_MAC_LENGTH_t, TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t,
+             TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t,
+             TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_USER_ID_t,
+             TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t,
+             TAG_ALLOW_WHILE_ON_BODY_t, TAG_UNLOCKED_DEVICE_REQUIRED_t, TAG_APPLICATION_ID_t,
+             TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t,
+             TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t,
+             TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, TAG_ATTESTATION_CHALLENGE_t,
+             TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t,
+             TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
+             TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t>;
 
 template <typename TypedTagType>
 struct TypedTag2ValueType;
@@ -343,6 +347,7 @@
         case Tag::BOOTLOADER_ONLY:
         case Tag::NO_AUTH_REQUIRED:
         case Tag::ALLOW_WHILE_ON_BODY:
+        case Tag::UNLOCKED_DEVICE_REQUIRED:
         case Tag::ROLLBACK_RESISTANCE:
         case Tag::RESET_SINCE_ID_ROTATION:
         case Tag::TRUSTED_CONFIRMATION_REQUIRED:
@@ -357,6 +362,7 @@
         case Tag::OS_VERSION:
         case Tag::OS_PATCHLEVEL:
         case Tag::MAC_LENGTH:
+        case Tag::USER_ID:
         case Tag::AUTH_TIMEOUT:
         case Tag::VENDOR_PATCHLEVEL:
         case Tag::BOOT_PATCHLEVEL:
diff --git a/keymaster/4.0/types.hal b/keymaster/4.0/types.hal
index 91ec9bf..47fd1ed 100644
--- a/keymaster/4.0/types.hal
+++ b/keymaster/4.0/types.hal
@@ -118,7 +118,8 @@
                                                        * boot. */
 
     /* User authentication */
-    // 500-501 reserved
+    // 500 reserved
+    USER_ID = TagType:UINT | 501,             /* Android ID of authorized user or authenticator(s), */
     USER_SECURE_ID = TagType:ULONG_REP | 502, /* Secure ID of authorized user or authenticator(s).
                                                * Disallowed if NO_AUTH_REQUIRED is present. */
     NO_AUTH_REQUIRED = TagType:BOOL | 503,    /* If key is usable without authentication. */
@@ -191,6 +192,9 @@
      * match the data described in the token, keymaster must return NO_USER_CONFIRMATION. */
     TRUSTED_CONFIRMATION_REQUIRED = TagType:BOOL | 508,
 
+    UNLOCKED_DEVICE_REQUIRED = TagType:BOOL | 509, /* Require the device screen to be unlocked if
+                                                    * the key is used. */
+
     /* Application access control */
     APPLICATION_ID = TagType:BYTES | 601, /* Byte string identifying the authorized application. */
 
@@ -471,6 +475,7 @@
     PROOF_OF_PRESENCE_REQUIRED = -69,
     CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
     NO_USER_CONFIRMATION = -71,
+    DEVICE_LOCKED = -72,
 
     UNIMPLEMENTED = -100,
     VERSION_MISMATCH = -101,
diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal
index 8779723..c97a00b 100644
--- a/neuralnetworks/1.0/types.hal
+++ b/neuralnetworks/1.0/types.hal
@@ -84,6 +84,7 @@
      *     output.dimension = {5, 4, 3, 2}
      *
      * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     *                         {@link OperandType::TENSOR_QUANT8_ASYMM}
      * Supported tensor rank: up to 4
      *
      * Inputs:
@@ -645,6 +646,7 @@
      * input operands. It starts with the trailing dimensions, and works its way forward.
      *
      * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     *                         {@link OperandType::TENSOR_QUANT8_ASYMM}
      * Supported tensor rank: up to 4
      *
      * Inputs:
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 54dd14a..e28113b 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -18,7 +18,6 @@
     name: "VtsHalNeuralnetworksTest_utils",
     srcs: [
         "Callbacks.cpp",
-        "Models.cpp",
         "GeneratedTestHarness.cpp",
     ],
     defaults: ["VtsHalTargetTestDefaults"],
@@ -41,14 +40,17 @@
 cc_test {
     name: "VtsHalNeuralnetworksV1_0TargetTest",
     srcs: [
-        "VtsHalNeuralnetworksV1_0.cpp",
-        "VtsHalNeuralnetworksV1_0BasicTest.cpp",
-        "VtsHalNeuralnetworksV1_0GeneratedTest.cpp",
+        "BasicTests.cpp",
+        "GeneratedTests.cpp",
+        "ValidateModel.cpp",
+        "ValidateRequest.cpp",
+        "ValidationTests.cpp",
+        "VtsHalNeuralnetworks.cpp",
     ],
     defaults: ["VtsHalTargetTestDefaults"],
     static_libs: [
-        "android.hardware.neuralnetworks@1.0",
         "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libhidlmemory",
diff --git a/neuralnetworks/1.0/vts/functional/BasicTests.cpp b/neuralnetworks/1.0/vts/functional/BasicTests.cpp
new file mode 100644
index 0000000..945c406
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/BasicTests.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+// create device test
+TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
+
+// status test
+TEST_F(NeuralnetworksHidlTest, StatusTest) {
+    Return<DeviceStatus> status = device->getStatus();
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
+}
+
+// initialization
+TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+    Return<void> ret =
+        device->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) {
+            EXPECT_EQ(ErrorStatus::NONE, status);
+            EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
+            EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
+            EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
+            EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
+        });
+    EXPECT_TRUE(ret.isOk());
+}
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.h b/neuralnetworks/1.0/vts/functional/Callbacks.h
index 0e2ffb3..2ac6130 100644
--- a/neuralnetworks/1.0/vts/functional/Callbacks.h
+++ b/neuralnetworks/1.0/vts/functional/Callbacks.h
@@ -17,14 +17,6 @@
 namespace V1_0 {
 namespace implementation {
 
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
 /**
  * The CallbackBase class is used internally by the NeuralNetworks runtime to
  * synchronize between different threads. An asynchronous task is launched
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 8646a4c..4f9d528 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -179,7 +179,7 @@
     }
 }
 
-void Execute(sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
+void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
              std::function<bool(int)> is_ignored,
              const std::vector<MixedTypedExampleType>& examples) {
     V1_0::Model model = create_model();
@@ -223,7 +223,7 @@
     EvaluatePreparedModel(preparedModel, is_ignored, examples);
 }
 
-void Execute(sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
+void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
              std::function<bool(int)> is_ignored,
              const std::vector<MixedTypedExampleType>& examples) {
     V1_1::Model model = create_model();
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0GeneratedTest.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
similarity index 61%
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0GeneratedTest.cpp
rename to neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
index b99aef7..2107333 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0GeneratedTest.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
@@ -16,47 +16,33 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
-#include "VtsHalNeuralnetworksV1_0.h"
+#include "VtsHalNeuralnetworks.h"
 
 #include "Callbacks.h"
 #include "TestHarness.h"
+#include "Utils.h"
 
 #include <android-base/logging.h>
 #include <android/hidl/memory/1.0/IMemory.h>
 #include <hidlmemory/mapping.h>
 
-using ::android::hardware::neuralnetworks::V1_0::IDevice;
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Capabilities;
-using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
-using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
-using ::android::hardware::neuralnetworks::V1_0::Model;
-using ::android::hardware::neuralnetworks::V1_0::OperationType;
-using ::android::hardware::neuralnetworks::V1_0::PerformanceInfo;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
 namespace android {
 namespace hardware {
 namespace neuralnetworks {
 
 namespace generated_tests {
 using ::generated_tests::MixedTypedExampleType;
-extern void Execute(sp<IDevice>&, std::function<Model(void)>, std::function<bool(int)>,
-                    const std::vector<MixedTypedExampleType>&);
+extern void Execute(const sp<V1_0::IDevice>&, std::function<V1_0::Model(void)>,
+                    std::function<bool(int)>, const std::vector<MixedTypedExampleType>&);
 }  // namespace generated_tests
 
 namespace V1_0 {
 namespace vts {
 namespace functional {
+
 using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
 using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::nn::allocateSharedMemory;
 
 // Mixed-typed examples
 typedef generated_tests::MixedTypedExampleType MixedTypedExample;
diff --git a/neuralnetworks/1.0/vts/functional/Models.cpp b/neuralnetworks/1.0/vts/functional/Models.cpp
deleted file mode 100644
index 180286a..0000000
--- a/neuralnetworks/1.0/vts/functional/Models.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "neuralnetworks_hidl_hal_test"
-
-#include "Models.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-#include <vector>
-
-using ::android::sp;
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-
-// create a valid model
-V1_1::Model createValidTestModel_1_1() {
-    const std::vector<float> operand2Data = {5.0f, 6.0f, 7.0f, 8.0f};
-    const uint32_t size = operand2Data.size() * sizeof(float);
-
-    const uint32_t operand1 = 0;
-    const uint32_t operand2 = 1;
-    const uint32_t operand3 = 2;
-    const uint32_t operand4 = 3;
-
-    const std::vector<Operand> operands = {
-        {
-            .type = OperandType::TENSOR_FLOAT32,
-            .dimensions = {1, 2, 2, 1},
-            .numberOfConsumers = 1,
-            .scale = 0.0f,
-            .zeroPoint = 0,
-            .lifetime = OperandLifeTime::MODEL_INPUT,
-            .location = {.poolIndex = 0, .offset = 0, .length = 0},
-        },
-        {
-            .type = OperandType::TENSOR_FLOAT32,
-            .dimensions = {1, 2, 2, 1},
-            .numberOfConsumers = 1,
-            .scale = 0.0f,
-            .zeroPoint = 0,
-            .lifetime = OperandLifeTime::CONSTANT_COPY,
-            .location = {.poolIndex = 0, .offset = 0, .length = size},
-        },
-        {
-            .type = OperandType::INT32,
-            .dimensions = {},
-            .numberOfConsumers = 1,
-            .scale = 0.0f,
-            .zeroPoint = 0,
-            .lifetime = OperandLifeTime::CONSTANT_COPY,
-            .location = {.poolIndex = 0, .offset = size, .length = sizeof(int32_t)},
-        },
-        {
-            .type = OperandType::TENSOR_FLOAT32,
-            .dimensions = {1, 2, 2, 1},
-            .numberOfConsumers = 0,
-            .scale = 0.0f,
-            .zeroPoint = 0,
-            .lifetime = OperandLifeTime::MODEL_OUTPUT,
-            .location = {.poolIndex = 0, .offset = 0, .length = 0},
-        },
-    };
-
-    const std::vector<Operation> operations = {{
-        .type = OperationType::ADD, .inputs = {operand1, operand2, operand3}, .outputs = {operand4},
-    }};
-
-    const std::vector<uint32_t> inputIndexes = {operand1};
-    const std::vector<uint32_t> outputIndexes = {operand4};
-    std::vector<uint8_t> operandValues(
-        reinterpret_cast<const uint8_t*>(operand2Data.data()),
-        reinterpret_cast<const uint8_t*>(operand2Data.data()) + size);
-    int32_t activation[1] = {static_cast<int32_t>(FusedActivationFunc::NONE)};
-    operandValues.insert(operandValues.end(), reinterpret_cast<const uint8_t*>(&activation[0]),
-                         reinterpret_cast<const uint8_t*>(&activation[1]));
-
-    const std::vector<hidl_memory> pools = {};
-
-    return {
-        .operands = operands,
-        .operations = operations,
-        .inputIndexes = inputIndexes,
-        .outputIndexes = outputIndexes,
-        .operandValues = operandValues,
-        .pools = pools,
-    };
-}
-
-// create first invalid model
-V1_1::Model createInvalidTestModel1_1_1() {
-    Model model = createValidTestModel_1_1();
-    model.operations[0].type = static_cast<OperationType>(0xDEADBEEF); /* INVALID */
-    return model;
-}
-
-// create second invalid model
-V1_1::Model createInvalidTestModel2_1_1() {
-    Model model = createValidTestModel_1_1();
-    const uint32_t operand1 = 0;
-    const uint32_t operand5 = 4;  // INVALID OPERAND
-    model.inputIndexes = std::vector<uint32_t>({operand1, operand5 /* INVALID OPERAND */});
-    return model;
-}
-
-V1_0::Model createValidTestModel_1_0() {
-    V1_1::Model model = createValidTestModel_1_1();
-    return nn::convertToV1_0(model);
-}
-
-V1_0::Model createInvalidTestModel1_1_0() {
-    V1_1::Model model = createInvalidTestModel1_1_1();
-    return nn::convertToV1_0(model);
-}
-
-V1_0::Model createInvalidTestModel2_1_0() {
-    V1_1::Model model = createInvalidTestModel2_1_1();
-    return nn::convertToV1_0(model);
-}
-
-// create a valid request
-Request createValidTestRequest() {
-    std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
-    std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
-    const uint32_t INPUT = 0;
-    const uint32_t OUTPUT = 1;
-
-    // prepare inputs
-    uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
-    uint32_t outputSize = static_cast<uint32_t>(outputData.size() * sizeof(float));
-    std::vector<RequestArgument> inputs = {{
-        .location = {.poolIndex = INPUT, .offset = 0, .length = inputSize}, .dimensions = {},
-    }};
-    std::vector<RequestArgument> outputs = {{
-        .location = {.poolIndex = OUTPUT, .offset = 0, .length = outputSize}, .dimensions = {},
-    }};
-    std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
-                                      nn::allocateSharedMemory(outputSize)};
-    if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
-        return {};
-    }
-
-    // load data
-    sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
-    sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
-    if (inputMemory.get() == nullptr || outputMemory.get() == nullptr) {
-        return {};
-    }
-    float* inputPtr = reinterpret_cast<float*>(static_cast<void*>(inputMemory->getPointer()));
-    float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
-    if (inputPtr == nullptr || outputPtr == nullptr) {
-        return {};
-    }
-    inputMemory->update();
-    outputMemory->update();
-    std::copy(inputData.begin(), inputData.end(), inputPtr);
-    std::copy(outputData.begin(), outputData.end(), outputPtr);
-    inputMemory->commit();
-    outputMemory->commit();
-
-    return {.inputs = inputs, .outputs = outputs, .pools = pools};
-}
-
-// create first invalid request
-Request createInvalidTestRequest1() {
-    Request request = createValidTestRequest();
-    const uint32_t INVALID = 2;
-    std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
-    uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
-    request.inputs[0].location = {
-        .poolIndex = INVALID /* INVALID */, .offset = 0, .length = inputSize};
-    return request;
-}
-
-// create second invalid request
-Request createInvalidTestRequest2() {
-    Request request = createValidTestRequest();
-    request.inputs[0].dimensions = std::vector<uint32_t>({1, 2, 3, 4, 5, 6, 7, 8} /* INVALID */);
-    return request;
-}
-
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/Models.h b/neuralnetworks/1.0/vts/functional/Models.h
index 9398235..a1fbe92 100644
--- a/neuralnetworks/1.0/vts/functional/Models.h
+++ b/neuralnetworks/1.0/vts/functional/Models.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,29 +14,187 @@
  * limitations under the License.
  */
 
+#ifndef VTS_HAL_NEURALNETWORKS_V1_0_VTS_FUNCTIONAL_MODELS_H
+#define VTS_HAL_NEURALNETWORKS_V1_0_VTS_FUNCTIONAL_MODELS_H
+
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
-#include <android/hardware/neuralnetworks/1.1/types.h>
+#include "TestHarness.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
 
 namespace android {
 namespace hardware {
 namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
 
-// create V1_1 model
-V1_1::Model createValidTestModel_1_1();
-V1_1::Model createInvalidTestModel1_1_1();
-V1_1::Model createInvalidTestModel2_1_1();
+using MixedTypedExample = generated_tests::MixedTypedExampleType;
 
-// create V1_0 model
-V1_0::Model createValidTestModel_1_0();
-V1_0::Model createInvalidTestModel1_1_0();
-V1_0::Model createInvalidTestModel2_1_0();
+#define FOR_EACH_TEST_MODEL(FN)                          \
+    FN(add_broadcast_quant8)                             \
+    FN(add)                                              \
+    FN(add_quant8)                                       \
+    FN(avg_pool_float_1)                                 \
+    FN(avg_pool_float_2)                                 \
+    FN(avg_pool_float_3)                                 \
+    FN(avg_pool_float_4)                                 \
+    FN(avg_pool_float_5)                                 \
+    FN(avg_pool_quant8_1)                                \
+    FN(avg_pool_quant8_2)                                \
+    FN(avg_pool_quant8_3)                                \
+    FN(avg_pool_quant8_4)                                \
+    FN(avg_pool_quant8_5)                                \
+    FN(concat_float_1)                                   \
+    FN(concat_float_2)                                   \
+    FN(concat_float_3)                                   \
+    FN(concat_quant8_1)                                  \
+    FN(concat_quant8_2)                                  \
+    FN(concat_quant8_3)                                  \
+    FN(conv_1_h3_w2_SAME)                                \
+    FN(conv_1_h3_w2_VALID)                               \
+    FN(conv_3_h3_w2_SAME)                                \
+    FN(conv_3_h3_w2_VALID)                               \
+    FN(conv_float_2)                                     \
+    FN(conv_float_channels)                              \
+    FN(conv_float_channels_weights_as_inputs)            \
+    FN(conv_float_large)                                 \
+    FN(conv_float_large_weights_as_inputs)               \
+    FN(conv_float)                                       \
+    FN(conv_float_weights_as_inputs)                     \
+    FN(conv_quant8_2)                                    \
+    FN(conv_quant8_channels)                             \
+    FN(conv_quant8_channels_weights_as_inputs)           \
+    FN(conv_quant8_large)                                \
+    FN(conv_quant8_large_weights_as_inputs)              \
+    FN(conv_quant8)                                      \
+    FN(conv_quant8_overflow)                             \
+    FN(conv_quant8_overflow_weights_as_inputs)           \
+    FN(conv_quant8_weights_as_inputs)                    \
+    FN(depth_to_space_float_1)                           \
+    FN(depth_to_space_float_2)                           \
+    FN(depth_to_space_float_3)                           \
+    FN(depth_to_space_quant8_1)                          \
+    FN(depth_to_space_quant8_2)                          \
+    FN(depthwise_conv2d_float_2)                         \
+    FN(depthwise_conv2d_float_large_2)                   \
+    FN(depthwise_conv2d_float_large_2_weights_as_inputs) \
+    FN(depthwise_conv2d_float_large)                     \
+    FN(depthwise_conv2d_float_large_weights_as_inputs)   \
+    FN(depthwise_conv2d_float)                           \
+    FN(depthwise_conv2d_float_weights_as_inputs)         \
+    FN(depthwise_conv2d_quant8_2)                        \
+    FN(depthwise_conv2d_quant8_large)                    \
+    FN(depthwise_conv2d_quant8_large_weights_as_inputs)  \
+    FN(depthwise_conv2d_quant8)                          \
+    FN(depthwise_conv2d_quant8_weights_as_inputs)        \
+    FN(depthwise_conv)                                   \
+    FN(dequantize)                                       \
+    FN(embedding_lookup)                                 \
+    FN(floor)                                            \
+    FN(fully_connected_float_2)                          \
+    FN(fully_connected_float_large)                      \
+    FN(fully_connected_float_large_weights_as_inputs)    \
+    FN(fully_connected_float)                            \
+    FN(fully_connected_float_weights_as_inputs)          \
+    FN(fully_connected_quant8_2)                         \
+    FN(fully_connected_quant8_large)                     \
+    FN(fully_connected_quant8_large_weights_as_inputs)   \
+    FN(fully_connected_quant8)                           \
+    FN(fully_connected_quant8_weights_as_inputs)         \
+    FN(hashtable_lookup_float)                           \
+    FN(hashtable_lookup_quant8)                          \
+    FN(l2_normalization_2)                               \
+    FN(l2_normalization_large)                           \
+    FN(l2_normalization)                                 \
+    FN(l2_pool_float_2)                                  \
+    FN(l2_pool_float_large)                              \
+    FN(l2_pool_float)                                    \
+    FN(local_response_norm_float_1)                      \
+    FN(local_response_norm_float_2)                      \
+    FN(local_response_norm_float_3)                      \
+    FN(local_response_norm_float_4)                      \
+    FN(logistic_float_1)                                 \
+    FN(logistic_float_2)                                 \
+    FN(logistic_quant8_1)                                \
+    FN(logistic_quant8_2)                                \
+    FN(lsh_projection_2)                                 \
+    FN(lsh_projection)                                   \
+    FN(lsh_projection_weights_as_inputs)                 \
+    FN(lstm2)                                            \
+    FN(lstm2_state2)                                     \
+    FN(lstm2_state)                                      \
+    FN(lstm3)                                            \
+    FN(lstm3_state2)                                     \
+    FN(lstm3_state3)                                     \
+    FN(lstm3_state)                                      \
+    FN(lstm)                                             \
+    FN(lstm_state2)                                      \
+    FN(lstm_state)                                       \
+    FN(max_pool_float_1)                                 \
+    FN(max_pool_float_2)                                 \
+    FN(max_pool_float_3)                                 \
+    FN(max_pool_float_4)                                 \
+    FN(max_pool_quant8_1)                                \
+    FN(max_pool_quant8_2)                                \
+    FN(max_pool_quant8_3)                                \
+    FN(max_pool_quant8_4)                                \
+    FN(mobilenet_224_gender_basic_fixed)                 \
+    FN(mobilenet_quantized)                              \
+    FN(mul_broadcast_quant8)                             \
+    FN(mul)                                              \
+    FN(mul_quant8)                                       \
+    FN(mul_relu)                                         \
+    FN(relu1_float_1)                                    \
+    FN(relu1_float_2)                                    \
+    FN(relu1_quant8_1)                                   \
+    FN(relu1_quant8_2)                                   \
+    FN(relu6_float_1)                                    \
+    FN(relu6_float_2)                                    \
+    FN(relu6_quant8_1)                                   \
+    FN(relu6_quant8_2)                                   \
+    FN(relu_float_1)                                     \
+    FN(relu_float_2)                                     \
+    FN(relu_quant8_1)                                    \
+    FN(relu_quant8_2)                                    \
+    FN(reshape)                                          \
+    FN(reshape_quant8)                                   \
+    FN(reshape_quant8_weights_as_inputs)                 \
+    FN(reshape_weights_as_inputs)                        \
+    FN(resize_bilinear_2)                                \
+    FN(resize_bilinear)                                  \
+    FN(rnn)                                              \
+    FN(rnn_state)                                        \
+    FN(softmax_float_1)                                  \
+    FN(softmax_float_2)                                  \
+    FN(softmax_quant8_1)                                 \
+    FN(softmax_quant8_2)                                 \
+    FN(space_to_depth_float_1)                           \
+    FN(space_to_depth_float_2)                           \
+    FN(space_to_depth_float_3)                           \
+    FN(space_to_depth_quant8_1)                          \
+    FN(space_to_depth_quant8_2)                          \
+    FN(svdf2)                                            \
+    FN(svdf)                                             \
+    FN(svdf_state)                                       \
+    FN(tanh)
 
-// create the request
-V1_0::Request createValidTestRequest();
-V1_0::Request createInvalidTestRequest1();
-V1_0::Request createInvalidTestRequest2();
+#define FORWARD_DECLARE_GENERATED_OBJECTS(function) \
+    namespace function {                            \
+    extern std::vector<MixedTypedExample> examples; \
+    Model createTestModel();                        \
+    }
 
+FOR_EACH_TEST_MODEL(FORWARD_DECLARE_GENERATED_OBJECTS)
+
+#undef FORWARD_DECLARE_GENERATED_OBJECTS
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_0
 }  // namespace neuralnetworks
 }  // namespace hardware
 }  // namespace android
+
+#endif  // VTS_HAL_NEURALNETWORKS_V1_0_VTS_FUNCTIONAL_MODELS_H
diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
new file mode 100644
index 0000000..4f0697e
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
+                                           const V1_0::Model& model) {
+    SCOPED_TRACE(message + " [getSupportedOperations]");
+
+    Return<void> ret =
+        device->getSupportedOperations(model, [&](ErrorStatus status, const hidl_vec<bool>&) {
+            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+        });
+    EXPECT_TRUE(ret.isOk());
+}
+
+static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
+                                 const V1_0::Model& model) {
+    SCOPED_TRACE(message + " [prepareModel]");
+
+    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+    ASSERT_NE(nullptr, preparedModelCallback.get());
+    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
+    ASSERT_TRUE(prepareLaunchStatus.isOk());
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+    preparedModelCallback->wait();
+    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
+    sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+    ASSERT_EQ(nullptr, preparedModel.get());
+}
+
+// Primary validation function. This function will take a valid model, apply a
+// mutation to it to invalidate the model, then pass it to interface calls that
+// use the model. Note that the model here is passed by value, and any mutation
+// to the model does not leave this function.
+static void validate(const sp<IDevice>& device, const std::string& message, V1_0::Model model,
+                     const std::function<void(Model*)>& mutation) {
+    mutation(&model);
+    validateGetSupportedOperations(device, message, model);
+    validatePrepareModel(device, message, model);
+}
+
+// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
+// so this is efficiently accomplished by moving the element to the end and
+// resizing the hidl_vec to one less.
+template <typename Type>
+static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
+    if (vec) {
+        std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
+        vec->resize(vec->size() - 1);
+    }
+}
+
+template <typename Type>
+static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
+    // assume vec is valid
+    const uint32_t index = vec->size();
+    vec->resize(index + 1);
+    (*vec)[index] = value;
+    return index;
+}
+
+static uint32_t addOperand(Model* model) {
+    return hidl_vec_push_back(&model->operands,
+                              {
+                                  .type = OperandType::INT32,
+                                  .dimensions = {},
+                                  .numberOfConsumers = 0,
+                                  .scale = 0.0f,
+                                  .zeroPoint = 0,
+                                  .lifetime = OperandLifeTime::MODEL_INPUT,
+                                  .location = {.poolIndex = 0, .offset = 0, .length = 0},
+                              });
+}
+
+static uint32_t addOperand(Model* model, OperandLifeTime lifetime) {
+    uint32_t index = addOperand(model);
+    model->operands[index].numberOfConsumers = 1;
+    model->operands[index].lifetime = lifetime;
+    return index;
+}
+
+///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
+
+static const int32_t invalidOperandTypes[] = {
+    static_cast<int32_t>(OperandType::FLOAT32) - 1,              // lower bound fundamental
+    static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1,  // upper bound fundamental
+    static_cast<int32_t>(OperandType::OEM) - 1,                  // lower bound OEM
+    static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1,      // upper bound OEM
+};
+
+static void mutateOperandTypeTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        for (int32_t invalidOperandType : invalidOperandTypes) {
+            const std::string message = "mutateOperandTypeTest: operand " +
+                                        std::to_string(operand) + " set to value " +
+                                        std::to_string(invalidOperandType);
+            validate(device, message, model, [operand, invalidOperandType](Model* model) {
+                model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE OPERAND RANK /////////////////////////
+
+static uint32_t getInvalidRank(OperandType type) {
+    switch (type) {
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+            return 1;
+        case OperandType::TENSOR_FLOAT32:
+        case OperandType::TENSOR_INT32:
+        case OperandType::TENSOR_QUANT8_ASYMM:
+            return 0;
+        default:
+            return 0;
+    }
+}
+
+static void mutateOperandRankTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
+        const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
+                                    " has rank of " + std::to_string(invalidRank);
+        validate(device, message, model, [operand, invalidRank](Model* model) {
+            model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+        });
+    }
+}
+
+///////////////////////// VALIDATE OPERAND SCALE /////////////////////////
+
+static float getInvalidScale(OperandType type) {
+    switch (type) {
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+        case OperandType::TENSOR_FLOAT32:
+            return 1.0f;
+        case OperandType::TENSOR_INT32:
+            return -1.0f;
+        case OperandType::TENSOR_QUANT8_ASYMM:
+            return 0.0f;
+        default:
+            return 0.0f;
+    }
+}
+
+static void mutateOperandScaleTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const float invalidScale = getInvalidScale(model.operands[operand].type);
+        const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
+                                    " has scale of " + std::to_string(invalidScale);
+        validate(device, message, model, [operand, invalidScale](Model* model) {
+            model->operands[operand].scale = invalidScale;
+        });
+    }
+}
+
+///////////////////////// VALIDATE OPERAND ZERO POINT /////////////////////////
+
+static std::vector<int32_t> getInvalidZeroPoints(OperandType type) {
+    switch (type) {
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+        case OperandType::TENSOR_FLOAT32:
+        case OperandType::TENSOR_INT32:
+            return {1};
+        case OperandType::TENSOR_QUANT8_ASYMM:
+            return {-1, 256};
+        default:
+            return {};
+    }
+}
+
+static void mutateOperandZeroPointTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const std::vector<int32_t> invalidZeroPoints =
+            getInvalidZeroPoints(model.operands[operand].type);
+        for (int32_t invalidZeroPoint : invalidZeroPoints) {
+            const std::string message = "mutateOperandZeroPointTest: operand " +
+                                        std::to_string(operand) + " has zero point of " +
+                                        std::to_string(invalidZeroPoint);
+            validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
+                model->operands[operand].zeroPoint = invalidZeroPoint;
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE EXTRA ??? /////////////////////////
+
+// TODO: Operand::lifetime
+// TODO: Operand::location
+
+///////////////////////// VALIDATE OPERATION OPERAND TYPE /////////////////////////
+
+static void mutateOperand(Operand* operand, OperandType type) {
+    Operand newOperand = *operand;
+    newOperand.type = type;
+    switch (type) {
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+            newOperand.dimensions = hidl_vec<uint32_t>();
+            newOperand.scale = 0.0f;
+            newOperand.zeroPoint = 0;
+            break;
+        case OperandType::TENSOR_FLOAT32:
+            newOperand.dimensions =
+                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+            newOperand.scale = 0.0f;
+            newOperand.zeroPoint = 0;
+            break;
+        case OperandType::TENSOR_INT32:
+            newOperand.dimensions =
+                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+            newOperand.zeroPoint = 0;
+            break;
+        case OperandType::TENSOR_QUANT8_ASYMM:
+            newOperand.dimensions =
+                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+            newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
+            break;
+        case OperandType::OEM:
+        case OperandType::TENSOR_OEM_BYTE:
+        default:
+            break;
+    }
+    *operand = newOperand;
+}
+
+static bool mutateOperationOperandTypeSkip(size_t operand, const V1_0::Model& model) {
+    // LSH_PROJECTION's second argument is allowed to have any type. This is the
+    // only operation that currently has a type that can be anything independent
+    // from any other type. Changing the operand type to any other type will
+    // result in a valid model for LSH_PROJECTION. If this is the case, skip the
+    // test.
+    for (const Operation& operation : model.operations) {
+        if (operation.type == OperationType::LSH_PROJECTION && operand == operation.inputs[1]) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        if (mutateOperationOperandTypeSkip(operand, model)) {
+            continue;
+        }
+        for (OperandType invalidOperandType : hidl_enum_iterator<OperandType>{}) {
+            // Do not test OEM types
+            if (invalidOperandType == model.operands[operand].type ||
+                invalidOperandType == OperandType::OEM ||
+                invalidOperandType == OperandType::TENSOR_OEM_BYTE) {
+                continue;
+            }
+            const std::string message = "mutateOperationOperandTypeTest: operand " +
+                                        std::to_string(operand) + " set to type " +
+                                        toString(invalidOperandType);
+            validate(device, message, model, [operand, invalidOperandType](Model* model) {
+                mutateOperand(&model->operands[operand], invalidOperandType);
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
+
+static const int32_t invalidOperationTypes[] = {
+    static_cast<int32_t>(OperationType::ADD) - 1,            // lower bound fundamental
+    static_cast<int32_t>(OperationType::TANH) + 1,           // upper bound fundamental
+    static_cast<int32_t>(OperationType::OEM_OPERATION) - 1,  // lower bound OEM
+    static_cast<int32_t>(OperationType::OEM_OPERATION) + 1,  // upper bound OEM
+};
+
+static void mutateOperationTypeTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        for (int32_t invalidOperationType : invalidOperationTypes) {
+            const std::string message = "mutateOperationTypeTest: operation " +
+                                        std::to_string(operation) + " set to value " +
+                                        std::to_string(invalidOperationType);
+            validate(device, message, model, [operation, invalidOperationType](Model* model) {
+                model->operations[operation].type =
+                    static_cast<OperationType>(invalidOperationType);
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
+
+static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device,
+                                                 const V1_0::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const uint32_t invalidOperand = model.operands.size();
+        for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+            const std::string message = "mutateOperationInputOperandIndexTest: operation " +
+                                        std::to_string(operation) + " input " +
+                                        std::to_string(input);
+            validate(device, message, model, [operation, input, invalidOperand](Model* model) {
+                model->operations[operation].inputs[input] = invalidOperand;
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
+
+static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device,
+                                                  const V1_0::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const uint32_t invalidOperand = model.operands.size();
+        for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+            const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
+                                        std::to_string(operation) + " output " +
+                                        std::to_string(output);
+            validate(device, message, model, [operation, output, invalidOperand](Model* model) {
+                model->operations[operation].outputs[output] = invalidOperand;
+            });
+        }
+    }
+}
+
+///////////////////////// REMOVE OPERAND FROM EVERYTHING /////////////////////////
+
+static void removeValueAndDecrementGreaterValues(hidl_vec<uint32_t>* vec, uint32_t value) {
+    if (vec) {
+        // remove elements matching "value"
+        auto last = std::remove(vec->begin(), vec->end(), value);
+        vec->resize(std::distance(vec->begin(), last));
+
+        // decrement elements exceeding "value"
+        std::transform(vec->begin(), vec->end(), vec->begin(),
+                       [value](uint32_t v) { return v > value ? v-- : v; });
+    }
+}
+
+static void removeOperand(Model* model, uint32_t index) {
+    hidl_vec_removeAt(&model->operands, index);
+    for (Operation& operation : model->operations) {
+        removeValueAndDecrementGreaterValues(&operation.inputs, index);
+        removeValueAndDecrementGreaterValues(&operation.outputs, index);
+    }
+    removeValueAndDecrementGreaterValues(&model->inputIndexes, index);
+    removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
+}
+
+static void removeOperandTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const std::string message = "removeOperandTest: operand " + std::to_string(operand);
+        validate(device, message, model,
+                 [operand](Model* model) { removeOperand(model, operand); });
+    }
+}
+
+///////////////////////// REMOVE OPERATION /////////////////////////
+
+static void removeOperation(Model* model, uint32_t index) {
+    for (uint32_t operand : model->operations[index].inputs) {
+        model->operands[operand].numberOfConsumers--;
+    }
+    hidl_vec_removeAt(&model->operations, index);
+}
+
+static void removeOperationTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const std::string message = "removeOperationTest: operation " + std::to_string(operation);
+        validate(device, message, model,
+                 [operation](Model* model) { removeOperation(model, operation); });
+    }
+}
+
+///////////////////////// REMOVE OPERATION INPUT /////////////////////////
+
+static void removeOperationInputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+            const V1_0::Operation& op = model.operations[operation];
+            // CONCATENATION has at least 2 inputs, with the last element being
+            // INT32. Skip this test if removing one of CONCATENATION's
+            // inputs still produces a valid model.
+            if (op.type == V1_0::OperationType::CONCATENATION && op.inputs.size() > 2 &&
+                input != op.inputs.size() - 1) {
+                continue;
+            }
+            const std::string message = "removeOperationInputTest: operation " +
+                                        std::to_string(operation) + ", input " +
+                                        std::to_string(input);
+            validate(device, message, model, [operation, input](Model* model) {
+                uint32_t operand = model->operations[operation].inputs[input];
+                model->operands[operand].numberOfConsumers--;
+                hidl_vec_removeAt(&model->operations[operation].inputs, input);
+            });
+        }
+    }
+}
+
+///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
+
+static void removeOperationOutputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+            const std::string message = "removeOperationOutputTest: operation " +
+                                        std::to_string(operation) + ", output " +
+                                        std::to_string(output);
+            validate(device, message, model, [operation, output](Model* model) {
+                hidl_vec_removeAt(&model->operations[operation].outputs, output);
+            });
+        }
+    }
+}
+
+///////////////////////// MODEL VALIDATION /////////////////////////
+
+// TODO: remove model input
+// TODO: remove model output
+// TODO: add unused operation
+
+///////////////////////// ADD OPERATION INPUT /////////////////////////
+
+static void addOperationInputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
+        validate(device, message, model, [operation](Model* model) {
+            uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
+            hidl_vec_push_back(&model->operations[operation].inputs, index);
+            hidl_vec_push_back(&model->inputIndexes, index);
+        });
+    }
+}
+
+///////////////////////// ADD OPERATION OUTPUT /////////////////////////
+
+static void addOperationOutputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const std::string message =
+            "addOperationOutputTest: operation " + std::to_string(operation);
+        validate(device, message, model, [operation](Model* model) {
+            uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
+            hidl_vec_push_back(&model->operations[operation].outputs, index);
+            hidl_vec_push_back(&model->outputIndexes, index);
+        });
+    }
+}
+
+////////////////////////// ENTRY POINT //////////////////////////////
+
+void ValidationTest::validateModel(const V1_0::Model& model) {
+    mutateOperandTypeTest(device, model);
+    mutateOperandRankTest(device, model);
+    mutateOperandScaleTest(device, model);
+    mutateOperandZeroPointTest(device, model);
+    mutateOperationOperandTypeTest(device, model);
+    mutateOperationTypeTest(device, model);
+    mutateOperationInputOperandIndexTest(device, model);
+    mutateOperationOutputOperandIndexTest(device, model);
+    removeOperandTest(device, model);
+    removeOperationTest(device, model);
+    removeOperationInputTest(device, model);
+    removeOperationOutputTest(device, model);
+    addOperationInputTest(device, model);
+    addOperationOutputTest(device, model);
+}
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
new file mode 100644
index 0000000..08f2613
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::hidl::memory::V1_0::IMemory;
+using generated_tests::MixedTyped;
+using generated_tests::MixedTypedExampleType;
+using generated_tests::for_all;
+
+///////////////////////// 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
+// mutation to the request does not leave this function.
+static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
+                     Request request, const std::function<void(Request*)>& mutation) {
+    mutation(&request);
+    SCOPED_TRACE(message + " [execute]");
+
+    sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+    ASSERT_NE(nullptr, executionCallback.get());
+    Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
+    ASSERT_TRUE(executeLaunchStatus.isOk());
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
+
+    executionCallback->wait();
+    ErrorStatus executionReturnStatus = executionCallback->getStatus();
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
+}
+
+// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
+// so this is efficiently accomplished by moving the element to the end and
+// resizing the hidl_vec to one less.
+template <typename Type>
+static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
+    if (vec) {
+        std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
+        vec->resize(vec->size() - 1);
+    }
+}
+
+template <typename Type>
+static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
+    // assume vec is valid
+    const uint32_t index = vec->size();
+    vec->resize(index + 1);
+    (*vec)[index] = value;
+    return index;
+}
+
+///////////////////////// REMOVE INPUT ////////////////////////////////////
+
+static void removeInputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    for (size_t input = 0; input < request.inputs.size(); ++input) {
+        const std::string message = "removeInput: removed input " + std::to_string(input);
+        validate(preparedModel, message, request,
+                 [input](Request* request) { hidl_vec_removeAt(&request->inputs, input); });
+    }
+}
+
+///////////////////////// REMOVE OUTPUT ////////////////////////////////////
+
+static void removeOutputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    for (size_t output = 0; output < request.outputs.size(); ++output) {
+        const std::string message = "removeOutput: removed Output " + std::to_string(output);
+        validate(preparedModel, message, request,
+                 [output](Request* request) { hidl_vec_removeAt(&request->outputs, output); });
+    }
+}
+
+///////////////////////////// ENTRY POINT //////////////////////////////////
+
+std::vector<Request> createRequests(const std::vector<MixedTypedExampleType>& examples) {
+    const uint32_t INPUT = 0;
+    const uint32_t OUTPUT = 1;
+
+    std::vector<Request> requests;
+
+    for (auto& example : examples) {
+        const MixedTyped& inputs = example.first;
+        const MixedTyped& outputs = example.second;
+
+        std::vector<RequestArgument> inputs_info, outputs_info;
+        uint32_t inputSize = 0, outputSize = 0;
+
+        // This function only partially specifies the metadata (vector of RequestArguments).
+        // The contents are copied over below.
+        for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
+            if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
+            RequestArgument arg = {
+                .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
+                .dimensions = {},
+            };
+            RequestArgument arg_empty = {
+                .hasNoValue = true,
+            };
+            inputs_info[index] = s ? arg : arg_empty;
+            inputSize += s;
+        });
+        // Compute offset for inputs 1 and so on
+        {
+            size_t offset = 0;
+            for (auto& i : inputs_info) {
+                if (!i.hasNoValue) i.location.offset = offset;
+                offset += i.location.length;
+            }
+        }
+
+        // Go through all outputs, initialize RequestArgument descriptors
+        for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
+            if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
+            RequestArgument arg = {
+                .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
+                .dimensions = {},
+            };
+            outputs_info[index] = arg;
+            outputSize += s;
+        });
+        // Compute offset for outputs 1 and so on
+        {
+            size_t offset = 0;
+            for (auto& i : outputs_info) {
+                i.location.offset = offset;
+                offset += i.location.length;
+            }
+        }
+        std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
+                                          nn::allocateSharedMemory(outputSize)};
+        if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
+            return {};
+        }
+
+        // map pool
+        sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
+        if (inputMemory == nullptr) {
+            return {};
+        }
+        char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
+        if (inputPtr == nullptr) {
+            return {};
+        }
+
+        // initialize pool
+        inputMemory->update();
+        for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
+            char* begin = (char*)p;
+            char* end = begin + s;
+            // TODO: handle more than one input
+            std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
+        });
+        inputMemory->commit();
+
+        requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
+    }
+
+    return requests;
+}
+
+void ValidationTest::validateRequests(const V1_0::Model& model,
+                                      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);
+        removeOutputTest(preparedModel, request);
+    }
+}
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/ValidationTests.cpp b/neuralnetworks/1.0/vts/functional/ValidationTests.cpp
new file mode 100644
index 0000000..98fc1c5
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/ValidationTests.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "Models.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+// forward declarations
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
+
+// generate validation tests
+#define VTS_CURRENT_TEST_CASE(TestName)                                           \
+    TEST_F(ValidationTest, TestName) {                                            \
+        const Model model = TestName::createTestModel();                          \
+        const std::vector<Request> requests = createRequests(TestName::examples); \
+        validateModel(model);                                                     \
+        validateRequests(model, requests);                                        \
+    }
+
+FOR_EACH_TEST_MODEL(VTS_CURRENT_TEST_CASE)
+
+#undef VTS_CURRENT_TEST_CASE
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
similarity index 64%
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.cpp
rename to neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
index b14fb2c..1ff3b66 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
@@ -16,15 +16,7 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
-#include "VtsHalNeuralnetworksV1_0.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-
-using ::android::hardware::hidl_memory;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
+#include "VtsHalNeuralnetworks.h"
 
 namespace android {
 namespace hardware {
@@ -33,11 +25,6 @@
 namespace vts {
 namespace functional {
 
-// allocator helper
-hidl_memory allocateSharedMemory(int64_t size) {
-    return nn::allocateSharedMemory(size);
-}
-
 // A class for test environment setup
 NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
 
@@ -51,23 +38,49 @@
 }
 
 void NeuralnetworksHidlEnvironment::registerTestServices() {
-    registerTestService<V1_0::IDevice>();
+    registerTestService<IDevice>();
 }
 
 // The main test class for NEURALNETWORK HIDL HAL.
+NeuralnetworksHidlTest::NeuralnetworksHidlTest() {}
+
 NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
 
 void NeuralnetworksHidlTest::SetUp() {
-    device = ::testing::VtsHalHidlTargetTestBase::getService<V1_0::IDevice>(
+    ::testing::VtsHalHidlTargetTestBase::SetUp();
+    device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
         NeuralnetworksHidlEnvironment::getInstance());
     ASSERT_NE(nullptr, device.get());
 }
 
-void NeuralnetworksHidlTest::TearDown() {}
+void NeuralnetworksHidlTest::TearDown() {
+    device = nullptr;
+    ::testing::VtsHalHidlTargetTestBase::TearDown();
+}
 
 }  // namespace functional
 }  // namespace vts
+
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) {
+    return os << toString(errorStatus);
+}
+
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) {
+    return os << toString(deviceStatus);
+}
+
 }  // namespace V1_0
 }  // namespace neuralnetworks
 }  // namespace hardware
 }  // namespace android
+
+using android::hardware::neuralnetworks::V1_0::vts::functional::NeuralnetworksHidlEnvironment;
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
+    ::testing::InitGoogleTest(&argc, argv);
+    NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
+
+    int status = RUN_ALL_TESTS();
+    return status;
+}
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
similarity index 60%
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.h
rename to neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
index fbb1607..e79129b 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.h
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
@@ -18,16 +18,15 @@
 #define VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
 
 #include <android/hardware/neuralnetworks/1.0/IDevice.h>
-#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
 #include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
+
+#include <android-base/macros.h>
 #include <gtest/gtest.h>
-#include <string>
+#include <iostream>
+#include <vector>
 
 namespace android {
 namespace hardware {
@@ -36,47 +35,47 @@
 namespace vts {
 namespace functional {
 
-hidl_memory allocateSharedMemory(int64_t size);
-
 // A class for test environment setup
 class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
     NeuralnetworksHidlEnvironment();
-    NeuralnetworksHidlEnvironment(const NeuralnetworksHidlEnvironment&) = delete;
-    NeuralnetworksHidlEnvironment(NeuralnetworksHidlEnvironment&&) = delete;
-    NeuralnetworksHidlEnvironment& operator=(const NeuralnetworksHidlEnvironment&) = delete;
-    NeuralnetworksHidlEnvironment& operator=(NeuralnetworksHidlEnvironment&&) = delete;
+    ~NeuralnetworksHidlEnvironment() override;
 
    public:
-    ~NeuralnetworksHidlEnvironment() override;
     static NeuralnetworksHidlEnvironment* getInstance();
     void registerTestServices() override;
 };
 
 // The main test class for NEURALNETWORKS HIDL HAL.
 class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
+
    public:
+    NeuralnetworksHidlTest();
     ~NeuralnetworksHidlTest() override;
     void SetUp() override;
     void TearDown() override;
 
-    sp<V1_0::IDevice> device;
+   protected:
+    sp<IDevice> device;
 };
+
+// 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);
+};
+
+// Tag for the generated tests
+class GeneratedTest : public NeuralnetworksHidlTest {};
+
 }  // namespace functional
 }  // namespace vts
 
 // pretty-print values for error messages
-
-template <typename CharT, typename Traits>
-::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
-                                                V1_0::ErrorStatus errorStatus) {
-    return os << toString(errorStatus);
-}
-
-template <typename CharT, typename Traits>
-::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
-                                                V1_0::DeviceStatus deviceStatus) {
-    return os << toString(deviceStatus);
-}
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus);
 
 }  // namespace V1_0
 }  // namespace neuralnetworks
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0BasicTest.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0BasicTest.cpp
deleted file mode 100644
index 59e5b80..0000000
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0BasicTest.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworksV1_0.h"
-
-#include "Callbacks.h"
-#include "Models.h"
-#include "TestHarness.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-using ::android::hardware::neuralnetworks::V1_0::IDevice;
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Capabilities;
-using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
-using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
-using ::android::hardware::neuralnetworks::V1_0::Model;
-using ::android::hardware::neuralnetworks::V1_0::OperationType;
-using ::android::hardware::neuralnetworks::V1_0::PerformanceInfo;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
-using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-
-static void doPrepareModelShortcut(const sp<IDevice>& device, sp<IPreparedModel>* preparedModel) {
-    ASSERT_NE(nullptr, preparedModel);
-    Model model = createValidTestModel_1_0();
-
-    // 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: 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;
-    }
-    ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
-    ASSERT_NE(nullptr, preparedModel->get());
-}
-
-// create device test
-TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
-
-// status test
-TEST_F(NeuralnetworksHidlTest, StatusTest) {
-    Return<DeviceStatus> status = device->getStatus();
-    ASSERT_TRUE(status.isOk());
-    EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
-}
-
-// initialization
-TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
-    Return<void> ret =
-        device->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) {
-            EXPECT_EQ(ErrorStatus::NONE, status);
-            EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
-            EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
-            EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
-            EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
-        });
-    EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations positive test
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsPositiveTest) {
-    Model model = createValidTestModel_1_0();
-    Return<void> ret = device->getSupportedOperations(
-        model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
-            EXPECT_EQ(ErrorStatus::NONE, status);
-            EXPECT_EQ(model.operations.size(), supported.size());
-        });
-    EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations negative test 1
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest1) {
-    Model model = createInvalidTestModel1_1_0();
-    Return<void> ret = device->getSupportedOperations(
-        model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
-            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
-            (void)supported;
-        });
-    EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations negative test 2
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest2) {
-    Model model = createInvalidTestModel2_1_0();
-    Return<void> ret = device->getSupportedOperations(
-        model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
-            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
-            (void)supported;
-        });
-    EXPECT_TRUE(ret.isOk());
-}
-
-// prepare simple model positive test
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelPositiveTest) {
-    sp<IPreparedModel> preparedModel;
-    doPrepareModelShortcut(device, &preparedModel);
-}
-
-// prepare simple model negative test 1
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest1) {
-    Model model = createInvalidTestModel1_1_0();
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk());
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
-
-    preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
-    sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
-    EXPECT_EQ(nullptr, preparedModel.get());
-}
-
-// prepare simple model negative test 2
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest2) {
-    Model model = createInvalidTestModel2_1_0();
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk());
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
-
-    preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
-    sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
-    EXPECT_EQ(nullptr, preparedModel.get());
-}
-
-// execute simple graph positive test
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphPositiveTest) {
-    std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
-    std::vector<float> expectedData = {6.0f, 8.0f, 10.0f, 12.0f};
-    const uint32_t OUTPUT = 1;
-
-    sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
-    Request request = createValidTestRequest();
-
-    auto postWork = [&] {
-        sp<IMemory> outputMemory = mapMemory(request.pools[OUTPUT]);
-        if (outputMemory == nullptr) {
-            return false;
-        }
-        float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
-        if (outputPtr == nullptr) {
-            return false;
-        }
-        outputMemory->read();
-        std::copy(outputPtr, outputPtr + outputData.size(), outputData.begin());
-        outputMemory->commit();
-        return true;
-    };
-
-    sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-    ASSERT_NE(nullptr, executionCallback.get());
-    executionCallback->on_finish(postWork);
-    Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
-    ASSERT_TRUE(executeLaunchStatus.isOk());
-    EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executeLaunchStatus));
-
-    executionCallback->wait();
-    ErrorStatus executionReturnStatus = executionCallback->getStatus();
-    EXPECT_EQ(ErrorStatus::NONE, executionReturnStatus);
-    EXPECT_EQ(expectedData, outputData);
-}
-
-// execute simple graph negative test 1
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest1) {
-    sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
-    Request request = createInvalidTestRequest1();
-
-    sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-    ASSERT_NE(nullptr, executionCallback.get());
-    Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
-    ASSERT_TRUE(executeLaunchStatus.isOk());
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
-
-    executionCallback->wait();
-    ErrorStatus executionReturnStatus = executionCallback->getStatus();
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
-}
-
-// execute simple graph negative test 2
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest2) {
-    sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
-    Request request = createInvalidTestRequest2();
-
-    sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-    ASSERT_NE(nullptr, executionCallback.get());
-    Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
-    ASSERT_TRUE(executeLaunchStatus.isOk());
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
-
-    executionCallback->wait();
-    ErrorStatus executionReturnStatus = executionCallback->getStatus();
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
-}
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_0
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
-
-using android::hardware::neuralnetworks::V1_0::vts::functional::NeuralnetworksHidlEnvironment;
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
-    ::testing::InitGoogleTest(&argc, argv);
-    NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
-
-    int status = RUN_ALL_TESTS();
-    return status;
-}
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 947ca2c..f755c20 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -17,9 +17,12 @@
 cc_test {
     name: "VtsHalNeuralnetworksV1_1TargetTest",
     srcs: [
-        "VtsHalNeuralnetworksV1_1.cpp",
-        "VtsHalNeuralnetworksV1_1BasicTest.cpp",
-        "VtsHalNeuralnetworksV1_1GeneratedTest.cpp",
+        "BasicTests.cpp",
+        "GeneratedTests.cpp",
+        "ValidateModel.cpp",
+        "ValidateRequest.cpp",
+        "ValidationTests.cpp",
+        "VtsHalNeuralnetworks.cpp",
     ],
     defaults: ["VtsHalTargetTestDefaults"],
     static_libs: [
diff --git a/neuralnetworks/1.1/vts/functional/BasicTests.cpp b/neuralnetworks/1.1/vts/functional/BasicTests.cpp
new file mode 100644
index 0000000..ed59a2d
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/BasicTests.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+// create device test
+TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
+
+// status test
+TEST_F(NeuralnetworksHidlTest, StatusTest) {
+    Return<DeviceStatus> status = device->getStatus();
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
+}
+
+// initialization
+TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+    Return<void> ret =
+        device->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) {
+            EXPECT_EQ(ErrorStatus::NONE, status);
+            EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
+            EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
+            EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
+            EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
+            EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.execTime);
+            EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.powerUsage);
+        });
+    EXPECT_TRUE(ret.isOk());
+}
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_1
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
new file mode 100644
index 0000000..1f1cc7a
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+
+namespace generated_tests {
+using ::generated_tests::MixedTypedExampleType;
+extern void Execute(const sp<V1_1::IDevice>&, std::function<V1_1::Model(void)>,
+                    std::function<bool(int)>, const std::vector<MixedTypedExampleType>&);
+}  // namespace generated_tests
+
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::nn::allocateSharedMemory;
+
+// Mixed-typed examples
+typedef generated_tests::MixedTypedExampleType MixedTypedExample;
+
+// in frameworks/ml/nn/runtime/tests/generated/
+#include "all_generated_V1_0_vts_tests.cpp"
+#include "all_generated_V1_1_vts_tests.cpp"
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_1
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/Models.h b/neuralnetworks/1.1/vts/functional/Models.h
new file mode 100644
index 0000000..c3cadb5
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/Models.h
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VTS_HAL_NEURALNETWORKS_V1_1_VTS_FUNCTIONAL_MODELS_H
+#define VTS_HAL_NEURALNETWORKS_V1_1_VTS_FUNCTIONAL_MODELS_H
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "TestHarness.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+using MixedTypedExample = generated_tests::MixedTypedExampleType;
+
+#define FOR_EACH_TEST_MODEL(FN)                                \
+    FN(add)                                                    \
+    FN(add_broadcast_quant8)                                   \
+    FN(add_quant8)                                             \
+    FN(add_relaxed)                                            \
+    FN(avg_pool_float_1)                                       \
+    FN(avg_pool_float_1_relaxed)                               \
+    FN(avg_pool_float_2)                                       \
+    FN(avg_pool_float_2_relaxed)                               \
+    FN(avg_pool_float_3)                                       \
+    FN(avg_pool_float_3_relaxed)                               \
+    FN(avg_pool_float_4)                                       \
+    FN(avg_pool_float_4_relaxed)                               \
+    FN(avg_pool_float_5)                                       \
+    FN(avg_pool_quant8_1)                                      \
+    FN(avg_pool_quant8_2)                                      \
+    FN(avg_pool_quant8_3)                                      \
+    FN(avg_pool_quant8_4)                                      \
+    FN(avg_pool_quant8_5)                                      \
+    FN(batch_to_space)                                         \
+    FN(batch_to_space_float_1)                                 \
+    FN(batch_to_space_quant8_1)                                \
+    FN(concat_float_1)                                         \
+    FN(concat_float_1_relaxed)                                 \
+    FN(concat_float_2)                                         \
+    FN(concat_float_2_relaxed)                                 \
+    FN(concat_float_3)                                         \
+    FN(concat_float_3_relaxed)                                 \
+    FN(concat_quant8_1)                                        \
+    FN(concat_quant8_2)                                        \
+    FN(concat_quant8_3)                                        \
+    FN(conv_1_h3_w2_SAME)                                      \
+    FN(conv_1_h3_w2_SAME_relaxed)                              \
+    FN(conv_1_h3_w2_VALID)                                     \
+    FN(conv_1_h3_w2_VALID_relaxed)                             \
+    FN(conv_3_h3_w2_SAME)                                      \
+    FN(conv_3_h3_w2_SAME_relaxed)                              \
+    FN(conv_3_h3_w2_VALID)                                     \
+    FN(conv_3_h3_w2_VALID_relaxed)                             \
+    FN(conv_float)                                             \
+    FN(conv_float_2)                                           \
+    FN(conv_float_channels)                                    \
+    FN(conv_float_channels_relaxed)                            \
+    FN(conv_float_channels_weights_as_inputs)                  \
+    FN(conv_float_channels_weights_as_inputs_relaxed)          \
+    FN(conv_float_large)                                       \
+    FN(conv_float_large_relaxed)                               \
+    FN(conv_float_large_weights_as_inputs)                     \
+    FN(conv_float_large_weights_as_inputs_relaxed)             \
+    FN(conv_float_relaxed)                                     \
+    FN(conv_float_weights_as_inputs)                           \
+    FN(conv_float_weights_as_inputs_relaxed)                   \
+    FN(conv_quant8)                                            \
+    FN(conv_quant8_2)                                          \
+    FN(conv_quant8_channels)                                   \
+    FN(conv_quant8_channels_weights_as_inputs)                 \
+    FN(conv_quant8_large)                                      \
+    FN(conv_quant8_large_weights_as_inputs)                    \
+    FN(conv_quant8_overflow)                                   \
+    FN(conv_quant8_overflow_weights_as_inputs)                 \
+    FN(conv_quant8_weights_as_inputs)                          \
+    FN(depth_to_space_float_1)                                 \
+    FN(depth_to_space_float_1_relaxed)                         \
+    FN(depth_to_space_float_2)                                 \
+    FN(depth_to_space_float_2_relaxed)                         \
+    FN(depth_to_space_float_3)                                 \
+    FN(depth_to_space_float_3_relaxed)                         \
+    FN(depth_to_space_quant8_1)                                \
+    FN(depth_to_space_quant8_2)                                \
+    FN(depthwise_conv)                                         \
+    FN(depthwise_conv2d_float)                                 \
+    FN(depthwise_conv2d_float_2)                               \
+    FN(depthwise_conv2d_float_large)                           \
+    FN(depthwise_conv2d_float_large_2)                         \
+    FN(depthwise_conv2d_float_large_2_weights_as_inputs)       \
+    FN(depthwise_conv2d_float_large_relaxed)                   \
+    FN(depthwise_conv2d_float_large_weights_as_inputs)         \
+    FN(depthwise_conv2d_float_large_weights_as_inputs_relaxed) \
+    FN(depthwise_conv2d_float_weights_as_inputs)               \
+    FN(depthwise_conv2d_quant8)                                \
+    FN(depthwise_conv2d_quant8_2)                              \
+    FN(depthwise_conv2d_quant8_large)                          \
+    FN(depthwise_conv2d_quant8_large_weights_as_inputs)        \
+    FN(depthwise_conv2d_quant8_weights_as_inputs)              \
+    FN(depthwise_conv_relaxed)                                 \
+    FN(dequantize)                                             \
+    FN(div)                                                    \
+    FN(embedding_lookup)                                       \
+    FN(embedding_lookup_relaxed)                               \
+    FN(floor)                                                  \
+    FN(floor_relaxed)                                          \
+    FN(fully_connected_float)                                  \
+    FN(fully_connected_float_2)                                \
+    FN(fully_connected_float_large)                            \
+    FN(fully_connected_float_large_weights_as_inputs)          \
+    FN(fully_connected_float_relaxed)                          \
+    FN(fully_connected_float_weights_as_inputs)                \
+    FN(fully_connected_float_weights_as_inputs_relaxed)        \
+    FN(fully_connected_quant8)                                 \
+    FN(fully_connected_quant8_2)                               \
+    FN(fully_connected_quant8_large)                           \
+    FN(fully_connected_quant8_large_weights_as_inputs)         \
+    FN(fully_connected_quant8_weights_as_inputs)               \
+    FN(hashtable_lookup_float)                                 \
+    FN(hashtable_lookup_float_relaxed)                         \
+    FN(hashtable_lookup_quant8)                                \
+    FN(l2_normalization)                                       \
+    FN(l2_normalization_2)                                     \
+    FN(l2_normalization_large)                                 \
+    FN(l2_normalization_large_relaxed)                         \
+    FN(l2_normalization_relaxed)                               \
+    FN(l2_pool_float)                                          \
+    FN(l2_pool_float_2)                                        \
+    FN(l2_pool_float_large)                                    \
+    FN(l2_pool_float_relaxed)                                  \
+    FN(local_response_norm_float_1)                            \
+    FN(local_response_norm_float_1_relaxed)                    \
+    FN(local_response_norm_float_2)                            \
+    FN(local_response_norm_float_2_relaxed)                    \
+    FN(local_response_norm_float_3)                            \
+    FN(local_response_norm_float_3_relaxed)                    \
+    FN(local_response_norm_float_4)                            \
+    FN(local_response_norm_float_4_relaxed)                    \
+    FN(logistic_float_1)                                       \
+    FN(logistic_float_1_relaxed)                               \
+    FN(logistic_float_2)                                       \
+    FN(logistic_float_2_relaxed)                               \
+    FN(logistic_quant8_1)                                      \
+    FN(logistic_quant8_2)                                      \
+    FN(lsh_projection)                                         \
+    FN(lsh_projection_2)                                       \
+    FN(lsh_projection_2_relaxed)                               \
+    FN(lsh_projection_relaxed)                                 \
+    FN(lsh_projection_weights_as_inputs)                       \
+    FN(lsh_projection_weights_as_inputs_relaxed)               \
+    FN(lstm)                                                   \
+    FN(lstm2)                                                  \
+    FN(lstm2_relaxed)                                          \
+    FN(lstm2_state)                                            \
+    FN(lstm2_state2)                                           \
+    FN(lstm2_state2_relaxed)                                   \
+    FN(lstm2_state_relaxed)                                    \
+    FN(lstm3)                                                  \
+    FN(lstm3_relaxed)                                          \
+    FN(lstm3_state)                                            \
+    FN(lstm3_state2)                                           \
+    FN(lstm3_state2_relaxed)                                   \
+    FN(lstm3_state3)                                           \
+    FN(lstm3_state3_relaxed)                                   \
+    FN(lstm3_state_relaxed)                                    \
+    FN(lstm_relaxed)                                           \
+    FN(lstm_state)                                             \
+    FN(lstm_state2)                                            \
+    FN(lstm_state2_relaxed)                                    \
+    FN(lstm_state_relaxed)                                     \
+    FN(max_pool_float_1)                                       \
+    FN(max_pool_float_1_relaxed)                               \
+    FN(max_pool_float_2)                                       \
+    FN(max_pool_float_2_relaxed)                               \
+    FN(max_pool_float_3)                                       \
+    FN(max_pool_float_3_relaxed)                               \
+    FN(max_pool_float_4)                                       \
+    FN(max_pool_quant8_1)                                      \
+    FN(max_pool_quant8_2)                                      \
+    FN(max_pool_quant8_3)                                      \
+    FN(max_pool_quant8_4)                                      \
+    FN(mean)                                                   \
+    FN(mean_float_1)                                           \
+    FN(mean_float_2)                                           \
+    FN(mean_quant8_1)                                          \
+    FN(mean_quant8_2)                                          \
+    FN(mobilenet_224_gender_basic_fixed)                       \
+    FN(mobilenet_224_gender_basic_fixed_relaxed)               \
+    FN(mobilenet_quantized)                                    \
+    FN(mul)                                                    \
+    FN(mul_broadcast_quant8)                                   \
+    FN(mul_quant8)                                             \
+    FN(mul_relaxed)                                            \
+    FN(mul_relu)                                               \
+    FN(mul_relu_relaxed)                                       \
+    FN(pad)                                                    \
+    FN(pad_float_1)                                            \
+    FN(relu1_float_1)                                          \
+    FN(relu1_float_1_relaxed)                                  \
+    FN(relu1_float_2)                                          \
+    FN(relu1_float_2_relaxed)                                  \
+    FN(relu1_quant8_1)                                         \
+    FN(relu1_quant8_2)                                         \
+    FN(relu6_float_1)                                          \
+    FN(relu6_float_1_relaxed)                                  \
+    FN(relu6_float_2)                                          \
+    FN(relu6_float_2_relaxed)                                  \
+    FN(relu6_quant8_1)                                         \
+    FN(relu6_quant8_2)                                         \
+    FN(relu_float_1)                                           \
+    FN(relu_float_1_relaxed)                                   \
+    FN(relu_float_2)                                           \
+    FN(relu_quant8_1)                                          \
+    FN(relu_quant8_2)                                          \
+    FN(reshape)                                                \
+    FN(reshape_quant8)                                         \
+    FN(reshape_quant8_weights_as_inputs)                       \
+    FN(reshape_relaxed)                                        \
+    FN(reshape_weights_as_inputs)                              \
+    FN(reshape_weights_as_inputs_relaxed)                      \
+    FN(resize_bilinear)                                        \
+    FN(resize_bilinear_2)                                      \
+    FN(resize_bilinear_relaxed)                                \
+    FN(rnn)                                                    \
+    FN(rnn_relaxed)                                            \
+    FN(rnn_state)                                              \
+    FN(rnn_state_relaxed)                                      \
+    FN(softmax_float_1)                                        \
+    FN(softmax_float_1_relaxed)                                \
+    FN(softmax_float_2)                                        \
+    FN(softmax_float_2_relaxed)                                \
+    FN(softmax_quant8_1)                                       \
+    FN(softmax_quant8_2)                                       \
+    FN(space_to_batch)                                         \
+    FN(space_to_batch_float_1)                                 \
+    FN(space_to_batch_float_2)                                 \
+    FN(space_to_batch_float_3)                                 \
+    FN(space_to_batch_quant8_1)                                \
+    FN(space_to_batch_quant8_2)                                \
+    FN(space_to_batch_quant8_3)                                \
+    FN(space_to_depth_float_1)                                 \
+    FN(space_to_depth_float_1_relaxed)                         \
+    FN(space_to_depth_float_2)                                 \
+    FN(space_to_depth_float_2_relaxed)                         \
+    FN(space_to_depth_float_3)                                 \
+    FN(space_to_depth_float_3_relaxed)                         \
+    FN(space_to_depth_quant8_1)                                \
+    FN(space_to_depth_quant8_2)                                \
+    FN(squeeze)                                                \
+    FN(squeeze_float_1)                                        \
+    FN(squeeze_quant8_1)                                       \
+    FN(strided_slice)                                          \
+    FN(strided_slice_float_1)                                  \
+    FN(strided_slice_float_10)                                 \
+    FN(strided_slice_float_2)                                  \
+    FN(strided_slice_float_3)                                  \
+    FN(strided_slice_float_4)                                  \
+    FN(strided_slice_float_5)                                  \
+    FN(strided_slice_float_6)                                  \
+    FN(strided_slice_float_7)                                  \
+    FN(strided_slice_float_8)                                  \
+    FN(strided_slice_float_9)                                  \
+    FN(strided_slice_qaunt8_10)                                \
+    FN(strided_slice_quant8_1)                                 \
+    FN(strided_slice_quant8_2)                                 \
+    FN(strided_slice_quant8_3)                                 \
+    FN(strided_slice_quant8_4)                                 \
+    FN(strided_slice_quant8_5)                                 \
+    FN(strided_slice_quant8_6)                                 \
+    FN(strided_slice_quant8_7)                                 \
+    FN(strided_slice_quant8_8)                                 \
+    FN(strided_slice_quant8_9)                                 \
+    FN(sub)                                                    \
+    FN(svdf)                                                   \
+    FN(svdf2)                                                  \
+    FN(svdf2_relaxed)                                          \
+    FN(svdf_relaxed)                                           \
+    FN(svdf_state)                                             \
+    FN(svdf_state_relaxed)                                     \
+    FN(tanh)                                                   \
+    FN(tanh_relaxed)                                           \
+    FN(transpose)                                              \
+    FN(transpose_float_1)                                      \
+    FN(transpose_quant8_1)
+
+#define FORWARD_DECLARE_GENERATED_OBJECTS(function) \
+    namespace function {                            \
+    extern std::vector<MixedTypedExample> examples; \
+    Model createTestModel();                        \
+    }
+
+FOR_EACH_TEST_MODEL(FORWARD_DECLARE_GENERATED_OBJECTS)
+
+#undef FORWARD_DECLARE_GENERATED_OBJECTS
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_1
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
+
+#endif  // VTS_HAL_NEURALNETWORKS_V1_1_VTS_FUNCTIONAL_MODELS_H
diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
new file mode 100644
index 0000000..7a20e26
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+
+using V1_0::IPreparedModel;
+using V1_0::Operand;
+using V1_0::OperandLifeTime;
+using V1_0::OperandType;
+
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
+                                           const V1_1::Model& model) {
+    SCOPED_TRACE(message + " [getSupportedOperations_1_1]");
+
+    Return<void> ret =
+        device->getSupportedOperations_1_1(model, [&](ErrorStatus status, const hidl_vec<bool>&) {
+            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+        });
+    EXPECT_TRUE(ret.isOk());
+}
+
+static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
+                                 const V1_1::Model& model) {
+    SCOPED_TRACE(message + " [prepareModel_1_1]");
+
+    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+    ASSERT_NE(nullptr, preparedModelCallback.get());
+    Return<ErrorStatus> prepareLaunchStatus =
+        device->prepareModel_1_1(model, preparedModelCallback);
+    ASSERT_TRUE(prepareLaunchStatus.isOk());
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+    preparedModelCallback->wait();
+    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
+    sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+    ASSERT_EQ(nullptr, preparedModel.get());
+}
+
+// Primary validation function. This function will take a valid model, apply a
+// mutation to it to invalidate the model, then pass it to interface calls that
+// use the model. Note that the model here is passed by value, and any mutation
+// to the model does not leave this function.
+static void validate(const sp<IDevice>& device, const std::string& message, V1_1::Model model,
+                     const std::function<void(Model*)>& mutation) {
+    mutation(&model);
+    validateGetSupportedOperations(device, message, model);
+    validatePrepareModel(device, message, model);
+}
+
+// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
+// so this is efficiently accomplished by moving the element to the end and
+// resizing the hidl_vec to one less.
+template <typename Type>
+static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
+    if (vec) {
+        std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
+        vec->resize(vec->size() - 1);
+    }
+}
+
+template <typename Type>
+static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
+    // assume vec is valid
+    const uint32_t index = vec->size();
+    vec->resize(index + 1);
+    (*vec)[index] = value;
+    return index;
+}
+
+static uint32_t addOperand(Model* model) {
+    return hidl_vec_push_back(&model->operands,
+                              {
+                                  .type = OperandType::INT32,
+                                  .dimensions = {},
+                                  .numberOfConsumers = 0,
+                                  .scale = 0.0f,
+                                  .zeroPoint = 0,
+                                  .lifetime = OperandLifeTime::MODEL_INPUT,
+                                  .location = {.poolIndex = 0, .offset = 0, .length = 0},
+                              });
+}
+
+static uint32_t addOperand(Model* model, OperandLifeTime lifetime) {
+    uint32_t index = addOperand(model);
+    model->operands[index].numberOfConsumers = 1;
+    model->operands[index].lifetime = lifetime;
+    return index;
+}
+
+///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
+
+static const int32_t invalidOperandTypes[] = {
+    static_cast<int32_t>(OperandType::FLOAT32) - 1,              // lower bound fundamental
+    static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1,  // upper bound fundamental
+    static_cast<int32_t>(OperandType::OEM) - 1,                  // lower bound OEM
+    static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1,      // upper bound OEM
+};
+
+static void mutateOperandTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        for (int32_t invalidOperandType : invalidOperandTypes) {
+            const std::string message = "mutateOperandTypeTest: operand " +
+                                        std::to_string(operand) + " set to value " +
+                                        std::to_string(invalidOperandType);
+            validate(device, message, model, [operand, invalidOperandType](Model* model) {
+                model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE OPERAND RANK /////////////////////////
+
+static uint32_t getInvalidRank(OperandType type) {
+    switch (type) {
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+            return 1;
+        case OperandType::TENSOR_FLOAT32:
+        case OperandType::TENSOR_INT32:
+        case OperandType::TENSOR_QUANT8_ASYMM:
+            return 0;
+        default:
+            return 0;
+    }
+}
+
+static void mutateOperandRankTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
+        const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
+                                    " has rank of " + std::to_string(invalidRank);
+        validate(device, message, model, [operand, invalidRank](Model* model) {
+            model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+        });
+    }
+}
+
+///////////////////////// VALIDATE OPERAND SCALE /////////////////////////
+
+static float getInvalidScale(OperandType type) {
+    switch (type) {
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+        case OperandType::TENSOR_FLOAT32:
+            return 1.0f;
+        case OperandType::TENSOR_INT32:
+            return -1.0f;
+        case OperandType::TENSOR_QUANT8_ASYMM:
+            return 0.0f;
+        default:
+            return 0.0f;
+    }
+}
+
+static void mutateOperandScaleTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const float invalidScale = getInvalidScale(model.operands[operand].type);
+        const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
+                                    " has scale of " + std::to_string(invalidScale);
+        validate(device, message, model, [operand, invalidScale](Model* model) {
+            model->operands[operand].scale = invalidScale;
+        });
+    }
+}
+
+///////////////////////// VALIDATE OPERAND ZERO POINT /////////////////////////
+
+static std::vector<int32_t> getInvalidZeroPoints(OperandType type) {
+    switch (type) {
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+        case OperandType::TENSOR_FLOAT32:
+        case OperandType::TENSOR_INT32:
+            return {1};
+        case OperandType::TENSOR_QUANT8_ASYMM:
+            return {-1, 256};
+        default:
+            return {};
+    }
+}
+
+static void mutateOperandZeroPointTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const std::vector<int32_t> invalidZeroPoints =
+            getInvalidZeroPoints(model.operands[operand].type);
+        for (int32_t invalidZeroPoint : invalidZeroPoints) {
+            const std::string message = "mutateOperandZeroPointTest: operand " +
+                                        std::to_string(operand) + " has zero point of " +
+                                        std::to_string(invalidZeroPoint);
+            validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
+                model->operands[operand].zeroPoint = invalidZeroPoint;
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE EXTRA ??? /////////////////////////
+
+// TODO: Operand::lifetime
+// TODO: Operand::location
+
+///////////////////////// VALIDATE OPERATION OPERAND TYPE /////////////////////////
+
+static void mutateOperand(Operand* operand, OperandType type) {
+    Operand newOperand = *operand;
+    newOperand.type = type;
+    switch (type) {
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+            newOperand.dimensions = hidl_vec<uint32_t>();
+            newOperand.scale = 0.0f;
+            newOperand.zeroPoint = 0;
+            break;
+        case OperandType::TENSOR_FLOAT32:
+            newOperand.dimensions =
+                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+            newOperand.scale = 0.0f;
+            newOperand.zeroPoint = 0;
+            break;
+        case OperandType::TENSOR_INT32:
+            newOperand.dimensions =
+                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+            newOperand.zeroPoint = 0;
+            break;
+        case OperandType::TENSOR_QUANT8_ASYMM:
+            newOperand.dimensions =
+                operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+            newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
+            break;
+        case OperandType::OEM:
+        case OperandType::TENSOR_OEM_BYTE:
+        default:
+            break;
+    }
+    *operand = newOperand;
+}
+
+static bool mutateOperationOperandTypeSkip(size_t operand, const V1_1::Model& model) {
+    // LSH_PROJECTION's second argument is allowed to have any type. This is the
+    // only operation that currently has a type that can be anything independent
+    // from any other type. Changing the operand type to any other type will
+    // result in a valid model for LSH_PROJECTION. If this is the case, skip the
+    // test.
+    for (const Operation& operation : model.operations) {
+        if (operation.type == OperationType::LSH_PROJECTION && operand == operation.inputs[1]) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        if (mutateOperationOperandTypeSkip(operand, model)) {
+            continue;
+        }
+        for (OperandType invalidOperandType : hidl_enum_iterator<OperandType>{}) {
+            // Do not test OEM types
+            if (invalidOperandType == model.operands[operand].type ||
+                invalidOperandType == OperandType::OEM ||
+                invalidOperandType == OperandType::TENSOR_OEM_BYTE) {
+                continue;
+            }
+            const std::string message = "mutateOperationOperandTypeTest: operand " +
+                                        std::to_string(operand) + " set to type " +
+                                        toString(invalidOperandType);
+            validate(device, message, model, [operand, invalidOperandType](Model* model) {
+                mutateOperand(&model->operands[operand], invalidOperandType);
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
+
+static const int32_t invalidOperationTypes[] = {
+    static_cast<int32_t>(OperationType::ADD) - 1,            // lower bound fundamental
+    static_cast<int32_t>(OperationType::TRANSPOSE) + 1,      // upper bound fundamental
+    static_cast<int32_t>(OperationType::OEM_OPERATION) - 1,  // lower bound OEM
+    static_cast<int32_t>(OperationType::OEM_OPERATION) + 1,  // upper bound OEM
+};
+
+static void mutateOperationTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        for (int32_t invalidOperationType : invalidOperationTypes) {
+            const std::string message = "mutateOperationTypeTest: operation " +
+                                        std::to_string(operation) + " set to value " +
+                                        std::to_string(invalidOperationType);
+            validate(device, message, model, [operation, invalidOperationType](Model* model) {
+                model->operations[operation].type =
+                    static_cast<OperationType>(invalidOperationType);
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
+
+static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device,
+                                                 const V1_1::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const uint32_t invalidOperand = model.operands.size();
+        for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+            const std::string message = "mutateOperationInputOperandIndexTest: operation " +
+                                        std::to_string(operation) + " input " +
+                                        std::to_string(input);
+            validate(device, message, model, [operation, input, invalidOperand](Model* model) {
+                model->operations[operation].inputs[input] = invalidOperand;
+            });
+        }
+    }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
+
+static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device,
+                                                  const V1_1::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const uint32_t invalidOperand = model.operands.size();
+        for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+            const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
+                                        std::to_string(operation) + " output " +
+                                        std::to_string(output);
+            validate(device, message, model, [operation, output, invalidOperand](Model* model) {
+                model->operations[operation].outputs[output] = invalidOperand;
+            });
+        }
+    }
+}
+
+///////////////////////// REMOVE OPERAND FROM EVERYTHING /////////////////////////
+
+static void removeValueAndDecrementGreaterValues(hidl_vec<uint32_t>* vec, uint32_t value) {
+    if (vec) {
+        // remove elements matching "value"
+        auto last = std::remove(vec->begin(), vec->end(), value);
+        vec->resize(std::distance(vec->begin(), last));
+
+        // decrement elements exceeding "value"
+        std::transform(vec->begin(), vec->end(), vec->begin(),
+                       [value](uint32_t v) { return v > value ? v-- : v; });
+    }
+}
+
+static void removeOperand(Model* model, uint32_t index) {
+    hidl_vec_removeAt(&model->operands, index);
+    for (Operation& operation : model->operations) {
+        removeValueAndDecrementGreaterValues(&operation.inputs, index);
+        removeValueAndDecrementGreaterValues(&operation.outputs, index);
+    }
+    removeValueAndDecrementGreaterValues(&model->inputIndexes, index);
+    removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
+}
+
+static void removeOperandTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+        const std::string message = "removeOperandTest: operand " + std::to_string(operand);
+        validate(device, message, model,
+                 [operand](Model* model) { removeOperand(model, operand); });
+    }
+}
+
+///////////////////////// REMOVE OPERATION /////////////////////////
+
+static void removeOperation(Model* model, uint32_t index) {
+    for (uint32_t operand : model->operations[index].inputs) {
+        model->operands[operand].numberOfConsumers--;
+    }
+    hidl_vec_removeAt(&model->operations, index);
+}
+
+static void removeOperationTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const std::string message = "removeOperationTest: operation " + std::to_string(operation);
+        validate(device, message, model,
+                 [operation](Model* model) { removeOperation(model, operation); });
+    }
+}
+
+///////////////////////// REMOVE OPERATION INPUT /////////////////////////
+
+static void removeOperationInputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+            const V1_1::Operation& op = model.operations[operation];
+            // CONCATENATION has at least 2 inputs, with the last element being
+            // INT32. Skip this test if removing one of CONCATENATION's
+            // inputs still produces a valid model.
+            if (op.type == V1_1::OperationType::CONCATENATION && op.inputs.size() > 2 &&
+                input != op.inputs.size() - 1) {
+                continue;
+            }
+            const std::string message = "removeOperationInputTest: operation " +
+                                        std::to_string(operation) + ", input " +
+                                        std::to_string(input);
+            validate(device, message, model, [operation, input](Model* model) {
+                uint32_t operand = model->operations[operation].inputs[input];
+                model->operands[operand].numberOfConsumers--;
+                hidl_vec_removeAt(&model->operations[operation].inputs, input);
+            });
+        }
+    }
+}
+
+///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
+
+static void removeOperationOutputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+            const std::string message = "removeOperationOutputTest: operation " +
+                                        std::to_string(operation) + ", output " +
+                                        std::to_string(output);
+            validate(device, message, model, [operation, output](Model* model) {
+                hidl_vec_removeAt(&model->operations[operation].outputs, output);
+            });
+        }
+    }
+}
+
+///////////////////////// MODEL VALIDATION /////////////////////////
+
+// TODO: remove model input
+// TODO: remove model output
+// TODO: add unused operation
+
+///////////////////////// ADD OPERATION INPUT /////////////////////////
+
+static void addOperationInputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
+        validate(device, message, model, [operation](Model* model) {
+            uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
+            hidl_vec_push_back(&model->operations[operation].inputs, index);
+            hidl_vec_push_back(&model->inputIndexes, index);
+        });
+    }
+}
+
+///////////////////////// ADD OPERATION OUTPUT /////////////////////////
+
+static void addOperationOutputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+        const std::string message =
+            "addOperationOutputTest: operation " + std::to_string(operation);
+        validate(device, message, model, [operation](Model* model) {
+            uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
+            hidl_vec_push_back(&model->operations[operation].outputs, index);
+            hidl_vec_push_back(&model->outputIndexes, index);
+        });
+    }
+}
+
+////////////////////////// ENTRY POINT //////////////////////////////
+
+void ValidationTest::validateModel(const V1_1::Model& model) {
+    mutateOperandTypeTest(device, model);
+    mutateOperandRankTest(device, model);
+    mutateOperandScaleTest(device, model);
+    mutateOperandZeroPointTest(device, model);
+    mutateOperationOperandTypeTest(device, model);
+    mutateOperationTypeTest(device, model);
+    mutateOperationInputOperandIndexTest(device, model);
+    mutateOperationOutputOperandIndexTest(device, model);
+    removeOperandTest(device, model);
+    removeOperationTest(device, model);
+    removeOperationInputTest(device, model);
+    removeOperationOutputTest(device, model);
+    addOperationInputTest(device, model);
+    addOperationOutputTest(device, model);
+}
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_1
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
new file mode 100644
index 0000000..bd96614
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::hidl::memory::V1_0::IMemory;
+using generated_tests::MixedTyped;
+using generated_tests::MixedTypedExampleType;
+using generated_tests::for_all;
+
+///////////////////////// 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, 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
+// mutation to the request does not leave this function.
+static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
+                     Request request, const std::function<void(Request*)>& mutation) {
+    mutation(&request);
+    SCOPED_TRACE(message + " [execute]");
+
+    sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+    ASSERT_NE(nullptr, executionCallback.get());
+    Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
+    ASSERT_TRUE(executeLaunchStatus.isOk());
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
+
+    executionCallback->wait();
+    ErrorStatus executionReturnStatus = executionCallback->getStatus();
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
+}
+
+// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
+// so this is efficiently accomplished by moving the element to the end and
+// resizing the hidl_vec to one less.
+template <typename Type>
+static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
+    if (vec) {
+        std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
+        vec->resize(vec->size() - 1);
+    }
+}
+
+template <typename Type>
+static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
+    // assume vec is valid
+    const uint32_t index = vec->size();
+    vec->resize(index + 1);
+    (*vec)[index] = value;
+    return index;
+}
+
+///////////////////////// REMOVE INPUT ////////////////////////////////////
+
+static void removeInputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    for (size_t input = 0; input < request.inputs.size(); ++input) {
+        const std::string message = "removeInput: removed input " + std::to_string(input);
+        validate(preparedModel, message, request,
+                 [input](Request* request) { hidl_vec_removeAt(&request->inputs, input); });
+    }
+}
+
+///////////////////////// REMOVE OUTPUT ////////////////////////////////////
+
+static void removeOutputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+    for (size_t output = 0; output < request.outputs.size(); ++output) {
+        const std::string message = "removeOutput: removed Output " + std::to_string(output);
+        validate(preparedModel, message, request,
+                 [output](Request* request) { hidl_vec_removeAt(&request->outputs, output); });
+    }
+}
+
+///////////////////////////// ENTRY POINT //////////////////////////////////
+
+std::vector<Request> createRequests(const std::vector<MixedTypedExampleType>& examples) {
+    const uint32_t INPUT = 0;
+    const uint32_t OUTPUT = 1;
+
+    std::vector<Request> requests;
+
+    for (auto& example : examples) {
+        const MixedTyped& inputs = example.first;
+        const MixedTyped& outputs = example.second;
+
+        std::vector<RequestArgument> inputs_info, outputs_info;
+        uint32_t inputSize = 0, outputSize = 0;
+
+        // This function only partially specifies the metadata (vector of RequestArguments).
+        // The contents are copied over below.
+        for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
+            if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
+            RequestArgument arg = {
+                .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
+                .dimensions = {},
+            };
+            RequestArgument arg_empty = {
+                .hasNoValue = true,
+            };
+            inputs_info[index] = s ? arg : arg_empty;
+            inputSize += s;
+        });
+        // Compute offset for inputs 1 and so on
+        {
+            size_t offset = 0;
+            for (auto& i : inputs_info) {
+                if (!i.hasNoValue) i.location.offset = offset;
+                offset += i.location.length;
+            }
+        }
+
+        // Go through all outputs, initialize RequestArgument descriptors
+        for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
+            if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
+            RequestArgument arg = {
+                .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
+                .dimensions = {},
+            };
+            outputs_info[index] = arg;
+            outputSize += s;
+        });
+        // Compute offset for outputs 1 and so on
+        {
+            size_t offset = 0;
+            for (auto& i : outputs_info) {
+                i.location.offset = offset;
+                offset += i.location.length;
+            }
+        }
+        std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
+                                          nn::allocateSharedMemory(outputSize)};
+        if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
+            return {};
+        }
+
+        // map pool
+        sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
+        if (inputMemory == nullptr) {
+            return {};
+        }
+        char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
+        if (inputPtr == nullptr) {
+            return {};
+        }
+
+        // initialize pool
+        inputMemory->update();
+        for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
+            char* begin = (char*)p;
+            char* end = begin + s;
+            // TODO: handle more than one input
+            std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
+        });
+        inputMemory->commit();
+
+        requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
+    }
+
+    return requests;
+}
+
+void ValidationTest::validateRequests(const V1_1::Model& model,
+                                      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);
+        removeOutputTest(preparedModel, request);
+    }
+}
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_1
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/ValidationTests.cpp b/neuralnetworks/1.1/vts/functional/ValidationTests.cpp
new file mode 100644
index 0000000..1c35ba8
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/ValidationTests.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "Models.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+// forward declarations
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
+
+// generate validation tests
+#define VTS_CURRENT_TEST_CASE(TestName)                                           \
+    TEST_F(ValidationTest, TestName) {                                            \
+        const Model model = TestName::createTestModel();                          \
+        const std::vector<Request> requests = createRequests(TestName::examples); \
+        validateModel(model);                                                     \
+        validateRequests(model, requests);                                        \
+    }
+
+FOR_EACH_TEST_MODEL(VTS_CURRENT_TEST_CASE)
+
+#undef VTS_CURRENT_TEST_CASE
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_1
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
similarity index 64%
rename from neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.cpp
rename to neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
index b1d3be7..62381e6 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
@@ -16,16 +16,7 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
-#include "VtsHalNeuralnetworksV1_1.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <hidlmemory/mapping.h>
-
-using ::android::hardware::hidl_memory;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
+#include "VtsHalNeuralnetworks.h"
 
 namespace android {
 namespace hardware {
@@ -34,11 +25,6 @@
 namespace vts {
 namespace functional {
 
-// allocator helper
-hidl_memory allocateSharedMemory(int64_t size) {
-    return nn::allocateSharedMemory(size);
-}
-
 // A class for test environment setup
 NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
 
@@ -52,23 +38,49 @@
 }
 
 void NeuralnetworksHidlEnvironment::registerTestServices() {
-    registerTestService<V1_1::IDevice>();
+    registerTestService<IDevice>();
 }
 
 // The main test class for NEURALNETWORK HIDL HAL.
+NeuralnetworksHidlTest::NeuralnetworksHidlTest() {}
+
 NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
 
 void NeuralnetworksHidlTest::SetUp() {
-    device = ::testing::VtsHalHidlTargetTestBase::getService<V1_1::IDevice>(
+    ::testing::VtsHalHidlTargetTestBase::SetUp();
+    device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
         NeuralnetworksHidlEnvironment::getInstance());
     ASSERT_NE(nullptr, device.get());
 }
 
-void NeuralnetworksHidlTest::TearDown() {}
+void NeuralnetworksHidlTest::TearDown() {
+    device = nullptr;
+    ::testing::VtsHalHidlTargetTestBase::TearDown();
+}
 
 }  // namespace functional
 }  // namespace vts
+
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) {
+    return os << toString(errorStatus);
+}
+
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) {
+    return os << toString(deviceStatus);
+}
+
 }  // namespace V1_1
 }  // namespace neuralnetworks
 }  // namespace hardware
 }  // namespace android
+
+using android::hardware::neuralnetworks::V1_1::vts::functional::NeuralnetworksHidlEnvironment;
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
+    ::testing::InitGoogleTest(&argc, argv);
+    NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
+
+    int status = RUN_ALL_TESTS();
+    return status;
+}
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
similarity index 60%
rename from neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.h
rename to neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index 426246c..0050e52 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.h
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
@@ -17,65 +17,71 @@
 #ifndef VTS_HAL_NEURALNETWORKS_V1_1_H
 #define VTS_HAL_NEURALNETWORKS_V1_1_H
 
-#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
 #include <android/hardware/neuralnetworks/1.1/IDevice.h>
 #include <android/hardware/neuralnetworks/1.1/types.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
+
+#include <android-base/macros.h>
 #include <gtest/gtest.h>
-#include <string>
+#include <iostream>
+#include <vector>
 
 namespace android {
 namespace hardware {
 namespace neuralnetworks {
 namespace V1_1 {
+
+using V1_0::Request;
+using V1_0::DeviceStatus;
+using V1_0::ErrorStatus;
+
 namespace vts {
 namespace functional {
-hidl_memory allocateSharedMemory(int64_t size);
 
 // A class for test environment setup
 class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
     NeuralnetworksHidlEnvironment();
-    NeuralnetworksHidlEnvironment(const NeuralnetworksHidlEnvironment&) = delete;
-    NeuralnetworksHidlEnvironment(NeuralnetworksHidlEnvironment&&) = delete;
-    NeuralnetworksHidlEnvironment& operator=(const NeuralnetworksHidlEnvironment&) = delete;
-    NeuralnetworksHidlEnvironment& operator=(NeuralnetworksHidlEnvironment&&) = delete;
+    ~NeuralnetworksHidlEnvironment() override;
 
    public:
-    ~NeuralnetworksHidlEnvironment() override;
     static NeuralnetworksHidlEnvironment* getInstance();
     void registerTestServices() override;
 };
 
 // The main test class for NEURALNETWORKS HIDL HAL.
 class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
+
    public:
+    NeuralnetworksHidlTest();
     ~NeuralnetworksHidlTest() override;
     void SetUp() override;
     void TearDown() override;
 
-    sp<V1_1::IDevice> device;
+   protected:
+    sp<IDevice> device;
 };
+
+// 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);
+};
+
+// Tag for the generated tests
+class GeneratedTest : public NeuralnetworksHidlTest {};
+
 }  // namespace functional
 }  // namespace vts
 
 // pretty-print values for error messages
-
-template <typename CharT, typename Traits>
-::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
-                                                V1_0::ErrorStatus errorStatus) {
-    return os << toString(errorStatus);
-}
-
-template <typename CharT, typename Traits>
-::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
-                                                V1_0::DeviceStatus deviceStatus) {
-    return os << toString(deviceStatus);
-}
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus);
 
 }  // namespace V1_1
 }  // namespace neuralnetworks
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp
deleted file mode 100644
index 10591dc..0000000
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworksV1_1.h"
-
-#include "Callbacks.h"
-#include "Models.h"
-#include "TestHarness.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/neuralnetworks/1.1/IDevice.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
-using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
-using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
-using ::android::hardware::neuralnetworks::V1_0::Operand;
-using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
-using ::android::hardware::neuralnetworks::V1_0::OperandType;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_1::Capabilities;
-using ::android::hardware::neuralnetworks::V1_1::IDevice;
-using ::android::hardware::neuralnetworks::V1_1::Model;
-using ::android::hardware::neuralnetworks::V1_1::Operation;
-using ::android::hardware::neuralnetworks::V1_1::OperationType;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
-using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-
-static void doPrepareModelShortcut(const sp<IDevice>& device, sp<IPreparedModel>* preparedModel) {
-    ASSERT_NE(nullptr, preparedModel);
-    Model model = createValidTestModel_1_1();
-
-    // 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, 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: 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;
-    }
-    ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
-    ASSERT_NE(nullptr, preparedModel->get());
-}
-
-// create device test
-TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
-
-// status test
-TEST_F(NeuralnetworksHidlTest, StatusTest) {
-    Return<DeviceStatus> status = device->getStatus();
-    ASSERT_TRUE(status.isOk());
-    EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
-}
-
-// initialization
-TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
-    Return<void> ret =
-        device->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) {
-            EXPECT_EQ(ErrorStatus::NONE, status);
-            EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
-            EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
-            EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
-            EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
-            EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.execTime);
-            EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.powerUsage);
-        });
-    EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations positive test
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsPositiveTest) {
-    Model model = createValidTestModel_1_1();
-    Return<void> ret = device->getSupportedOperations_1_1(
-        model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
-            EXPECT_EQ(ErrorStatus::NONE, status);
-            EXPECT_EQ(model.operations.size(), supported.size());
-        });
-    EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations negative test 1
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest1) {
-    Model model = createInvalidTestModel1_1_1();
-    Return<void> ret = device->getSupportedOperations_1_1(
-        model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
-            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
-            (void)supported;
-        });
-    EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations negative test 2
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest2) {
-    Model model = createInvalidTestModel2_1_1();
-    Return<void> ret = device->getSupportedOperations_1_1(
-        model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
-            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
-            (void)supported;
-        });
-    EXPECT_TRUE(ret.isOk());
-}
-
-// prepare simple model positive test
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelPositiveTest) {
-    sp<IPreparedModel> preparedModel;
-    doPrepareModelShortcut(device, &preparedModel);
-}
-
-// prepare simple model negative test 1
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest1) {
-    Model model = createInvalidTestModel1_1_1();
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus =
-        device->prepareModel_1_1(model, preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk());
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
-
-    preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
-    sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
-    EXPECT_EQ(nullptr, preparedModel.get());
-}
-
-// prepare simple model negative test 2
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest2) {
-    Model model = createInvalidTestModel2_1_1();
-    sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    ASSERT_NE(nullptr, preparedModelCallback.get());
-    Return<ErrorStatus> prepareLaunchStatus =
-        device->prepareModel_1_1(model, preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk());
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
-
-    preparedModelCallback->wait();
-    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
-    sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
-    EXPECT_EQ(nullptr, preparedModel.get());
-}
-
-// execute simple graph positive test
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphPositiveTest) {
-    std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
-    std::vector<float> expectedData = {6.0f, 8.0f, 10.0f, 12.0f};
-    const uint32_t OUTPUT = 1;
-
-    sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
-    Request request = createValidTestRequest();
-
-    auto postWork = [&] {
-        sp<IMemory> outputMemory = mapMemory(request.pools[OUTPUT]);
-        if (outputMemory == nullptr) {
-            return false;
-        }
-        float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
-        if (outputPtr == nullptr) {
-            return false;
-        }
-        outputMemory->read();
-        std::copy(outputPtr, outputPtr + outputData.size(), outputData.begin());
-        outputMemory->commit();
-        return true;
-    };
-
-    sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-    ASSERT_NE(nullptr, executionCallback.get());
-    executionCallback->on_finish(postWork);
-    Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
-    ASSERT_TRUE(executeLaunchStatus.isOk());
-    EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executeLaunchStatus));
-
-    executionCallback->wait();
-    ErrorStatus executionReturnStatus = executionCallback->getStatus();
-    EXPECT_EQ(ErrorStatus::NONE, executionReturnStatus);
-    EXPECT_EQ(expectedData, outputData);
-}
-
-// execute simple graph negative test 1
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest1) {
-    sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
-    Request request = createInvalidTestRequest1();
-
-    sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-    ASSERT_NE(nullptr, executionCallback.get());
-    Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
-    ASSERT_TRUE(executeLaunchStatus.isOk());
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
-
-    executionCallback->wait();
-    ErrorStatus executionReturnStatus = executionCallback->getStatus();
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
-}
-
-// execute simple graph negative test 2
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest2) {
-    sp<IPreparedModel> preparedModel;
-    ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
-    if (preparedModel == nullptr) {
-        return;
-    }
-    Request request = createInvalidTestRequest2();
-
-    sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-    ASSERT_NE(nullptr, executionCallback.get());
-    Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
-    ASSERT_TRUE(executeLaunchStatus.isOk());
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
-
-    executionCallback->wait();
-    ErrorStatus executionReturnStatus = executionCallback->getStatus();
-    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
-}
-
-class NeuralnetworksInputsOutputsTest
-    : public NeuralnetworksHidlTest,
-      public ::testing::WithParamInterface<std::tuple<bool, bool>> {
-   protected:
-    virtual void SetUp() { NeuralnetworksHidlTest::SetUp(); }
-    virtual void TearDown() { NeuralnetworksHidlTest::TearDown(); }
-    V1_1::Model createModel(const std::vector<uint32_t>& inputs,
-                            const std::vector<uint32_t>& outputs) {
-        // We set up the operands as floating-point with no designated
-        // model inputs and outputs, and then patch type and lifetime
-        // later on in this function.
-
-        std::vector<Operand> operands = {
-            {
-                .type = OperandType::TENSOR_FLOAT32,
-                .dimensions = {1},
-                .numberOfConsumers = 1,
-                .scale = 0.0f,
-                .zeroPoint = 0,
-                .lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
-                .location = {.poolIndex = 0, .offset = 0, .length = 0},
-            },
-            {
-                .type = OperandType::TENSOR_FLOAT32,
-                .dimensions = {1},
-                .numberOfConsumers = 1,
-                .scale = 0.0f,
-                .zeroPoint = 0,
-                .lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
-                .location = {.poolIndex = 0, .offset = 0, .length = 0},
-            },
-            {
-                .type = OperandType::INT32,
-                .dimensions = {},
-                .numberOfConsumers = 1,
-                .scale = 0.0f,
-                .zeroPoint = 0,
-                .lifetime = OperandLifeTime::CONSTANT_COPY,
-                .location = {.poolIndex = 0, .offset = 0, .length = sizeof(int32_t)},
-            },
-            {
-                .type = OperandType::TENSOR_FLOAT32,
-                .dimensions = {1},
-                .numberOfConsumers = 0,
-                .scale = 0.0f,
-                .zeroPoint = 0,
-                .lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
-                .location = {.poolIndex = 0, .offset = 0, .length = 0},
-            },
-        };
-
-        const std::vector<Operation> operations = {{
-            .type = OperationType::ADD, .inputs = {0, 1, 2}, .outputs = {3},
-        }};
-
-        std::vector<uint8_t> operandValues;
-        int32_t activation[1] = {static_cast<int32_t>(FusedActivationFunc::NONE)};
-        operandValues.insert(operandValues.end(), reinterpret_cast<const uint8_t*>(&activation[0]),
-                             reinterpret_cast<const uint8_t*>(&activation[1]));
-
-        if (kQuantized) {
-            for (auto& operand : operands) {
-                if (operand.type == OperandType::TENSOR_FLOAT32) {
-                    operand.type = OperandType::TENSOR_QUANT8_ASYMM;
-                    operand.scale = 1.0f;
-                    operand.zeroPoint = 0;
-                }
-            }
-        }
-
-        auto patchLifetime = [&operands](const std::vector<uint32_t>& operandIndexes,
-                                         OperandLifeTime lifetime) {
-            for (uint32_t index : operandIndexes) {
-                operands[index].lifetime = lifetime;
-            }
-        };
-        if (kInputHasPrecedence) {
-            patchLifetime(outputs, OperandLifeTime::MODEL_OUTPUT);
-            patchLifetime(inputs, OperandLifeTime::MODEL_INPUT);
-        } else {
-            patchLifetime(inputs, OperandLifeTime::MODEL_INPUT);
-            patchLifetime(outputs, OperandLifeTime::MODEL_OUTPUT);
-        }
-
-        return {
-            .operands = operands,
-            .operations = operations,
-            .inputIndexes = inputs,
-            .outputIndexes = outputs,
-            .operandValues = operandValues,
-            .pools = {},
-        };
-    }
-    void check(const std::string& name,
-               bool expectation,  // true = success
-               const std::vector<uint32_t>& inputs, const std::vector<uint32_t>& outputs) {
-        SCOPED_TRACE(name + " (HAL calls should " + (expectation ? "succeed" : "fail") + ", " +
-                     (kInputHasPrecedence ? "input" : "output") + " precedence, " +
-                     (kQuantized ? "quantized" : "float"));
-
-        V1_1::Model model = createModel(inputs, outputs);
-
-        // ensure that getSupportedOperations_1_1() checks model validity
-        ErrorStatus supportedOpsErrorStatus = ErrorStatus::GENERAL_FAILURE;
-        Return<void> supportedOpsReturn = device->getSupportedOperations_1_1(
-            model, [&model, &supportedOpsErrorStatus](ErrorStatus status,
-                                                      const hidl_vec<bool>& supported) {
-                supportedOpsErrorStatus = status;
-                if (status == ErrorStatus::NONE) {
-                    ASSERT_EQ(supported.size(), model.operations.size());
-                }
-            });
-        ASSERT_TRUE(supportedOpsReturn.isOk());
-        ASSERT_EQ(supportedOpsErrorStatus,
-                  (expectation ? ErrorStatus::NONE : ErrorStatus::INVALID_ARGUMENT));
-
-        // ensure that prepareModel_1_1() checks model validity
-        sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback;
-        ASSERT_NE(preparedModelCallback.get(), nullptr);
-        Return<ErrorStatus> prepareLaunchReturn =
-            device->prepareModel_1_1(model, preparedModelCallback);
-        ASSERT_TRUE(prepareLaunchReturn.isOk());
-        ASSERT_TRUE(prepareLaunchReturn == ErrorStatus::NONE ||
-                    prepareLaunchReturn == ErrorStatus::INVALID_ARGUMENT);
-        bool preparationOk = (prepareLaunchReturn == ErrorStatus::NONE);
-        if (preparationOk) {
-            preparedModelCallback->wait();
-            preparationOk = (preparedModelCallback->getStatus() == ErrorStatus::NONE);
-        }
-
-        if (preparationOk) {
-            ASSERT_TRUE(expectation);
-        } else {
-            // Preparation can fail for reasons other than an invalid model --
-            // for example, perhaps not all operations are supported, or perhaps
-            // the device hit some kind of capacity limit.
-            bool invalid = prepareLaunchReturn == ErrorStatus::INVALID_ARGUMENT ||
-                           preparedModelCallback->getStatus() == ErrorStatus::INVALID_ARGUMENT;
-            ASSERT_NE(expectation, invalid);
-        }
-    }
-
-    // Indicates whether an operand that appears in both the inputs
-    // and outputs vector should have lifetime appropriate for input
-    // rather than for output.
-    const bool kInputHasPrecedence = std::get<0>(GetParam());
-
-    // Indicates whether we should test TENSOR_QUANT8_ASYMM rather
-    // than TENSOR_FLOAT32.
-    const bool kQuantized = std::get<1>(GetParam());
-};
-
-TEST_P(NeuralnetworksInputsOutputsTest, Validate) {
-    check("Ok", true, {0, 1}, {3});
-    check("InputIsOutput", false, {0, 1}, {3, 0});
-    check("OutputIsInput", false, {0, 1, 3}, {3});
-    check("DuplicateInputs", false, {0, 1, 0}, {3});
-    check("DuplicateOutputs", false, {0, 1}, {3, 3});
-}
-
-INSTANTIATE_TEST_CASE_P(Flavor, NeuralnetworksInputsOutputsTest,
-                        ::testing::Combine(::testing::Bool(), ::testing::Bool()));
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
-
-using android::hardware::neuralnetworks::V1_1::vts::functional::NeuralnetworksHidlEnvironment;
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
-    ::testing::InitGoogleTest(&argc, argv);
-    NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
-
-    int status = RUN_ALL_TESTS();
-    return status;
-}
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1GeneratedTest.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1GeneratedTest.cpp
deleted file mode 100644
index 025d9fe..0000000
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1GeneratedTest.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworksV1_1.h"
-
-#include "Callbacks.h"
-#include "TestHarness.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/neuralnetworks/1.1/IDevice.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Capabilities;
-using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
-using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
-using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
-using ::android::hardware::neuralnetworks::V1_0::Operand;
-using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
-using ::android::hardware::neuralnetworks::V1_0::OperandType;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_1::IDevice;
-using ::android::hardware::neuralnetworks::V1_1::Model;
-using ::android::hardware::neuralnetworks::V1_1::Operation;
-using ::android::hardware::neuralnetworks::V1_1::OperationType;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-
-namespace generated_tests {
-using ::generated_tests::MixedTypedExampleType;
-extern void Execute(sp<V1_1::IDevice>&, std::function<Model(void)>, std::function<bool(int)>,
-                    const std::vector<MixedTypedExampleType>&);
-}  // namespace generated_tests
-
-namespace V1_1 {
-namespace vts {
-namespace functional {
-using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-
-// Mixed-typed examples
-typedef generated_tests::MixedTypedExampleType MixedTypedExample;
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_0_vts_tests.cpp"
-#include "all_generated_V1_1_vts_tests.cpp"
-
-}  // namespace functional
-}  // namespace vts
-}  // namespace V1_1
-}  // namespace neuralnetworks
-}  // namespace hardware
-}  // namespace android
diff --git a/radio/1.2/Android.bp b/radio/1.2/Android.bp
index a9c80b7..c90a03c 100644
--- a/radio/1.2/Android.bp
+++ b/radio/1.2/Android.bp
@@ -24,6 +24,7 @@
         "Call",
         "CardStatus",
         "CellConnectionStatus",
+        "CellIdentity",
         "CellIdentityCdma",
         "CellIdentityGsm",
         "CellIdentityLte",
@@ -36,6 +37,7 @@
         "CellInfoLte",
         "CellInfoTdscdma",
         "CellInfoWcdma",
+        "DataRegStateResult",
         "DataRequestReason",
         "IncrementalResultsPeriodicityRange",
         "IndicationFilter",
@@ -48,6 +50,7 @@
         "ScanIntervalRange",
         "SignalStrength",
         "TdscdmaSignalStrength",
+        "VoiceRegStateResult",
         "WcdmaSignalStrength",
     ],
     gen_java: true,
diff --git a/radio/1.2/IRadioResponse.hal b/radio/1.2/IRadioResponse.hal
index f26c9ec..300aa37 100644
--- a/radio/1.2/IRadioResponse.hal
+++ b/radio/1.2/IRadioResponse.hal
@@ -98,4 +98,31 @@
      *   RadioError:INTERNAL_ERR
      */
     oneway getSignalStrengthResponse_1_2(RadioResponseInfo info, SignalStrength signalStrength);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param voiceRegResponse Current Voice registration response as defined by VoiceRegStateResult
+     *        in types.hal
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    oneway getVoiceRegistrationStateResponse_1_2(RadioResponseInfo info,
+            VoiceRegStateResult voiceRegResponse);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param dataRegResponse Current Data registration response as defined by DataRegStateResult in
+     *        types.hal
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:NOT_PROVISIONED
+     */
+    oneway getDataRegistrationStateResponse_1_2(RadioResponseInfo info,
+            DataRegStateResult dataRegResponse);
 };
diff --git a/radio/1.2/types.hal b/radio/1.2/types.hal
index 5e72b3b..4715fac 100644
--- a/radio/1.2/types.hal
+++ b/radio/1.2/types.hal
@@ -32,6 +32,7 @@
 import @1.0::LteSignalStrength;
 import @1.0::RadioConst;
 import @1.0::RadioError;
+import @1.0::RegState;
 import @1.0::SignalStrength;
 import @1.0::TdScdmaSignalStrength;
 import @1.0::TimeStampType;
@@ -462,3 +463,129 @@
     TdScdmaSignalStrength tdScdma;
     WcdmaSignalStrength wcdma;
 };
+
+struct CellIdentity {
+    /**
+     * Cell type for selecting from union CellInfo.
+     * Only one of the below vectors must be of size 1 based on a
+     * valid CellInfoType and others must be of size 0.
+     * If cell info type is NONE, then all the vectors must be of size 0.
+     */
+    CellInfoType cellInfoType;
+    vec<CellIdentityGsm> cellIdentityGsm;
+    vec<CellIdentityWcdma> cellIdentityWcdma;
+    vec<CellIdentityCdma> cellIdentityCdma;
+    vec<CellIdentityLte> cellIdentityLte;
+    vec<CellIdentityTdscdma> cellIdentityTdscdma;
+};
+
+struct VoiceRegStateResult {
+    /**
+     * Valid reg states are NOT_REG_MT_NOT_SEARCHING_OP,
+     * REG_HOME, NOT_REG_MT_SEARCHING_OP, REG_DENIED,
+     * UNKNOWN, REG_ROAMING defined in RegState
+     */
+    RegState regState;
+    /**
+     * Indicates the available voice radio technology, valid values as
+     * defined by RadioTechnology.
+     */
+    int32_t rat;
+    /**
+     * concurrent services support indicator. if registered on a CDMA system.
+     * false - Concurrent services not supported,
+     * true - Concurrent services supported
+     */
+    bool cssSupported;
+    /**
+     * TSB-58 Roaming Indicator if registered on a CDMA or EVDO system or -1 if not.
+     * Valid values are 0-255.
+     */
+    int32_t roamingIndicator;
+    /**
+     * Indicates whether the current system is in the PRL if registered on a CDMA or EVDO system
+     * or -1 if not. 0=not in the PRL, 1=in the PRL
+     */
+    int32_t systemIsInPrl;
+    /**
+     * Default Roaming Indicator from the PRL if registered on a CDMA or EVDO system or -1 if not.
+     * Valid values are 0-255.
+     */
+    int32_t defaultRoamingIndicator;
+    /**
+     * reasonForDenial if registration state is 3
+     * (Registration denied) this is an enumerated reason why
+     * registration was denied. See 3GPP TS 24.008,
+     * 10.5.3.6 and Annex G.
+     * 0 - General
+     * 1 - Authentication Failure
+     * 2 - IMSI unknown in HLR
+     * 3 - Illegal MS
+     * 4 - Illegal ME
+     * 5 - PLMN not allowed
+     * 6 - Location area not allowed
+     * 7 - Roaming not allowed
+     * 8 - No Suitable Cells in this Location Area
+     * 9 - Network failure
+     * 10 - Persistent location update reject
+     * 11 - PLMN not allowed
+     * 12 - Location area not allowed
+     * 13 - Roaming not allowed in this Location Area
+     * 15 - No Suitable Cells in this Location Area
+     * 17 - Network Failure
+     * 20 - MAC Failure
+     * 21 - Sync Failure
+     * 22 - Congestion
+     * 23 - GSM Authentication unacceptable
+     * 25 - Not Authorized for this CSG
+     * 32 - Service option not supported
+     * 33 - Requested service option not subscribed
+     * 34 - Service option temporarily out of order
+     * 38 - Call cannot be identified
+     * 48-63 - Retry upon entry into a new cell
+     * 95 - Semantically incorrect message
+     * 96 - Invalid mandatory information
+     * 97 - Message type non-existent or not implemented
+     * 98 - Message type not compatible with protocol state
+     * 99 - Information element non-existent or not implemented
+     * 100 - Conditional IE error
+     * 101 - Message not compatible with protocol state
+     * 111 - Protocol error, unspecified
+     */
+    int32_t reasonForDenial;
+
+    CellIdentity cellIdentity;
+};
+
+struct DataRegStateResult {
+    /**
+     * Valid reg states are NOT_REG_MT_NOT_SEARCHING_OP,
+     * REG_HOME, NOT_REG_MT_SEARCHING_OP, REG_DENIED,
+     * UNKNOWN, REG_ROAMING defined in RegState
+     */
+    RegState regState;
+    /**
+     * Indicates the available data radio technology,
+     * valid values as defined by RadioTechnology.
+     */
+    int32_t rat;
+    /**
+     * If registration state is 3 (Registration
+     * denied) this is an enumerated reason why
+     * registration was denied. See 3GPP TS 24.008,
+     * Annex G.6 "Additional cause codes for GMM".
+     * 7 == GPRS services not allowed
+     * 8 == GPRS services and non-GPRS services not allowed
+     * 9 == MS identity cannot be derived by the network
+     * 10 == Implicitly detached
+     * 14 == GPRS services not allowed in this PLMN
+     * 16 == MSC temporarily not reachable
+     * 40 == No PDP context activated
+     */
+    int32_t reasonDataDenied;
+    /**
+     * The maximum number of simultaneous Data Calls must be established using setupDataCall().
+     */
+    int32_t maxDataCalls;
+    CellIdentity cellIdentity;
+};
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 34a87e1..ee130f8 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
@@ -673,3 +673,40 @@
     ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
                                  {RadioError::NONE, RadioError::NO_NETWORK_FOUND}));
 }
+
+/*
+ * Test IRadio.getVoiceRegistrationState() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_2, getVoiceRegistrationState) {
+    int serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_2->getVoiceRegistrationState(serial);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_2->rspInfo.serial);
+
+    ALOGI("getVoiceRegistrationStateResponse_1_2, rspInfo.error = %s\n",
+          toString(radioRsp_v1_2->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
+                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
+}
+
+/*
+ * Test IRadio.getDataRegistrationState() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_2, getDataRegistrationState) {
+    int serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_2->getDataRegistrationState(serial);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_2->rspInfo.serial);
+
+    ALOGI("getVoiceRegistrationStateResponse_1_2, rspInfo.error = %s\n",
+          toString(radioRsp_v1_2->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(
+        radioRsp_v1_2->rspInfo.error,
+        {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::NOT_PROVISIONED}));
+}
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h b/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h
index 66d8ca4..c61913c 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h
+++ b/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h
@@ -417,6 +417,12 @@
 
     Return<void> getCellInfoListResponse_1_2(
         const RadioResponseInfo& info, const ::android::hardware::hidl_vec<CellInfo>& cellInfo);
+
+    Return<void> getVoiceRegistrationStateResponse_1_2(
+        const RadioResponseInfo& info, const V1_2::VoiceRegStateResult& voiceRegResponse);
+
+    Return<void> getDataRegistrationStateResponse_1_2(
+        const RadioResponseInfo& info, const V1_2::DataRegStateResult& dataRegResponse);
 };
 
 /* Callback class for radio indication */
diff --git a/radio/1.2/vts/functional/radio_response.cpp b/radio/1.2/vts/functional/radio_response.cpp
index d96f76b..9195689 100644
--- a/radio/1.2/vts/functional/radio_response.cpp
+++ b/radio/1.2/vts/functional/radio_response.cpp
@@ -731,4 +731,14 @@
     rspInfo = info;
     parent_v1_2.notify();
     return Void();
-}
\ No newline at end of file
+}
+
+Return<void> RadioResponse_v1_2::getVoiceRegistrationStateResponse_1_2(
+    const RadioResponseInfo& /*info*/, const V1_2::VoiceRegStateResult& /*voiceRegResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_2::getDataRegistrationStateResponse_1_2(
+    const RadioResponseInfo& /*info*/, const V1_2::DataRegStateResult& /*dataRegResponse*/) {
+    return Void();
+}
diff --git a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
index 59c354f..dab81e2 100644
--- a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
+++ b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
@@ -34,14 +34,13 @@
 using ::android::sp;
 using ::testing::VtsHalHidlTargetTestEnvBase;
 
-#define SELECT_ISD \
-    { 0x00, 0xA4, 0x04, 0x00, 0x00 }
-#define SEQUENCE_COUNTER \
-    { 0x80, 0xCA, 0x00, 0xC1, 0x00 }
-#define MANAGE_SELECT \
-    { 0x00, 0xA4, 0x04, 0x00, 0x00 }
-#define CRS_AID \
-    { 0xA0, 0x00, 0x00, 0x01, 0x51, 0x43, 0x52, 0x53, 0x00 }
+#define DATA_APDU \
+    { 0x00, 0x08, 0x00, 0x00, 0x00 }
+#define ANDROID_TEST_AID                                                                          \
+    {                                                                                             \
+        0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, \
+            0x31                                                                                  \
+    }
 
 constexpr char kCallbackNameOnStateChange[] = "onStateChange";
 
@@ -115,7 +114,7 @@
  * Check status word in the response
  */
 TEST_F(SecureElementHidlTest, transmit) {
-    std::vector<uint8_t> aid = CRS_AID;
+    std::vector<uint8_t> aid = ANDROID_TEST_AID;
     SecureElementStatus statusReturned;
     LogicalChannelResponse response;
     se_->openLogicalChannel(
@@ -132,9 +131,9 @@
             }
         });
     EXPECT_EQ(SecureElementStatus::SUCCESS, statusReturned);
-    EXPECT_LE((unsigned int)3, response.selectResponse.size());
+    EXPECT_LE((unsigned int)2, response.selectResponse.size());
     EXPECT_LE(1, response.channelNumber);
-    std::vector<uint8_t> command = SELECT_ISD;
+    std::vector<uint8_t> command = DATA_APDU;
     std::vector<uint8_t> transmitResponse;
     se_->transmit(command, [&transmitResponse](std::vector<uint8_t> res) {
         transmitResponse.resize(res.size());
@@ -145,16 +144,6 @@
     EXPECT_LE((unsigned int)3, transmitResponse.size());
     EXPECT_EQ(0x90, transmitResponse[transmitResponse.size() - 2]);
     EXPECT_EQ(0x00, transmitResponse[transmitResponse.size() - 1]);
-    command = SEQUENCE_COUNTER;
-    se_->transmit(command, [&transmitResponse](std::vector<uint8_t> res) {
-        transmitResponse.resize(res.size());
-        for (size_t i = 0; i < res.size(); i++) {
-            transmitResponse[i] = res[i];
-        }
-    });
-    EXPECT_LE((unsigned int)3, transmitResponse.size());
-    EXPECT_EQ(0x90, transmitResponse[transmitResponse.size() - 2]);
-    EXPECT_EQ(0x00, transmitResponse[transmitResponse.size() - 1]);
     EXPECT_EQ(SecureElementStatus::SUCCESS, se_->closeChannel(response.channelNumber));
 }
 
@@ -164,7 +153,7 @@
  *  open channel, check the length of selectResponse and close the channel
  */
 TEST_F(SecureElementHidlTest, openBasicChannel) {
-    std::vector<uint8_t> aid = CRS_AID;
+    std::vector<uint8_t> aid = ANDROID_TEST_AID;
     SecureElementStatus statusReturned;
     std::vector<uint8_t> response;
     se_->openBasicChannel(aid, 0x00,
@@ -180,17 +169,6 @@
                           });
     if (statusReturned == SecureElementStatus::SUCCESS) {
         EXPECT_LE((unsigned int)3, response.size());
-        std::vector<uint8_t> command = SELECT_ISD;
-        std::vector<uint8_t> transmitResponse;
-        se_->transmit(command, [&transmitResponse](std::vector<uint8_t> res) {
-            transmitResponse.resize(res.size());
-            for (size_t i = 0; i < res.size(); i++) {
-                transmitResponse[i] = res[i];
-            }
-        });
-        EXPECT_LE((unsigned int)3, transmitResponse.size());
-        EXPECT_EQ(0x90, transmitResponse[transmitResponse.size() - 2]);
-        EXPECT_EQ(0x00, transmitResponse[transmitResponse.size() - 1]);
         return;
     }
     EXPECT_EQ(SecureElementStatus::UNSUPPORTED_OPERATION, statusReturned);
@@ -221,7 +199,7 @@
  * Close Channel
  */
 TEST_F(SecureElementHidlTest, openCloseLogicalChannel) {
-    std::vector<uint8_t> aid = CRS_AID;
+    std::vector<uint8_t> aid = ANDROID_TEST_AID;
     SecureElementStatus statusReturned;
     LogicalChannelResponse response;
     se_->openLogicalChannel(
@@ -238,7 +216,7 @@
             }
         });
     EXPECT_EQ(SecureElementStatus::SUCCESS, statusReturned);
-    EXPECT_LE((unsigned int)3, response.selectResponse.size());
+    EXPECT_LE((unsigned int)2, response.selectResponse.size());
     EXPECT_LE(1, response.channelNumber);
     EXPECT_EQ(SecureElementStatus::SUCCESS, se_->closeChannel(response.channelNumber));
 }
diff --git a/wifi/1.2/IWifiStaIface.hal b/wifi/1.2/IWifiStaIface.hal
index be4e537..3a7f777 100644
--- a/wifi/1.2/IWifiStaIface.hal
+++ b/wifi/1.2/IWifiStaIface.hal
@@ -17,6 +17,7 @@
 package android.hardware.wifi@1.2;
 
 import @1.0::WifiStatus;
+import @1.0::MacAddress;
 import @1.0::IWifiStaIface;
 
 /**
@@ -51,4 +52,17 @@
      * @see installApfPacketFilter()
      */
     readApfPacketFilterData() generates (WifiStatus status, vec<uint8_t> data);
+
+    /**
+     * Changes the MAC address of the Sta Interface to the given
+     * MAC address.
+     *
+     * @param mac MAC address to change into.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    setMacAddress(MacAddress mac) generates (WifiStatus status);
 };
diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
index 27c8d60..3928c9a 100644
--- a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
@@ -146,7 +146,7 @@
         } else if (type == IfaceType::STA) {
             chip_->createStaIface(
                 [&iface_name](const WifiStatus& status,
-                              const sp<IWifiStaIface>& iface) {
+                              const sp<V1_0::IWifiStaIface>& iface) {
                     if (WifiStatusCode::SUCCESS == status.code) {
                         ASSERT_NE(iface.get(), nullptr);
                         iface->getName([&iface_name](const WifiStatus& status,
diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.2/default/wifi_legacy_hal.cpp
index 84af9c4..c314e64 100644
--- a/wifi/1.2/default/wifi_legacy_hal.cpp
+++ b/wifi/1.2/default/wifi_legacy_hal.cpp
@@ -492,6 +492,28 @@
         getIfaceHandle(iface_name), program.data(), program.size());
 }
 
+std::pair<wifi_error, std::vector<uint8_t>>
+WifiLegacyHal::readApfPacketFilterData(const std::string& iface_name) {
+    if (global_func_table_.wifi_read_packet_filter == nullptr) {
+        return {WIFI_ERROR_NOT_SUPPORTED, {}};
+    }
+
+    PacketFilterCapabilities caps;
+    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+        getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+    if (status != WIFI_SUCCESS) {
+        return {status, {}};
+    }
+
+    // Size the buffer to read the entire program & work memory.
+    std::vector<uint8_t> buffer(caps.max_len);
+
+    status = global_func_table_.wifi_read_packet_filter(
+        getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(),
+        buffer.size());
+    return {status, move(buffer)};
+}
+
 std::pair<wifi_error, wifi_gscan_capabilities>
 WifiLegacyHal::getGscanCapabilities(const std::string& iface_name) {
     wifi_gscan_capabilities caps;
diff --git a/wifi/1.2/default/wifi_legacy_hal.h b/wifi/1.2/default/wifi_legacy_hal.h
index dedbbf8..60905ab 100644
--- a/wifi/1.2/default/wifi_legacy_hal.h
+++ b/wifi/1.2/default/wifi_legacy_hal.h
@@ -156,7 +156,7 @@
  * Class that encapsulates all legacy HAL interactions.
  * This class manages the lifetime of the event loop thread used by legacy HAL.
  *
- * Note: aThere will only be a single instance of this class created in the Wifi
+ * Note: There will only be a single instance of this class created in the Wifi
  * object and will be valid for the lifetime of the process.
  */
 class WifiLegacyHal {
@@ -188,6 +188,8 @@
         const std::string& iface_name);
     wifi_error setPacketFilter(const std::string& iface_name,
                                const std::vector<uint8_t>& program);
+    std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
+        const std::string& iface_name);
     // Gscan functions.
     std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
         const std::string& iface_name);
diff --git a/wifi/1.2/default/wifi_sta_iface.cpp b/wifi/1.2/default/wifi_sta_iface.cpp
index 6faf009..daa5610 100644
--- a/wifi/1.2/default/wifi_sta_iface.cpp
+++ b/wifi/1.2/default/wifi_sta_iface.cpp
@@ -94,6 +94,13 @@
                            hidl_status_cb, cmd_id, program);
 }
 
+Return<void> WifiStaIface::readApfPacketFilterData(
+    readApfPacketFilterData_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::readApfPacketFilterDataInternal,
+                           hidl_status_cb);
+}
+
 Return<void> WifiStaIface::getBackgroundScanCapabilities(
     getBackgroundScanCapabilities_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
@@ -234,6 +241,13 @@
                            hidl_status_cb);
 }
 
+Return<void> WifiStaIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                                         setMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setMacAddressInternal, hidl_status_cb,
+                           mac);
+}
+
 std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
     return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
 }
@@ -297,6 +311,15 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
+std::pair<WifiStatus, std::vector<uint8_t>>
+WifiStaIface::readApfPacketFilterDataInternal() {
+    const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>>
+        legacy_status_and_data =
+            legacy_hal_.lock()->readApfPacketFilterData(ifname_);
+    return {createWifiStatusFromLegacyError(legacy_status_and_data.first),
+            std::move(legacy_status_and_data.second)};
+}
+
 std::pair<WifiStatus, StaBackgroundScanCapabilities>
 WifiStaIface::getBackgroundScanCapabilitiesInternal() {
     legacy_hal::wifi_error legacy_status;
@@ -578,6 +601,26 @@
     return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
 }
 
+WifiStatus WifiStaIface::setMacAddressInternal(
+    const std::array<uint8_t, 6>& mac) {
+    if (!iface_tool_.SetWifiUpState(false)) {
+        LOG(ERROR) << "SetWifiUpState(false) failed.";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+
+    if (!iface_tool_.SetMacAddress(ifname_.c_str(), mac)) {
+        LOG(ERROR) << "SetMacAddress failed.";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+
+    if (!iface_tool_.SetWifiUpState(true)) {
+        LOG(ERROR) << "SetWifiUpState(true) failed.";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    LOG(DEBUG) << "Successfully SetMacAddress.";
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
 }  // namespace implementation
 }  // namespace V1_2
 }  // namespace wifi
diff --git a/wifi/1.2/default/wifi_sta_iface.h b/wifi/1.2/default/wifi_sta_iface.h
index 423365c..71cd17d 100644
--- a/wifi/1.2/default/wifi_sta_iface.h
+++ b/wifi/1.2/default/wifi_sta_iface.h
@@ -18,8 +18,10 @@
 #define WIFI_STA_IFACE_H_
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiStaIface.h>
 #include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
+#include <android/hardware/wifi/1.2/IWifiStaIface.h>
+
+#include <wifi_system/interface_tool.h>
 
 #include "hidl_callback_util.h"
 #include "wifi_legacy_hal.h"
@@ -34,7 +36,7 @@
 /**
  * HIDL interface object used to control a STA Iface instance.
  */
-class WifiStaIface : public V1_0::IWifiStaIface {
+class WifiStaIface : public V1_2::IWifiStaIface {
    public:
     WifiStaIface(const std::string& ifname,
                  const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -56,6 +58,8 @@
     Return<void> installApfPacketFilter(
         uint32_t cmd_id, const hidl_vec<uint8_t>& program,
         installApfPacketFilter_cb hidl_status_cb) override;
+    Return<void> readApfPacketFilterData(
+        readApfPacketFilterData_cb hidl_status_cb) override;
     Return<void> getBackgroundScanCapabilities(
         getBackgroundScanCapabilities_cb hidl_status_cb) override;
     Return<void> getValidFrequenciesForBand(
@@ -101,6 +105,8 @@
         getDebugTxPacketFates_cb hidl_status_cb) override;
     Return<void> getDebugRxPacketFates(
         getDebugRxPacketFates_cb hidl_status_cb) override;
+    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                               setMacAddress_cb hidl_status_cb) override;
 
    private:
     // Corresponding worker functions for the HIDL methods.
@@ -113,6 +119,8 @@
     getApfPacketFilterCapabilitiesInternal();
     WifiStatus installApfPacketFilterInternal(
         uint32_t cmd_id, const std::vector<uint8_t>& program);
+    std::pair<WifiStatus, std::vector<uint8_t>>
+    readApfPacketFilterDataInternal();
     std::pair<WifiStatus, StaBackgroundScanCapabilities>
     getBackgroundScanCapabilitiesInternal();
     std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
@@ -142,12 +150,14 @@
     getDebugTxPacketFatesInternal();
     std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
     getDebugRxPacketFatesInternal();
+    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
 
     std::string ifname_;
     std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
     bool is_valid_;
     hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback>
         event_cb_handler_;
+    wifi_system::InterfaceTool iface_tool_;
 
     DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
 };
diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp
index d85d42e..918e4a4 100644
--- a/wifi/1.2/vts/functional/Android.bp
+++ b/wifi/1.2/vts/functional/Android.bp
@@ -20,6 +20,7 @@
     srcs: [
         "VtsHalWifiV1_2TargetTest.cpp",
         "wifi_chip_hidl_test.cpp",
+        "wifi_sta_iface_hidl_test.cpp",
     ],
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
diff --git a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
new file mode 100644
index 0000000..fd4a671
--- /dev/null
+++ b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Staache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include <android/hardware/wifi/1.2/IWifiStaIface.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::wifi::V1_2::IWifiStaIface;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+
+/**
+ * Fixture to use for all STA Iface HIDL interface tests.
+ */
+class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface());
+        ASSERT_NE(nullptr, wifi_sta_iface_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(); }
+
+   protected:
+    sp<IWifiStaIface> wifi_sta_iface_;
+};
+
+/*
+ * SetMacAddress:
+ * Ensures that calls to set MAC address will return a success status
+ * code.
+ */
+TEST_F(WifiStaIfaceHidlTest, SetMacAddress) {
+    const android::hardware::hidl_array<uint8_t, 6> kMac{
+        std::array<uint8_t, 6>{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}}};
+    EXPECT_EQ(WifiStatusCode::SUCCESS,
+              HIDL_INVOKE(wifi_sta_iface_, setMacAddress, kMac).code);
+}
diff --git a/wifi/supplicant/1.1/Android.bp b/wifi/supplicant/1.1/Android.bp
index fafd6ad..832d1ad 100644
--- a/wifi/supplicant/1.1/Android.bp
+++ b/wifi/supplicant/1.1/Android.bp
@@ -8,6 +8,8 @@
     },
     srcs: [
         "ISupplicant.hal",
+        "ISupplicantStaIface.hal",
+        "ISupplicantStaIfaceCallback.hal",
         "ISupplicantStaNetwork.hal",
     ],
     interfaces: [
diff --git a/wifi/supplicant/1.1/ISupplicantStaIface.hal b/wifi/supplicant/1.1/ISupplicantStaIface.hal
new file mode 100644
index 0000000..025cc6a
--- /dev/null
+++ b/wifi/supplicant/1.1/ISupplicantStaIface.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant@1.1;
+
+import @1.0::ISupplicantStaIface;
+import @1.1::ISupplicantStaIfaceCallback;
+import @1.0::SupplicantStatus;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * interface (e.g wlan0) it controls.
+ */
+interface ISupplicantStaIface extends @1.0::ISupplicantStaIface {
+
+    /**
+     * Register for callbacks from this interface.
+     *
+     * These callbacks are invoked for events that are specific to this interface.
+     * Registration of multiple callback objects is supported. These objects must
+     * be automatically deleted when the corresponding client process is dead or
+     * if this interface is removed.
+     *
+     * @param callback An instance of the |ISupplicantStaIfaceCallback| HIDL
+     *        interface object.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    registerCallback_1_1(ISupplicantStaIfaceCallback callback)
+        generates (SupplicantStatus status);
+};
+
diff --git a/wifi/supplicant/1.1/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.1/ISupplicantStaIfaceCallback.hal
new file mode 100644
index 0000000..8b92ee5
--- /dev/null
+++ b/wifi/supplicant/1.1/ISupplicantStaIfaceCallback.hal
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant@1.1;
+
+import @1.0::ISupplicantStaIfaceCallback;
+
+/**
+ * Callback Interface exposed by the supplicant service
+ * for each station mode interface (ISupplicantStaIface).
+ *
+ * Clients need to host an instance of this HIDL interface object and
+ * pass a reference of the object to the supplicant via the
+ * corresponding |ISupplicantStaIface.registerCallback_1_1| method.
+ */
+interface ISupplicantStaIfaceCallback extends @1.0::ISupplicantStaIfaceCallback {
+
+    /* EapErrorCode: Error code for EAP or EAP Method as per RFC-4186 */
+    enum EapErrorCode : uint32_t {
+        SIM_GENERAL_FAILURE_AFTER_AUTH = 0,
+        SIM_TEMPORARILY_DENIED = 1026,
+        SIM_NOT_SUBSCRIBED = 1031,
+        SIM_GENERAL_FAILURE_BEFORE_AUTH = 16384,
+        SIM_VENDOR_SPECIFIC_EXPIRED_CERT = 16385,
+    };
+
+    /**
+     * Used to indicate an EAP authentication failure.
+     */
+    oneway onEapFailure_1_1(EapErrorCode errorCode);
+};
+
diff --git a/wifi/supplicant/1.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp
index 3efe15d..3e65453 100644
--- a/wifi/supplicant/1.1/vts/functional/Android.bp
+++ b/wifi/supplicant/1.1/vts/functional/Android.bp
@@ -40,6 +40,7 @@
     srcs: [
         "VtsHalWifiSupplicantV1_1TargetTest.cpp",
         "supplicant_hidl_test.cpp",
+        "supplicant_sta_iface_hidl_test.cpp",
         "supplicant_sta_network_hidl_test.cpp",
     ],
     static_libs: [
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
index 3f17740..04a5ed9 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
@@ -21,6 +21,7 @@
 #include "supplicant_hidl_test_utils_1_1.h"
 
 using ::android::hardware::wifi::supplicant::V1_1::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface;
 using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaNetwork;
 using ::android::sp;
 
@@ -28,6 +29,10 @@
     return ISupplicant::castFrom(getSupplicant());
 }
 
+sp<ISupplicantStaIface> getSupplicantStaIface_1_1() {
+    return ISupplicantStaIface::castFrom(getSupplicantStaIface());
+}
+
 sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_1() {
     return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork());
 }
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
index e7ce54a..1c13325 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
@@ -18,11 +18,15 @@
 #define SUPPLICANT_HIDL_TEST_UTILS_1_1_H
 
 #include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIface.h>
 #include <android/hardware/wifi/supplicant/1.1/ISupplicantStaNetwork.h>
 
 android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>
     getSupplicant_1_1();
 
+android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface>
+    getSupplicantStaIface_1_1();
+
 android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicantStaNetwork>
     createSupplicantStaNetwork_1_1();
 
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
new file mode 100644
index 0000000..c5e6319
--- /dev/null
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIface.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_1.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIfaceCallback;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+
+class SupplicantStaIfaceHidlTest
+    : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+  virtual void SetUp() override {
+      startSupplicantAndWaitForHidlService();
+      EXPECT_TRUE(turnOnExcessiveLogging());
+      sta_iface_ = getSupplicantStaIface_1_1();
+      ASSERT_NE(sta_iface_.get(), nullptr);
+  }
+
+  virtual void TearDown() override { stopSupplicant(); }
+
+ protected:
+  // ISupplicantStaIface object used for all tests in this fixture.
+  sp<ISupplicantStaIface> sta_iface_;
+};
+
+class IfaceCallback : public ISupplicantStaIfaceCallback {
+    Return<void> onNetworkAdded(uint32_t /* id */) override { return Void(); }
+    Return<void> onNetworkRemoved(uint32_t /* id */) override { return Void(); }
+    Return<void> onStateChanged(
+        ISupplicantStaIfaceCallback::State /* newState */,
+        const hidl_array<uint8_t, 6>& /*bssid */, uint32_t /* id */,
+        const hidl_vec<uint8_t>& /* ssid */) override {
+        return Void();
+    }
+    Return<void> onAnqpQueryDone(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        const ISupplicantStaIfaceCallback::AnqpData& /* data */,
+        const ISupplicantStaIfaceCallback::Hs20AnqpData& /* hs20Data */)
+        override {
+        return Void();
+    }
+    virtual Return<void> onHs20IconQueryDone(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        const hidl_string& /* fileName */,
+        const hidl_vec<uint8_t>& /* data */) override {
+        return Void();
+    }
+    virtual Return<void> onHs20SubscriptionRemediation(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        ISupplicantStaIfaceCallback::OsuMethod /* osuMethod */,
+        const hidl_string& /* url*/) override {
+        return Void();
+    }
+    Return<void> onHs20DeauthImminentNotice(
+        const hidl_array<uint8_t, 6>& /* bssid */, uint32_t /* reasonCode */,
+        uint32_t /* reAuthDelayInSec */,
+        const hidl_string& /* url */) override {
+        return Void();
+    }
+    Return<void> onDisconnected(const hidl_array<uint8_t, 6>& /* bssid */,
+                                bool /* locallyGenerated */,
+                                ISupplicantStaIfaceCallback::ReasonCode
+                                /* reasonCode */) override {
+        return Void();
+    }
+    Return<void> onAssociationRejected(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        ISupplicantStaIfaceCallback::StatusCode /* statusCode */,
+        bool /*timedOut */) override {
+        return Void();
+    }
+    Return<void> onAuthenticationTimeout(
+        const hidl_array<uint8_t, 6>& /* bssid */) override {
+        return Void();
+    }
+    Return<void> onBssidChanged(
+        ISupplicantStaIfaceCallback::BssidChangeReason /* reason */,
+        const hidl_array<uint8_t, 6>& /* bssid */) override {
+        return Void();
+    }
+    Return<void> onEapFailure() override { return Void(); }
+    Return<void> onEapFailure_1_1(
+        ISupplicantStaIfaceCallback::EapErrorCode /* eapErrorCode */) override {
+        return Void();
+    }
+    Return<void> onWpsEventSuccess() override { return Void(); }
+    Return<void> onWpsEventFail(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        ISupplicantStaIfaceCallback::WpsConfigError /* configError */,
+        ISupplicantStaIfaceCallback::WpsErrorIndication /* errorInd */)
+        override {
+        return Void();
+    }
+    Return<void> onWpsEventPbcOverlap() override { return Void(); }
+    Return<void> onExtRadioWorkStart(uint32_t /* id */) override {
+        return Void();
+    }
+    Return<void> onExtRadioWorkTimeout(uint32_t /* id*/) override {
+        return Void();
+    }
+};
+
+/*
+ * RegisterCallback_1_1
+ */
+TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_1) {
+  sta_iface_->registerCallback_1_1(
+      new IfaceCallback(), [](const SupplicantStatus& status) {
+          EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+      });
+}