Merge "composer: few changes for refresh rate switching"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 98e125b..0e18f48 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,6 +1,12 @@
 {
   "presubmit": [
     {
+      "name": "vts_treble_vintf_framework_test"
+    },
+    {
+      "name": "vts_treble_vintf_vendor_test"
+    },
+    {
       "name": "hidl_implementation_test"
     }
   ]
diff --git a/audio/5.0/config/api/current.txt b/audio/5.0/config/api/current.txt
index c665781..a1d8e1e 100644
--- a/audio/5.0/config/api/current.txt
+++ b/audio/5.0/config/api/current.txt
@@ -237,6 +237,7 @@
     method public audio.policy.configuration.V5_0.GainMode getMode();
     method public String getName();
     method public int getStepValueMB();
+    method public boolean getUseForVolume();
     method public void setChannel_mask(String);
     method public void setDefaultValueMB(int);
     method public void setMaxRampMs(int);
@@ -246,6 +247,7 @@
     method public void setMode(audio.policy.configuration.V5_0.GainMode);
     method public void setName(String);
     method public void setStepValueMB(int);
+    method public void setUseForVolume(boolean);
   }
 
   public class GlobalConfiguration {
diff --git a/audio/5.0/config/audio_policy_configuration.xsd b/audio/5.0/config/audio_policy_configuration.xsd
index 2e1a722..284d2e2 100644
--- a/audio/5.0/config/audio_policy_configuration.xsd
+++ b/audio/5.0/config/audio_policy_configuration.xsd
@@ -446,6 +446,7 @@
                     <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
                     <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
                     <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+                    <xs:attribute name="useForVolume" type="xs:boolean" use="optional"/>
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
index e885fe2..520e776 100644
--- a/audio/6.0/IDevice.hal
+++ b/audio/6.0/IDevice.hal
@@ -280,4 +280,15 @@
      */
     setConnectedState(DeviceAddress address, bool connected)
             generates (Result retval);
+
+    /**
+     * Called by the framework to deinitialize the device and free up
+     * all currently allocated resources. It is recommended to close
+     * the device on the client side as soon as it is becomes unused.
+     *
+     * @return retval OK in case the success.
+     *                INVALID_STATE if the device was already closed.
+     */
+    @exit
+    close() generates (Result retval);
 };
diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal
index 451e116..d7d3c84 100644
--- a/audio/6.0/IStream.hal
+++ b/audio/6.0/IStream.hal
@@ -277,7 +277,7 @@
      * @return retval OK in case the success.
      *                NOT_SUPPORTED on non mmap mode streams
      *                NOT_INITIALIZED in case of memory allocation error
-     *                INVALID_ARGUMENTS if the requested buffer size is too large
+     *                INVALID_ARGUMENTS if the requested buffer size is invalid
      *                INVALID_STATE if called out of sequence
      * @return info    a MmapBufferInfo struct containing information on the MMMAP buffer created.
      */
@@ -300,13 +300,17 @@
 
     /**
      * Called by the framework to deinitialize the stream and free up
-     * all the currently allocated resources. It is recommended to close
+     * all currently allocated resources. It is recommended to close
      * the stream on the client side as soon as it is becomes unused.
      *
+     * The client must ensure that this function is not called while
+     * audio data is being transferred through the stream's message queues.
+     *
      * @return retval OK in case the success.
      *                NOT_SUPPORTED if called on IStream instead of input or
      *                              output stream interface.
      *                INVALID_STATE if the stream was already closed.
      */
+    @exit
     close() generates (Result retval);
 };
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
index e67831c..ddd4d1c 100644
--- a/audio/6.0/config/api/current.txt
+++ b/audio/6.0/config/api/current.txt
@@ -237,6 +237,7 @@
     method public audio.policy.configuration.V6_0.GainMode getMode();
     method public String getName();
     method public int getStepValueMB();
+    method public boolean getUseForVolume();
     method public void setChannel_mask(String);
     method public void setDefaultValueMB(int);
     method public void setMaxRampMs(int);
@@ -246,6 +247,7 @@
     method public void setMode(audio.policy.configuration.V6_0.GainMode);
     method public void setName(String);
     method public void setStepValueMB(int);
+    method public void setUseForVolume(boolean);
   }
 
   public class GlobalConfiguration {
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
index 29f6f38..3fab7dc 100644
--- a/audio/6.0/config/audio_policy_configuration.xsd
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -447,6 +447,7 @@
                     <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
                     <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
                     <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+                    <xs:attribute name="useForVolume" type="xs:boolean" use="optional"/>
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
diff --git a/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h b/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h
deleted file mode 100644
index 3833fd0..0000000
--- a/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
-#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
-
-#include <iosfwd>
-#include <utility>
-
-/** @file Use HIDL generated toString methods to pretty print gtest errors
- *        Unfortunately Gtest does not offer a template to specialize, only
- *        overloading PrintTo.
- *  @note that this overload can NOT be template because
- *        the fallback is already template, resulting in ambiguity.
- *  @note that the overload MUST be in the exact namespace
- *        the type is declared in, as per the ADL rules.
- */
-
-namespace android {
-namespace hardware {
-namespace audio {
-
-#define DEFINE_GTEST_PRINT_TO(T) \
-    inline void PrintTo(const T& val, ::std::ostream* os) { *os << toString(val); }
-
-namespace CPP_VERSION {
-DEFINE_GTEST_PRINT_TO(IPrimaryDevice::TtyMode)
-DEFINE_GTEST_PRINT_TO(Result)
-}  // namespace CPP_VERSION
-
-namespace common {
-namespace CPP_VERSION {
-DEFINE_GTEST_PRINT_TO(AudioConfig)
-DEFINE_GTEST_PRINT_TO(AudioMode)
-DEFINE_GTEST_PRINT_TO(AudioDevice)
-DEFINE_GTEST_PRINT_TO(AudioFormat)
-DEFINE_GTEST_PRINT_TO(AudioChannelMask)
-}  // namespace CPP_VERSION
-}  // namespace common
-
-#undef DEFINE_GTEST_PRINT_TO
-
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index 1a9df21..5ea4c8d 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -39,11 +39,10 @@
 
 using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
 
-Device::Device(audio_hw_device_t* device) : mDevice(device) {}
+Device::Device(audio_hw_device_t* device) : mIsClosed(false), mDevice(device) {}
 
 Device::~Device() {
-    int status = audio_hw_device_close(mDevice);
-    ALOGW_IF(status, "Error closing audio hw device %p: %s", mDevice, strerror(-status));
+    (void)doClose();
     mDevice = nullptr;
 }
 
@@ -383,6 +382,18 @@
 }
 #endif
 
+Result Device::doClose() {
+    if (mIsClosed) return Result::INVALID_STATE;
+    mIsClosed = true;
+    return analyzeStatus("close", audio_hw_device_close(mDevice));
+}
+
+#if MAJOR_VERSION >= 6
+Return<Result> Device::close() {
+    return doClose();
+}
+#endif
+
 }  // namespace implementation
 }  // namespace CPP_VERSION
 }  // namespace audio
diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp
index 99590b0..3cf0932 100644
--- a/audio/core/all-versions/default/PrimaryDevice.cpp
+++ b/audio/core/all-versions/default/PrimaryDevice.cpp
@@ -31,7 +31,11 @@
 
 PrimaryDevice::PrimaryDevice(audio_hw_device_t* device) : mDevice(new Device(device)) {}
 
-PrimaryDevice::~PrimaryDevice() {}
+PrimaryDevice::~PrimaryDevice() {
+    // Do not call mDevice->close here. If there are any unclosed streams,
+    // they only hold IDevice instance, not IPrimaryDevice, thus IPrimaryDevice
+    // "part" of a device can be destroyed before the streams.
+}
 
 // Methods from ::android::hardware::audio::CPP_VERSION::IDevice follow.
 Return<Result> PrimaryDevice::initCheck() {
@@ -160,6 +164,11 @@
     return mDevice->setConnectedState(address, connected);
 }
 #endif
+#if MAJOR_VERSION >= 6
+Return<Result> PrimaryDevice::close() {
+    return mDevice->close();
+}
+#endif
 
 // Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow.
 Return<Result> PrimaryDevice::setVoiceVolume(float volume) {
diff --git a/audio/core/all-versions/default/StreamIn.cpp b/audio/core/all-versions/default/StreamIn.cpp
index d316f83..f1152ca 100644
--- a/audio/core/all-versions/default/StreamIn.cpp
+++ b/audio/core/all-versions/default/StreamIn.cpp
@@ -139,8 +139,7 @@
 }  // namespace
 
 StreamIn::StreamIn(const sp<Device>& device, audio_stream_in_t* stream)
-    : mIsClosed(false),
-      mDevice(device),
+    : mDevice(device),
       mStream(stream),
       mStreamCommon(new Stream(&stream->common)),
       mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
@@ -159,7 +158,9 @@
         status_t status = EventFlag::deleteEventFlag(&mEfGroup);
         ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
     }
+#if MAJOR_VERSION <= 5
     mDevice->closeInputStream(mStream);
+#endif
     mStream = nullptr;
 }
 
@@ -303,14 +304,16 @@
 }
 
 Return<Result> StreamIn::close() {
-    if (mIsClosed) return Result::INVALID_STATE;
-    mIsClosed = true;
-    if (mReadThread.get()) {
-        mStopReadThread.store(true, std::memory_order_release);
+    if (mStopReadThread.load(std::memory_order_relaxed)) {  // only this thread writes
+        return Result::INVALID_STATE;
     }
+    mStopReadThread.store(true, std::memory_order_release);
     if (mEfGroup) {
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
     }
+#if MAJOR_VERSION >= 6
+    mDevice->closeInputStream(mStream);
+#endif
     return Result::OK;
 }
 
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 82cc408..396d354 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -138,8 +138,7 @@
 }  // namespace
 
 StreamOut::StreamOut(const sp<Device>& device, audio_stream_out_t* stream)
-    : mIsClosed(false),
-      mDevice(device),
+    : mDevice(device),
       mStream(stream),
       mStreamCommon(new Stream(&stream->common)),
       mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)),
@@ -148,7 +147,7 @@
 
 StreamOut::~StreamOut() {
     ATRACE_CALL();
-    close();
+    (void)close();
     if (mWriteThread.get()) {
         ATRACE_NAME("mWriteThread->join");
         status_t status = mWriteThread->join();
@@ -159,10 +158,12 @@
         ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status));
     }
     mCallback.clear();
+#if MAJOR_VERSION <= 5
     mDevice->closeOutputStream(mStream);
     // Closing the output stream in the HAL waits for the callback to finish,
     // and joins the callback thread. Thus is it guaranteed that the callback
     // thread will not be accessing our object anymore.
+#endif
     mStream = nullptr;
 }
 
@@ -291,14 +292,16 @@
 #endif
 
 Return<Result> StreamOut::close() {
-    if (mIsClosed) return Result::INVALID_STATE;
-    mIsClosed = true;
-    if (mWriteThread.get()) {
-        mStopWriteThread.store(true, std::memory_order_release);
+    if (mStopWriteThread.load(std::memory_order_relaxed)) {  // only this thread writes
+        return Result::INVALID_STATE;
     }
+    mStopWriteThread.store(true, std::memory_order_release);
     if (mEfGroup) {
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
     }
+#if MAJOR_VERSION >= 6
+    mDevice->closeOutputStream(mStream);
+#endif
     return Result::OK;
 }
 
diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h
index e64f00f..dc53a39 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -114,6 +114,9 @@
     Return<void> getMicrophones(getMicrophones_cb _hidl_cb) override;
     Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override;
 #endif
+#if MAJOR_VERSION >= 6
+    Return<Result> close() override;
+#endif
 
     Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
@@ -124,11 +127,14 @@
     void closeOutputStream(audio_stream_out_t* stream);
     audio_hw_device_t* device() const { return mDevice; }
 
-   private:
+  private:
+    bool mIsClosed;
     audio_hw_device_t* mDevice;
 
     virtual ~Device();
 
+    Result doClose();
+
     // Methods from ParametersUtil.
     char* halGetParameters(const char* keys) override;
     int halSetParameters(const char* keysAndValues) override;
diff --git a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
index 9d69cb0..f5f3848 100644
--- a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
+++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
@@ -96,6 +96,9 @@
     Return<void> getMicrophones(getMicrophones_cb _hidl_cb) override;
     Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override;
 #endif
+#if MAJOR_VERSION >= 6
+    Return<Result> close() override;
+#endif
 
     Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
diff --git a/audio/core/all-versions/default/include/core/default/StreamIn.h b/audio/core/all-versions/default/include/core/default/StreamIn.h
index 6209b8f..24f9944 100644
--- a/audio/core/all-versions/default/include/core/default/StreamIn.h
+++ b/audio/core/all-versions/default/include/core/default/StreamIn.h
@@ -120,7 +120,6 @@
                                          uint64_t* time);
 
    private:
-    bool mIsClosed;
     const sp<Device> mDevice;
     audio_stream_in_t* mStream;
     const sp<Stream> mStreamCommon;
diff --git a/audio/core/all-versions/default/include/core/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h
index b098005..6334785 100644
--- a/audio/core/all-versions/default/include/core/default/StreamOut.h
+++ b/audio/core/all-versions/default/include/core/default/StreamOut.h
@@ -126,7 +126,6 @@
                                               TimeSpec* timeStamp);
 
    private:
-    bool mIsClosed;
     const sp<Device> mDevice;
     audio_stream_out_t* mStream;
     const sp<Stream> mStreamCommon;
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index e267a5e..81f963d 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -22,18 +22,16 @@
         GTEST_SKIP() << "No primary device on this factory";  // returns
     }
 
-    struct WaitExecutor {
-        ~WaitExecutor() { DeviceManager::waitForInstanceDestruction(); }
-    } waitExecutor;  // Make sure we wait for the device destruction on exiting from the test.
-    Result result;
-    sp<IDevice> baseDevice;
-    ASSERT_OK(getDevicesFactory()->openDevice("primary", returnIn(result, baseDevice)));
-    ASSERT_OK(result);
-    ASSERT_TRUE(baseDevice != nullptr);
-
-    Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
-    ASSERT_TRUE(primaryDevice.isOk());
-    ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
+    {  // Scope for device SPs
+        sp<IDevice> baseDevice =
+                DeviceManager::getInstance().get(getFactoryName(), DeviceManager::kPrimaryDevice);
+        ASSERT_TRUE(baseDevice != nullptr);
+        Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
+        EXPECT_TRUE(primaryDevice.isOk());
+        EXPECT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
+    }
+    EXPECT_TRUE(
+            DeviceManager::getInstance().reset(getFactoryName(), DeviceManager::kPrimaryDevice));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -113,10 +111,12 @@
                 ASSERT_NE(0U, activeMicrophones.size());
             }
             stream->close();
+#if MAJOR_VERSION <= 5
             // Workaround for b/139329877. Ensures the stream gets closed on the audio hal side.
             stream.clear();
             IPCThreadState::self()->flushCommands();
             usleep(1000);
+#endif
             if (efGroup) {
                 EventFlag::deleteEventFlag(&efGroup);
             }
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
index 30f8a7a..7e931ff 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -100,7 +100,8 @@
                             special = true;
                         }
                         if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) &&
-                            !(flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) {
+                            !(flags &
+                              (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ))) {
                             result.emplace_back(device, config,
                                                 AudioOutputFlag(AUDIO_OUTPUT_FLAG_DIRECT));
                             special = true;
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 468f9b2..6fc9339 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -58,7 +58,6 @@
 
 #include "utility/AssertOk.h"
 #include "utility/Documentation.h"
-#include "utility/PrettyPrintAudioTypes.h"
 #include "utility/ReturnIn.h"
 #include "utility/ValidateXml.h"
 
@@ -860,6 +859,7 @@
     }
 
     static void waitForStreamDestruction() {
+#if MAJOR_VERSION <= 5
         // FIXME: there is no way to know when the remote IStream is being destroyed
         //        Binder does not support testing if an object is alive, thus
         //        wait for 100ms to let the binder destruction propagates and
@@ -868,6 +868,7 @@
         //        the latency between local and remote destruction.
         IPCThreadState::self()->flushCommands();
         usleep(100 * 1000);
+#endif
     }
 
   private:
@@ -1202,19 +1203,17 @@
         waitForStreamDestruction())
 // clang-format on
 
-static void testCreateTooBigMmapBuffer(IStream* stream) {
-    MmapBufferInfo info;
-    Result res;
-    // Assume that int max is a value too big to be allocated
-    // This is true currently with a 32bit media server, but might not when it
-    // will run in 64 bit
-    auto minSizeFrames = std::numeric_limits<int32_t>::max();
-    ASSERT_OK(stream->createMmapBuffer(minSizeFrames, returnIn(res, info)));
-    ASSERT_RESULT(invalidArgsOrNotSupported, res);
+static void testMmapBufferOfInvalidSize(IStream* stream) {
+    for (int32_t value : {-1, 0, std::numeric_limits<int32_t>::max()}) {
+        MmapBufferInfo info;
+        Result res;
+        EXPECT_OK(stream->createMmapBuffer(value, returnIn(res, info)));
+        EXPECT_RESULT(invalidArgsOrNotSupported, res) << "value=" << value;
+    }
 }
 
-TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer too big should fail",
-               testCreateTooBigMmapBuffer(stream.get()))
+TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer of invalid size must fail",
+               testMmapBufferOfInvalidSize(stream.get()))
 
 static void testGetMmapPositionOfNonMmapedStream(IStream* stream) {
     Result res;
diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h
index b6e2db0..d849f85 100644
--- a/audio/core/all-versions/vts/functional/DeviceManager.h
+++ b/audio/core/all-versions/vts/functional/DeviceManager.h
@@ -22,25 +22,33 @@
 template <class Derived, class Key, class Interface>
 class InterfaceManager {
   public:
+    sp<Interface> getExisting(const Key& name) {
+        auto existing = instances.find(name);
+        return existing != instances.end() ? existing->second : sp<Interface>();
+    }
+
     sp<Interface> get(const Key& name) {
         auto existing = instances.find(name);
         if (existing != instances.end()) return existing->second;
         auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name));
         if (inserted->second) {
-            environment->registerTearDown([name]() { (void)Derived::getInstance().reset(name); });
+            environment->registerTearDown(
+                    [name]() { (void)Derived::getInstance().reset(name, false); });
         }
         return inserted->second;
     }
 
     // The test must check that reset was successful. Reset failure means that the test code
     // is holding a strong reference to the device.
-    bool reset(const Key& name) __attribute__((warn_unused_result)) {
+    bool reset(const Key& name, bool waitForDestruction) __attribute__((warn_unused_result)) {
         auto iter = instances.find(name);
         if (iter == instances.end()) return true;
         ::android::wp<Interface> weak = iter->second;
         instances.erase(iter);
         if (weak.promote() != nullptr) return false;
-        waitForInstanceDestruction();
+        if (waitForDestruction) {
+            waitForInstanceDestruction();
+        }
         return true;
     }
 
@@ -100,7 +108,15 @@
     }
     bool reset(const std::string& factoryName, const std::string& name)
             __attribute__((warn_unused_result)) {
-        return InterfaceManager::reset(std::make_tuple(factoryName, name));
+#if MAJOR_VERSION <= 5
+        return InterfaceManager::reset(std::make_tuple(factoryName, name), true);
+#elif MAJOR_VERSION >= 6
+        {
+            sp<IDevice> device = getExisting(std::make_tuple(factoryName, name));
+            if (device != nullptr) device->close();
+        }
+        return InterfaceManager::reset(std::make_tuple(factoryName, name), false);
+#endif
     }
     bool resetPrimary(const std::string& factoryName) __attribute__((warn_unused_result)) {
         return reset(factoryName, kPrimaryDevice);
diff --git a/audio/effect/6.0/IEffect.hal b/audio/effect/6.0/IEffect.hal
index b35afee..f4c50a2 100644
--- a/audio/effect/6.0/IEffect.hal
+++ b/audio/effect/6.0/IEffect.hal
@@ -407,9 +407,12 @@
 
     /**
      * Called by the framework to deinitialize the effect and free up
-     * all the currently allocated resources. It is recommended to close
+     * all currently allocated resources. It is recommended to close
      * the effect on the client side as soon as it is becomes unused.
      *
+     * The client must ensure that this function is not called while
+     * audio data is being transferred through the effect's message queues.
+     *
      * @return retval OK in case the success.
      *                INVALID_STATE if the effect was already closed.
      */
diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index 3c0d878..0afa779 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -138,11 +138,11 @@
 const char* Effect::sContextCallFunction = sContextCallToCommand;
 
 Effect::Effect(effect_handle_t handle)
-    : mIsClosed(false), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {}
+    : mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {}
 
 Effect::~Effect() {
     ATRACE_CALL();
-    close();
+    (void)close();
     if (mProcessThread.get()) {
         ATRACE_NAME("mProcessThread->join");
         status_t status = mProcessThread->join();
@@ -154,8 +154,10 @@
     }
     mInBuffer.clear();
     mOutBuffer.clear();
+#if MAJOR_VERSION <= 5
     int status = EffectRelease(mHandle);
     ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
+#endif
     EffectMap::getInstance().remove(mHandle);
     mHandle = 0;
 }
@@ -699,15 +701,20 @@
 }
 
 Return<Result> Effect::close() {
-    if (mIsClosed) return Result::INVALID_STATE;
-    mIsClosed = true;
-    if (mProcessThread.get()) {
-        mStopProcessThread.store(true, std::memory_order_release);
+    if (mStopProcessThread.load(std::memory_order_relaxed)) {  // only this thread modifies
+        return Result::INVALID_STATE;
     }
+    mStopProcessThread.store(true, std::memory_order_release);
     if (mEfGroup) {
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT));
     }
+#if MAJOR_VERSION <= 5
     return Result::OK;
+#elif MAJOR_VERSION >= 6
+    // No need to join the processing thread, it is part of the API contract that the client
+    // must finish processing before closing the effect.
+    return analyzeStatus("EffectRelease", "", sContextCallFunction, EffectRelease(mHandle));
+#endif
 }
 
 Return<void> Effect::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /* options */) {
diff --git a/audio/effect/all-versions/default/Effect.h b/audio/effect/all-versions/default/Effect.h
index 3d99a0e..181e542 100644
--- a/audio/effect/all-versions/default/Effect.h
+++ b/audio/effect/all-versions/default/Effect.h
@@ -170,7 +170,6 @@
     static const char* sContextCallToCommand;
     static const char* sContextCallFunction;
 
-    bool mIsClosed;
     effect_handle_t mHandle;
     sp<AudioBufferWrapper> mInBuffer;
     sp<AudioBufferWrapper> mOutBuffer;
diff --git a/automotive/audiocontrol/1.0/default/Android.bp b/automotive/audiocontrol/1.0/default/Android.bp
index 314830b..3d04c89 100644
--- a/automotive/audiocontrol/1.0/default/Android.bp
+++ b/automotive/audiocontrol/1.0/default/Android.bp
@@ -29,7 +29,7 @@
         "liblog",
         "libutils",
     ],
-
+    vintf_fragments: ["audiocontrol_manifest.xml"],
     cflags: [
         "-DLOG_TAG=\"AudCntrlDrv\"",
         "-O0",
diff --git a/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml b/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml
new file mode 100644
index 0000000..0981eb7
--- /dev/null
+++ b/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.automotive.audiocontrol</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IAudioControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp
index 8aa1d6b..ee2e92b 100644
--- a/automotive/can/1.0/default/Android.bp
+++ b/automotive/can/1.0/default/Android.bp
@@ -39,6 +39,7 @@
         "CanBus.cpp",
         "CanBusNative.cpp",
         "CanBusVirtual.cpp",
+        "CanBusSlcan.cpp",
         "CanController.cpp",
         "CanSocket.cpp",
         "CloseHandle.cpp",
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 38a9974..42d2e3c 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -30,9 +30,7 @@
 namespace V1_0 {
 namespace implementation {
 
-/**
- * Whether to log sent/received packets.
- */
+/** Whether to log sent/received packets. */
 static constexpr bool kSuperVerbose = false;
 
 Return<Result> CanBus::send(const CanMessage& message) {
@@ -85,6 +83,8 @@
     return {};
 }
 
+CanBus::CanBus() {}
+
 CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {}
 
 CanBus::~CanBus() {
diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h
index 30a2924..365e90c 100644
--- a/automotive/can/1.0/default/CanBus.h
+++ b/automotive/can/1.0/default/CanBus.h
@@ -48,12 +48,22 @@
     bool down();
 
   protected:
+    /**
+     * Blank constructor, since some interface types (such as SLCAN) don't get a name until after
+     * being initialized.
+     *
+     * If using this constructor, you MUST initialize mIfname prior to the completion of preUp().
+     */
+    CanBus();
+
     CanBus(const std::string& ifname);
 
     /**
      * Prepare the SocketCAN interface.
      *
      * After calling this method, mIfname network interface is available and ready to be brought up.
+     *
+     * \return OK on success, or an error state on failure. See ICanController::Result
      */
     virtual ICanController::Result preUp();
 
@@ -61,11 +71,13 @@
      * Cleanup after bringing the interface down.
      *
      * This is a counterpart to preUp().
+     *
+     * \return true upon success and false upon failure
      */
     virtual bool postDown();
 
     /** Network interface name. */
-    const std::string mIfname;
+    std::string mIfname;
 
   private:
     struct CanMessageListener {
diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp
new file mode 100644
index 0000000..7dce838
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusSlcan.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <termios.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+namespace slcanprotocol {
+static const std::string kOpenCommand = "O\r";
+static const std::string kCloseCommand = "C\r";
+static constexpr int kSlcanDiscipline = N_SLCAN;
+static constexpr int kDefaultDiscipline = N_TTY;
+
+static const std::map<uint32_t, std::string> kBitrateCommands = {
+        {10000, "C\rS0\r"},  {20000, "C\rS1\r"},  {50000, "C\rS2\r"},
+        {100000, "C\rS3\r"}, {125000, "C\rS4\r"}, {250000, "C\rS5\r"},
+        {500000, "C\rS6\r"}, {800000, "C\rS7\r"}, {1000000, "C\rS8\r"}};
+}  // namespace slcanprotocol
+
+/**
+ * Serial Line CAN constructor
+ * \param string uartName - name of slcan device (e.x. /dev/ttyUSB0)
+ * \param uint32_t bitrate - speed of the CAN bus (125k = MSCAN, 500k = HSCAN)
+ */
+CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate)
+    : CanBus(), mUartName(uartName), kBitrate(bitrate) {}
+
+ICanController::Result CanBusSlcan::preUp() {
+    // verify valid bitrate and translate to serial command format
+    const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate);
+    if (lookupIt == slcanprotocol::kBitrateCommands.end()) {
+        return ICanController::Result::BAD_BAUDRATE;
+    }
+    const auto canBitrateCommand = lookupIt->second;
+
+    /* Attempt to open the uart in r/w without blocking or becoming the
+     * controlling terminal */
+    mFd = base::unique_fd(open(mUartName.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY));
+    if (!mFd.ok()) {
+        LOG(ERROR) << "SLCAN Failed to open " << mUartName << ": " << strerror(errno);
+        return ICanController::Result::BAD_ADDRESS;
+    }
+
+    // blank terminal settings and pull them from the device
+    struct termios terminalSettings = {};
+    if (tcgetattr(mFd.get(), &terminalSettings) < 0) {
+        LOG(ERROR) << "Failed to read attrs of" << mUartName << ": " << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // change settings to raw mode
+    cfmakeraw(&terminalSettings);
+
+    // disable software flow control
+    terminalSettings.c_iflag &= ~IXOFF;
+    // enable hardware flow control
+    terminalSettings.c_cflag |= CRTSCTS;
+
+    struct serial_struct serialSettings;
+    // get serial settings
+    if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) {
+        LOG(ERROR) << "Failed to read serial settings from " << mUartName << ": "
+                   << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+    // set low latency mode
+    serialSettings.flags |= ASYNC_LOW_LATENCY;
+    // apply serial settings
+    if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) {
+        LOG(ERROR) << "Failed to set low latency mode on " << mUartName << ": " << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    /* TCSADRAIN applies settings after we finish writing the rest of our
+     * changes (as opposed to TCSANOW, which changes immediately) */
+    if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) {
+        LOG(ERROR) << "Failed to apply terminal settings to " << mUartName << ": "
+                   << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // apply speed setting for CAN
+    if (write(mFd.get(), canBitrateCommand.c_str(), canBitrateCommand.length()) <= 0) {
+        LOG(ERROR) << "Failed to apply CAN bitrate: " << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // set open flag TODO: also support listen only
+    if (write(mFd.get(), slcanprotocol::kOpenCommand.c_str(),
+              slcanprotocol::kOpenCommand.length()) <= 0) {
+        LOG(ERROR) << "Failed to set open flag: " << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // set line discipline to slcan
+    if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) {
+        LOG(ERROR) << "Failed to set line discipline to slcan: " << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // get the name of the device we created
+    struct ifreq ifrequest = {};
+    if (ioctl(mFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) {
+        LOG(ERROR) << "Failed to get the name of the created device: " << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // Update the CanBus object with name that was assigned to it
+    mIfname = ifrequest.ifr_name;
+
+    return ICanController::Result::OK;
+}
+
+bool CanBusSlcan::postDown() {
+    // reset the line discipline to TTY mode
+    if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kDefaultDiscipline) < 0) {
+        LOG(ERROR) << "Failed to reset line discipline!";
+        return false;
+    }
+
+    // issue the close command
+    if (write(mFd.get(), slcanprotocol::kCloseCommand.c_str(),
+              slcanprotocol::kCloseCommand.length()) <= 0) {
+        LOG(ERROR) << "Failed to close tty!";
+        return false;
+    }
+
+    // close our unique_fd
+    mFd.reset();
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanBusSlcan.h b/automotive/can/1.0/default/CanBusSlcan.h
new file mode 100644
index 0000000..2713da8
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <net/if.h>
+#include <termios.h>
+#include "CanBus.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+struct CanBusSlcan : public CanBus {
+    CanBusSlcan(const std::string& uartName, uint32_t bitrate);
+
+  protected:
+    virtual ICanController::Result preUp() override;
+    virtual bool postDown() override;
+
+  private:
+    const std::string mUartName;
+    const uint32_t kBitrate;
+    base::unique_fd mFd;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp
index 3b63fe4..ffdc912 100644
--- a/automotive/can/1.0/default/CanController.cpp
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -17,6 +17,7 @@
 #include "CanController.h"
 
 #include "CanBusNative.h"
+#include "CanBusSlcan.h"
 #include "CanBusVirtual.h"
 
 #include <android-base/logging.h>
@@ -34,10 +35,8 @@
 using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
 
 Return<void> CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) {
-    _hidl_cb({
-            ICanController::InterfaceType::VIRTUAL,
-            ICanController::InterfaceType::SOCKETCAN,
-    });
+    _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN,
+              ICanController::InterfaceType::SLCAN});
     return {};
 }
 
@@ -77,6 +76,12 @@
         } else {
             return ICanController::Result::BAD_ADDRESS;
         }
+    } else if (config.iftype == ICanController::InterfaceType::SLCAN) {
+        if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
+            busService = new CanBusSlcan(config.interfaceId.address(), config.baudrate);
+        } else {
+            return ICanController::Result::BAD_ADDRESS;
+        }
     } else {
         return ICanController::Result::NOT_SUPPORTED;
     }
diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp
index ecf4044..86e12d1 100644
--- a/automotive/can/1.0/default/CanSocket.cpp
+++ b/automotive/can/1.0/default/CanSocket.cpp
@@ -33,12 +33,10 @@
 
 using namespace std::chrono_literals;
 
-/**
- * How frequently the read thread checks whether the interface was asked to be down.
+/* How frequently the read thread checks whether the interface was asked to be down.
  *
  * Note: This does *not* affect read timing or bandwidth, just CPU load vs time to
- *       down the interface.
- */
+ *       down the interface. */
 static constexpr auto kReadPooling = 100ms;
 
 std::unique_ptr<CanSocket> CanSocket::open(const std::string& ifname, ReadCallback rdcb,
@@ -105,8 +103,7 @@
 
     while (!mStopReaderThread) {
         /* The ideal would be to have a blocking read(3) call and interrupt it with shutdown(3).
-         * This is unfortunately not supported for SocketCAN, so we need to rely on select(3).
-         */
+         * This is unfortunately not supported for SocketCAN, so we need to rely on select(3). */
         const auto sel = selectRead(mSocket, kReadPooling);
         if (sel == 0) continue;  // timeout
         if (sel == -1) {
@@ -127,8 +124,7 @@
          * Apart from the added complexity, it's possible the added calculations and system calls
          * would add so much time to the processing pipeline so the precision of the reported time
          * was buried under the subsystem latency. Let's just use a local time since boot here and
-         * leave precise hardware timestamps for custom proprietary implementations (if needed).
-         */
+         * leave precise hardware timestamps for custom proprietary implementations (if needed). */
         const std::chrono::nanoseconds ts(elapsedRealtimeNano());
 
         if (nbytes != CAN_MTU) {
diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h
index 284e1ea..c98330b 100644
--- a/automotive/can/1.0/default/CanSocket.h
+++ b/automotive/can/1.0/default/CanSocket.h
@@ -31,9 +31,7 @@
 namespace V1_0 {
 namespace implementation {
 
-/**
- * Wrapper around SocketCAN socket.
- */
+/** Wrapper around SocketCAN socket. */
 struct CanSocket {
     using ReadCallback = std::function<void(const struct canfd_frame&, std::chrono::nanoseconds)>;
     using ErrorCallback = std::function<void(int errnoVal)>;
diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h
index 5191739..eade109 100644
--- a/automotive/can/1.0/default/CloseHandle.h
+++ b/automotive/can/1.0/default/CloseHandle.h
@@ -26,9 +26,7 @@
 namespace V1_0 {
 namespace implementation {
 
-/**
- * Generic ICloseHandle implementation ignoring double-close events.
- */
+/** Generic ICloseHandle implementation ignoring double-close events. */
 struct CloseHandle : public ICloseHandle {
     using Callback = std::function<void()>;
 
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
index 21202e3..ba9b65b 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
@@ -27,9 +27,7 @@
 typedef unsigned short rtattrtype_t;  // as in rtnetlink.h
 typedef __u16 nlmsgtype_t;            // as in netlink.h
 
-/**
- * Implementation details, do not use outside NetlinkRequest template.
- */
+/** Implementation details, do not use outside NetlinkRequest template. */
 namespace impl {
 
 struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
@@ -59,7 +57,7 @@
         mRequest.nlmsg.nlmsg_flags = flags;
     }
 
-    /** Returns pointer to raw netlink message header. */
+    /** \return pointer to raw netlink message header. */
     struct nlmsghdr* header() {
         return &mRequest.nlmsg;
     }
@@ -89,9 +87,7 @@
         if (ap == nullptr) mIsGood = false;
     }
 
-    /**
-     * Guard class to frame nested attributes. See nest(int).
-     */
+    /** Guard class to frame nested attributes. See nest(int). */
     struct Nest {
         Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
         ~Nest() { mReq.nestEnd(mAttr); }
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
index 81d6224..90e1f3f 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
@@ -38,8 +38,8 @@
     /**
      * Send Netlink message to Kernel.
      *
-     * @param msg Message to send, nlmsg_seq will be set to next sequence number
-     * @return true, if succeeded
+     * \param msg Message to send, nlmsg_seq will be set to next sequence number
+     * \return true, if succeeded
      */
     template <class T, unsigned int BUFSIZE>
     bool send(NetlinkRequest<T, BUFSIZE>& req) {
@@ -50,7 +50,7 @@
     /**
      * Receive Netlink ACK message from Kernel.
      *
-     * @return true if received ACK message, false in case of error
+     * \return true if received ACK message, false in case of error
      */
     bool receiveAck();
 
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
index ec3f962..d75361e 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
@@ -27,13 +27,16 @@
 /**
  * Opens and binds SocketCAN socket.
  *
- * @param ifname Interface to open a socket against
- * @return Socket's FD or -1 in case of failure
+ * \param ifname Interface to open a socket against
+ * \return Socket's FD or -1 in case of failure
  */
 base::unique_fd socket(const std::string& ifname);
 
 /**
  * Sets CAN interface bitrate.
+ *
+ * \param ifname Interface for which the bitrate is to be set
+ * \return true on success, false on failure
  */
 bool setBitrate(std::string ifname, uint32_t bitrate);
 
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
index 33d5de5..e22eafb 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -25,49 +25,49 @@
 /**
  * Checks, if the network interface exists.
  *
- * @param ifname Interface to check
- * @return true if it exists, false otherwise
+ * \param ifname Interface to check
+ * \return true if it exists, false otherwise
  */
 bool exists(std::string ifname);
 
 /**
  * Checks if network interface is up.
  *
- * @param ifname Interface to check
- * @return true/false if the check succeeded, nullopt otherwise
+ * \param ifname Interface to check
+ * \return true/false if the check succeeded, nullopt otherwise
  */
 std::optional<bool> isUp(std::string ifname);
 
 /**
  * Brings network interface up.
  *
- * @param ifname Interface to bring up
- * @return true in case of success, false otherwise
+ * \param ifname Interface to bring up
+ * \return true in case of success, false otherwise
  */
 bool up(std::string ifname);
 
 /**
  * Brings network interface down.
  *
- * @param ifname Interface to bring down
- * @return true in case of success, false otherwise
+ * \param ifname Interface to bring down
+ * \return true in case of success, false otherwise
  */
 bool down(std::string ifname);
 
 /**
  * Adds virtual link.
  *
- * @param dev the name of the new virtual device
- * @param type the type of the new device
- * @return true in case of success, false otherwise
+ * \param dev the name of the new virtual device
+ * \param type the type of the new device
+ * \return true in case of success, false otherwise
  */
 bool add(std::string dev, std::string type);
 
 /**
  * Deletes virtual link.
  *
- * @param dev the name of the device to remove
- * @return true in case of success, false otherwise
+ * \param dev the name of the device to remove
+ * \return true in case of success, false otherwise
  */
 bool del(std::string dev);
 
diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp
index 5713d17..99fd14a 100644
--- a/automotive/can/1.0/tools/canhaldump.cpp
+++ b/automotive/can/1.0/tools/canhaldump.cpp
@@ -49,7 +49,7 @@
         } else {
             std::cout << "   [" << message.payload.size() << "] ";
             for (const auto byte : message.payload) {
-                std::cout << " " << unsigned(byte);
+                std::cout << " " << std::setfill('0') << std::setw(2) << unsigned(byte);
             }
         }
         std::cout << std::nouppercase << std::dec << std::endl;
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
index ba29c29..225984d 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -91,8 +91,7 @@
         EXPECT_EQ(ICanController::Result::OK, result);
 
         /* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
-         * file -- this is a test, so we don't want to add dummy services to a device manifest.
-         */
+         * file -- this is a test, so we don't want to add dummy services to a device manifest. */
         auto manager = hidl::manager::V1_2::IServiceManager::getService();
         auto service = manager->get(ICanBus::descriptor, config.name);
         mBus = ICanBus::castFrom(service);
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
index 70f9fe4..64e7a96 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -95,8 +95,7 @@
 
 void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) {
     /* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
-     * file -- this is a test, so we don't want to add dummy services to a device manifest.
-     */
+     * file -- this is a test, so we don't want to add dummy services to a device manifest. */
     auto manager = hidl::manager::V1_2::IServiceManager::getService();
     auto busService = manager->get(ICanBus::descriptor, srvname);
     ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
new file mode 100644
index 0000000..56ecd67
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_VehicleConnector_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleConnector_H_
+
+#include <vector>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+/**
+ *  This file defines the interface of client/server pair for HAL-vehicle
+ *  communication. Vehicle HAL may use this interface to talk to the vehicle
+ *  regardless of the underlying communication channels.
+ */
+
+/**
+ *  Vehicle HAL talks to the vehicle through a client, instead of accessing
+ *  the car bus directly, to give us more flexibility on the implementation.
+ *  Android OS do not need direct access to the vehicle, and the communication
+ *  channel is also customizable.
+ *
+ *  Client lives on the Android (HAL) side to talk to the vehicle
+ */
+class IVehicleClient {
+  public:
+    IVehicleClient() = default;
+
+    IVehicleClient(const IVehicleClient&) = delete;
+
+    IVehicleClient& operator=(const IVehicleClient&) = delete;
+
+    IVehicleClient(IVehicleClient&&) = default;
+
+    virtual ~IVehicleClient() = default;
+
+    // Get configuration of all properties from server
+    virtual std::vector<VehiclePropConfig> getAllPropertyConfig() const = 0;
+
+    // Send the set property request to server
+    virtual StatusCode setProperty(const VehiclePropValue& value) = 0;
+
+    // Receive a new property value from server
+    virtual void onPropertyValue(const VehiclePropValue& value) = 0;
+};
+
+/**
+ *  Server lives on the vehicle side to talk to Android HAL
+ */
+class IVehicleServer {
+  public:
+    IVehicleServer() = default;
+
+    IVehicleServer(const IVehicleServer&) = delete;
+
+    IVehicleServer& operator=(const IVehicleServer&) = delete;
+
+    IVehicleServer(IVehicleServer&&) = default;
+
+    virtual ~IVehicleServer() = default;
+
+    // Receive the get property configuration request from HAL.
+    // Return a list of all property config
+    virtual std::vector<VehiclePropConfig> onGetAllPropertyConfig() const = 0;
+
+    // Receive the set property request from HAL.
+    // Process the setting and return the status code
+    virtual StatusCode onSetProperty(const VehiclePropValue& value) = 0;
+
+    // Receive a new property value from car (via direct connection to the car bus or the emulator)
+    // and forward the value to HAL
+    virtual void onPropertyValueFromCar(const VehiclePropValue& value) = 0;
+};
+
+/**
+ *  If Android has direct access to the vehicle, then the client and
+ *  the server may act in passthrough mode to avoid extra IPC
+ *
+ *  Template is used here for spliting the logic of operating Android objects (VehicleClientType),
+ *  talking to cars (VehicleServerType) and the commucation between client and server (passthrough
+ *  mode in this case), so that we can easily combine different parts together without duplicating
+ *  codes (for example, in Google VHAL, the server talks to the fake car in the same way no matter
+ *  if it is on top of passthrough connector or VSOCK or any other communication channels between
+ *  client and server)
+ *
+ *  The alternative may be factoring the common logic of every operations for both client and
+ *  server. Which is not always the case. Making sure different non-template connectors calling
+ *  the same method is hard, especially when the engineer maintaining the code may not be aware
+ *  of it when making changes. Template is a clean and easy way to solve this problem in this
+ *  case.
+ */
+template <typename VehicleClientType, typename VehicleServerType>
+class IPassThroughConnector : public VehicleClientType, public VehicleServerType {
+    static_assert(std::is_base_of_v<IVehicleClient, VehicleClientType>);
+    static_assert(std::is_base_of_v<IVehicleServer, VehicleServerType>);
+
+  public:
+    std::vector<VehiclePropConfig> getAllPropertyConfig() const override {
+        return this->onGetAllPropertyConfig();
+    }
+
+    StatusCode setProperty(const VehiclePropValue& value) override {
+        return this->onSetProperty(value);
+    }
+
+    void onPropertyValueFromCar(const VehiclePropValue& value) override {
+        return this->onPropertyValue(value);
+    }
+
+    // To be implemented:
+    // virtual std::vector<VehiclePropConfig> onGetAllPropertyConfig() = 0;
+    // virtual void onPropertyValue(const VehiclePropValue& value) = 0;
+    // virtual StatusCode onSetProperty(const VehiclePropValue& value) = 0;
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_VehicleConnector_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
index 8ee3c54..f8b10ca 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
@@ -61,7 +61,7 @@
 
 struct VmsLayerAndPublisher {
     VmsLayerAndPublisher(VmsLayer layer, int publisher_id)
-        : layer(layer), publisher_id(publisher_id) {}
+        : layer(std::move(layer)), publisher_id(publisher_id) {}
     VmsLayer layer;
     int publisher_id;
 };
@@ -69,6 +69,8 @@
 // A VmsAssociatedLayer is used by subscribers to specify which publisher IDs
 // are acceptable for a given layer.
 struct VmsAssociatedLayer {
+    VmsAssociatedLayer(VmsLayer layer, std::vector<int> publisher_ids)
+        : layer(std::move(layer)), publisher_ids(std::move(publisher_ids)) {}
     VmsLayer layer;
     std::vector<int> publisher_ids;
 };
@@ -77,7 +79,7 @@
 // its dependencies. Dependencies can be empty.
 struct VmsLayerOffering {
     VmsLayerOffering(VmsLayer layer, std::vector<VmsLayer> dependencies)
-        : layer(layer), dependencies(dependencies) {}
+        : layer(std::move(layer)), dependencies(std::move(dependencies)) {}
     VmsLayerOffering(VmsLayer layer) : layer(layer), dependencies() {}
     VmsLayer layer;
     std::vector<VmsLayer> dependencies;
@@ -87,7 +89,7 @@
 // with the specified publisher ID.
 struct VmsOffers {
     VmsOffers(int publisher_id, std::vector<VmsLayerOffering> offerings)
-        : publisher_id(publisher_id), offerings(offerings) {}
+        : publisher_id(publisher_id), offerings(std::move(offerings)) {}
     int publisher_id;
     std::vector<VmsLayerOffering> offerings;
 };
@@ -231,6 +233,24 @@
                                           const int current_service_id, const int current_client_id,
                                           int* new_service_id);
 
+// Returns true if the new sequence number of the availability state message is greater than
+// the last seen availability sequence number.
+bool isAvailabilitySequenceNumberNewer(const VehiclePropValue& availability_state,
+                                       const int last_seen_availability_sequence_number);
+
+// Returns sequence number of the availability state message.
+int32_t getSequenceNumberForAvailabilityState(const VehiclePropValue& availability_state);
+
+// Takes a availability state message and returns the associated layers that are
+// available to publish data.
+//
+// A subscriber can use this function when receiving an availability response or availability
+// change message to determine which associated layers are ready to publish data.
+// The caller of this function can optionally decide to not consume these layers
+// if the availability change has the sequence number less than the last seen
+// sequence number.
+std::vector<VmsAssociatedLayer> getAvailableLayers(const VehiclePropValue& availability_state);
+
 }  // namespace vms
 }  // namespace V2_0
 }  // namespace vehicle
diff --git a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
index 9eba905..a65cded 100644
--- a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
@@ -219,12 +219,9 @@
     if (isValidVmsMessage(subscriptions_state) &&
         (parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_CHANGE ||
          parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_RESPONSE) &&
-        subscriptions_state.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
-        const int32_t num_of_layers = subscriptions_state.value.int32Values[toInt(
-                VmsSubscriptionsStateIntegerValuesIndex::NUMBER_OF_LAYERS)];
-        const int32_t num_of_associated_layers = subscriptions_state.value.int32Values[toInt(
-                VmsSubscriptionsStateIntegerValuesIndex ::NUMBER_OF_ASSOCIATED_LAYERS)];
-
+        subscriptions_state.value.int32Values.size() >
+                toInt(VmsSubscriptionsStateIntegerValuesIndex::NUMBER_OF_LAYERS)) {
+        int subscriptions_state_int_size = subscriptions_state.value.int32Values.size();
         std::unordered_set<VmsLayer, VmsLayer::VmsLayerHashFunction> offered_layers;
         for (const auto& offer : offers.offerings) {
             offered_layers.insert(offer.layer);
@@ -232,33 +229,52 @@
         std::vector<VmsLayer> subscribed_layers;
 
         int current_index = toInt(VmsSubscriptionsStateIntegerValuesIndex::SUBSCRIPTIONS_START);
+
         // Add all subscribed layers which are offered by the current publisher.
+        const int32_t num_of_layers = subscriptions_state.value.int32Values[toInt(
+                VmsSubscriptionsStateIntegerValuesIndex::NUMBER_OF_LAYERS)];
         for (int i = 0; i < num_of_layers; i++) {
+            if (subscriptions_state_int_size < current_index + kLayerSize) {
+                return {};
+            }
             VmsLayer layer = VmsLayer(subscriptions_state.value.int32Values[current_index],
                                       subscriptions_state.value.int32Values[current_index + 1],
                                       subscriptions_state.value.int32Values[current_index + 2]);
             if (offered_layers.find(layer) != offered_layers.end()) {
-                subscribed_layers.push_back(layer);
+                subscribed_layers.push_back(std::move(layer));
             }
             current_index += kLayerSize;
         }
+
         // Add all subscribed associated layers which are offered by the current publisher.
         // For this, we need to check if the associated layer has a publisher ID which is
         // same as that of the current publisher.
-        for (int i = 0; i < num_of_associated_layers; i++) {
-            VmsLayer layer = VmsLayer(subscriptions_state.value.int32Values[current_index],
-                                      subscriptions_state.value.int32Values[current_index + 1],
-                                      subscriptions_state.value.int32Values[current_index + 2]);
-            current_index += kLayerSize;
-            if (offered_layers.find(layer) != offered_layers.end()) {
-                int32_t num_of_publisher_ids = subscriptions_state.value.int32Values[current_index];
-                current_index++;
-                for (int j = 0; j < num_of_publisher_ids; j++) {
-                    if (subscriptions_state.value.int32Values[current_index] ==
-                        offers.publisher_id) {
-                        subscribed_layers.push_back(layer);
-                    }
+        if (subscriptions_state_int_size >
+            toInt(VmsSubscriptionsStateIntegerValuesIndex::NUMBER_OF_ASSOCIATED_LAYERS)) {
+            const int32_t num_of_associated_layers = subscriptions_state.value.int32Values[toInt(
+                    VmsSubscriptionsStateIntegerValuesIndex::NUMBER_OF_ASSOCIATED_LAYERS)];
+
+            for (int i = 0; i < num_of_associated_layers; i++) {
+                if (subscriptions_state_int_size < current_index + kLayerSize) {
+                    return {};
+                }
+                VmsLayer layer = VmsLayer(subscriptions_state.value.int32Values[current_index],
+                                          subscriptions_state.value.int32Values[current_index + 1],
+                                          subscriptions_state.value.int32Values[current_index + 2]);
+                current_index += kLayerSize;
+                if (offered_layers.find(layer) != offered_layers.end() &&
+                    subscriptions_state_int_size > current_index) {
+                    int32_t num_of_publisher_ids =
+                            subscriptions_state.value.int32Values[current_index];
                     current_index++;
+                    for (int j = 0; j < num_of_publisher_ids; j++) {
+                        if (subscriptions_state_int_size > current_index &&
+                            subscriptions_state.value.int32Values[current_index] ==
+                                    offers.publisher_id) {
+                            subscribed_layers.push_back(std::move(layer));
+                        }
+                        current_index++;
+                    }
                 }
             }
         }
@@ -300,6 +316,64 @@
     return VmsSessionStatus::kInvalidMessage;
 }
 
+bool isAvailabilitySequenceNumberNewer(const VehiclePropValue& availability_state,
+                                       const int last_seen_availability_sequence_number) {
+    return (isValidVmsMessage(availability_state) &&
+            (parseMessageType(availability_state) == VmsMessageType::AVAILABILITY_CHANGE ||
+             parseMessageType(availability_state) == VmsMessageType::AVAILABILITY_RESPONSE) &&
+            availability_state.value.int32Values.size() > kAvailabilitySequenceNumberIndex &&
+            availability_state.value.int32Values[kAvailabilitySequenceNumberIndex] >
+                    last_seen_availability_sequence_number);
+}
+
+int32_t getSequenceNumberForAvailabilityState(const VehiclePropValue& availability_state) {
+    if (isValidVmsMessage(availability_state) &&
+        (parseMessageType(availability_state) == VmsMessageType::AVAILABILITY_CHANGE ||
+         parseMessageType(availability_state) == VmsMessageType::AVAILABILITY_RESPONSE) &&
+        availability_state.value.int32Values.size() > kAvailabilitySequenceNumberIndex) {
+        return availability_state.value.int32Values[kAvailabilitySequenceNumberIndex];
+    }
+    return -1;
+}
+
+std::vector<VmsAssociatedLayer> getAvailableLayers(const VehiclePropValue& availability_state) {
+    if (isValidVmsMessage(availability_state) &&
+        (parseMessageType(availability_state) == VmsMessageType::AVAILABILITY_CHANGE ||
+         parseMessageType(availability_state) == VmsMessageType::AVAILABILITY_RESPONSE) &&
+        availability_state.value.int32Values.size() >
+                toInt(VmsAvailabilityStateIntegerValuesIndex::NUMBER_OF_ASSOCIATED_LAYERS)) {
+        int availability_state_int_size = availability_state.value.int32Values.size();
+        const int32_t num_of_associated_layers = availability_state.value.int32Values[toInt(
+                VmsAvailabilityStateIntegerValuesIndex::NUMBER_OF_ASSOCIATED_LAYERS)];
+        int current_index = toInt(VmsAvailabilityStateIntegerValuesIndex::LAYERS_START);
+        std::vector<VmsAssociatedLayer> available_layers;
+        for (int i = 0; i < num_of_associated_layers; i++) {
+            if (availability_state_int_size < current_index + kLayerSize) {
+                return {};
+            }
+            VmsLayer layer = VmsLayer(availability_state.value.int32Values[current_index],
+                                      availability_state.value.int32Values[current_index + 1],
+                                      availability_state.value.int32Values[current_index + 2]);
+            current_index += kLayerSize;
+            std::vector<int> publisher_ids;
+            if (availability_state_int_size > current_index) {
+                int32_t num_of_publisher_ids = availability_state.value.int32Values[current_index];
+                current_index++;
+                for (int j = 0; j < num_of_publisher_ids; j++) {
+                    if (availability_state_int_size > current_index) {
+                        publisher_ids.push_back(
+                                availability_state.value.int32Values[current_index]);
+                        current_index++;
+                    }
+                }
+            }
+            available_layers.emplace_back(layer, std::move(publisher_ids));
+        }
+        return available_layers;
+    }
+    return {};
+}
+
 }  // namespace vms
 }  // namespace V2_0
 }  // namespace vehicle
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 f41b33c..2dbcbba 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
@@ -948,6 +948,24 @@
                     .access = VehiclePropertyAccess::READ_WRITE,
                     .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
          .initialValue = {.stringValue = "Vendor String Property"}},
+
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .configArray =
+                                 {kMixedTypePropertyForTest,
+                                  (int)VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_INFO,
+                                  (int)VehicleVendorPermission::PERMISSION_SET_VENDOR_CATEGORY_INFO,
+                                  VENDOR_EXTENSION_INT_PROPERTY,
+                                  (int)VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_SEAT,
+                                  (int)VehicleVendorPermission::PERMISSION_NOT_ACCESSIBLE,
+                                  VENDOR_EXTENSION_FLOAT_PROPERTY,
+                                  (int)VehicleVendorPermission::PERMISSION_DEFAULT,
+                                  (int)VehicleVendorPermission::PERMISSION_DEFAULT},
+                 },
+         .initialValue = {.int32Values = {1}}},
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
index 9eb8894..068333c 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
@@ -92,7 +92,10 @@
     }
 
     ALOGI("%s: Listening for connections on port %d", __FUNCTION__, DEBUG_SOCKET);
-    ::listen(mListenFd, 1);
+    if (::listen(mListenFd, 1) == -1) {
+        ALOGE("%s: Error on listening: errno: %d: %s", __FUNCTION__, errno, strerror(errno));
+        return false;
+    }
     return true;
 }
 
diff --git a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
index 8b547f1..a48d19c 100644
--- a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
@@ -279,7 +279,7 @@
     VmsOffers offers = {123,
                         {VmsLayerOffering(VmsLayer(1, 0, 1), {VmsLayer(4, 1, 1)}),
                          VmsLayerOffering(VmsLayer(2, 0, 1))}};
-    auto message = createBaseVmsMessage(2);
+    auto message = createBaseVmsMessage(16);
     message->value.int32Values = hidl_vec<int32_t>{toInt(type),
                                                    1234,  // sequence number
                                                    2,     // number of layers
@@ -308,9 +308,28 @@
     testSubscribedLayers(VmsMessageType::SUBSCRIPTIONS_RESPONSE);
 }
 
+void testGetSubscribedLayersMalformedData(VmsMessageType type) {
+    VmsOffers offers = {123,
+                        {VmsLayerOffering(VmsLayer(1, 0, 1), {VmsLayer(4, 1, 1)}),
+                         VmsLayerOffering(VmsLayer(2, 0, 1))}};
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values = hidl_vec<int32_t>{toInt(type), 1234};  // sequence number
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    auto result = getSubscribedLayers(*message, offers);
+    EXPECT_EQ(static_cast<int>(result.size()), 0);
+}
+
+TEST(VmsUtilsTest, subscribedLayersForMalformedChange) {
+    testGetSubscribedLayersMalformedData(VmsMessageType::SUBSCRIPTIONS_CHANGE);
+}
+
+TEST(VmsUtilsTest, subscribedLayersForMalformedResponse) {
+    testGetSubscribedLayersMalformedData(VmsMessageType::SUBSCRIPTIONS_RESPONSE);
+}
+
 void testSubscribedLayersWithDifferentSubtype(VmsMessageType type) {
     VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
-    auto message = createBaseVmsMessage(2);
+    auto message = createBaseVmsMessage(7);
     message->value.int32Values = hidl_vec<int32_t>{toInt(type),
                                                    1234,  // sequence number
                                                    1,     // number of layers
@@ -332,7 +351,7 @@
 
 void subscribedLayersWithDifferentVersion(VmsMessageType type) {
     VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
-    auto message = createBaseVmsMessage(2);
+    auto message = createBaseVmsMessage(7);
     message->value.int32Values = hidl_vec<int32_t>{toInt(type),
                                                    1234,             // sequence number
                                                    1,                // number of layers
@@ -353,7 +372,7 @@
 
 void subscribedLayersWithDifferentPublisherId(VmsMessageType type) {
     VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
-    auto message = createBaseVmsMessage(2);
+    auto message = createBaseVmsMessage(9);
     message->value.int32Values = hidl_vec<int32_t>{toInt(type),
                                                    1234,  // sequence number
                                                    0,     // number of layers
@@ -475,6 +494,113 @@
     EXPECT_EQ(new_service_id, 123);
 }
 
+TEST(VmsUtilsTest, newAvailabilitySequenceNumberForExistingSmallerNumberForChange) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_CHANGE), 1234};
+    EXPECT_TRUE(isAvailabilitySequenceNumberNewer(*message, 1233));
+}
+
+TEST(VmsUtilsTest, newAvailabilitySequenceNumberForExistingSmallerNumberForResponse) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_RESPONSE), 1234};
+    EXPECT_TRUE(isAvailabilitySequenceNumberNewer(*message, 1233));
+}
+
+TEST(VmsUtilsTest, newAvailabilitySequenceNumberForExistingGreaterNumberForChange) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_CHANGE), 1234};
+    EXPECT_FALSE(isAvailabilitySequenceNumberNewer(*message, 1235));
+}
+
+TEST(VmsUtilsTest, newAvailabilitySequenceNumberForExistingGreaterNumberForResponse) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_RESPONSE), 1234};
+    EXPECT_FALSE(isAvailabilitySequenceNumberNewer(*message, 1235));
+}
+
+TEST(VmsUtilsTest, newAvailabilitySequenceNumberForSameNumberForChange) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_CHANGE), 1234};
+    EXPECT_FALSE(isAvailabilitySequenceNumberNewer(*message, 1234));
+}
+
+TEST(VmsUtilsTest, newAvailabilitySequenceNumberForSameNumberForResponse) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_RESPONSE), 1234};
+    EXPECT_FALSE(isAvailabilitySequenceNumberNewer(*message, 1234));
+}
+
+TEST(VmsUtilsTest, validSequenceNumberForAvailabilityChange) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_CHANGE), 1234};
+    EXPECT_EQ(getSequenceNumberForAvailabilityState(*message), 1234);
+}
+
+TEST(VmsUtilsTest, validSequenceNumberForAvailabilityResponse) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_RESPONSE), 1234};
+    EXPECT_EQ(getSequenceNumberForAvailabilityState(*message), 1234);
+}
+
+TEST(VmsUtilsTest, invalidAvailabilityState) {
+    auto message = createBaseVmsMessage(1);
+    EXPECT_EQ(getSequenceNumberForAvailabilityState(*message), -1);
+}
+
+void testGetAvailableLayers(VmsMessageType type) {
+    auto message = createBaseVmsMessage(13);
+    message->value.int32Values = hidl_vec<int32_t>{toInt(type),
+                                                   1234,  // sequence number
+                                                   2,     // number of associated layers
+                                                   1,     // associated layer 1
+                                                   0,           1,
+                                                   2,    // number of publisher IDs
+                                                   111,  // publisher IDs
+                                                   123,
+                                                   2,                   // associated layer 2
+                                                   0,           1, 0};  // number of publisher IDs
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    auto result = getAvailableLayers(*message);
+    EXPECT_EQ(static_cast<int>(result.size()), 2);
+    EXPECT_EQ(result.at(0).layer, VmsLayer(1, 0, 1));
+    EXPECT_EQ(result.at(0).publisher_ids.at(0), 111);
+    EXPECT_EQ(result.at(0).publisher_ids.at(1), 123);
+    EXPECT_EQ(result.at(1).layer, VmsLayer(2, 0, 1));
+    EXPECT_EQ(static_cast<int>(result.at(1).publisher_ids.size()), 0);
+}
+
+TEST(VmsUtilsTest, availableLayersForChange) {
+    testGetAvailableLayers(VmsMessageType::AVAILABILITY_CHANGE);
+}
+
+TEST(VmsUtilsTest, availableLayersForResponse) {
+    testGetAvailableLayers(VmsMessageType::AVAILABILITY_RESPONSE);
+}
+
+void testGetAvailableLayersMalformedData(VmsMessageType type) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values = hidl_vec<int32_t>{toInt(type), 1234};  // sequence number
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    auto result = getAvailableLayers(*message);
+    EXPECT_EQ(static_cast<int>(result.size()), 0);
+}
+
+TEST(VmsUtilsTest, availableLayersForMalformedChange) {
+    testGetAvailableLayersMalformedData(VmsMessageType::AVAILABILITY_CHANGE);
+}
+
+TEST(VmsUtilsTest, availableLayersForMalformedResponse) {
+    testGetAvailableLayersMalformedData(VmsMessageType::AVAILABILITY_RESPONSE);
+}
+
 }  // namespace
 
 }  // namespace vms
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index bc0b4d3..279d5cd 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -2349,6 +2349,96 @@
         | VehiclePropertyType:INT32
         | VehicleArea:SEAT),
 
+    /**
+     * Support customize permissions for vendor properties
+     *
+     * Implement this property if vehicle hal support customize vendor permissions feature.
+     * VehiclePropConfig.configArray is used to indicate vendor properties and permissions
+     * which selected for this vendor property. The permission must be one of enum in
+     * VehicleVendorPermission.
+     * The configArray is set as follows:
+     *      configArray[n] = propId : property ID for the vendor property
+     *      configArray[n+1] = one of enums in VehicleVendorPermission. It indicates the permission
+     *      for reading value of the property.
+     *      configArray[n+2] = one of enums in VehicleVendorPermission. It indicates the permission
+     *      for writing value of the property.
+     *
+     * For example:
+     * configArray = {
+     *      vendor_prop_1, PERMISSION_VENDOR_SEAT_READ, PERMISSION_VENDOR_SEAT_WRITE,
+     *      vendor_prop_2, PERMISSION_VENDOR_INFO, PERMISSION_NOT_ACCESSIBLE,
+     * }
+     * If vendor properties are not in this array, they will have the default vendor permission.
+     * If vendor chose PERMISSION_NOT_ACCESSIBLE, android will not have access to the property. In
+     * the example, Android can not write value for vendor_prop_2.
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     */
+    SUPPORT_CUSTOMIZE_VENDOR_PERMISSION = (
+        0x0F05
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BOOLEAN
+        | VehicleArea:GLOBAL),
+
+};
+
+/**
+ * Used by SUPPORT_CUSTOMIZE_VENDOR_PERMISSION to indicate the permission of vendor properties.
+ */
+enum VehicleVendorPermission : int32_t {
+    PERMISSION_DEFAULT = 0x00000000,
+
+    // permissions for the property related with window
+    PERMISSION_SET_VENDOR_CATEGORY_WINDOW= 0X00000001,
+    PERMISSION_GET_VENDOR_CATEGORY_WINDOW = 0x00000002,
+    // permissions for the property related with door
+    PERMISSION_SET_VENDOR_CATEGORY_DOOR  = 0x00000003,
+    PERMISSION_GET_VENDOR_CATEGORY_DOOR   = 0x00000004,
+    // permissions for the property related with seat
+    PERMISSION_SET_VENDOR_CATEGORY_SEAT  = 0x00000005,
+    PERMISSION_GET_VENDOR_CATEGORY_SEAT   = 0x00000006,
+    // permissions for the property related with mirror
+    PERMISSION_SET_VENDOR_CATEGORY_MIRROR= 0x00000007,
+    PERMISSION_GET_VENDOR_CATEGORY_MIRROR = 0x00000008,
+
+    // permissions for the property related with car's information
+    PERMISSION_SET_VENDOR_CATEGORY_INFO  = 0x00000009,
+    PERMISSION_GET_VENDOR_CATEGORY_INFO   = 0x0000000A,
+    // permissions for the property related with car's engine
+    PERMISSION_SET_VENDOR_CATEGORY_ENGINE= 0x0000000B,
+    PERMISSION_GET_VENDOR_CATEGORY_ENGINE = 0x0000000C,
+    // permissions for the property related with car's HVAC
+    PERMISSION_SET_VENDOR_CATEGORY_HVAC  = 0x0000000D,
+    PERMISSION_GET_VENDOR_CATEGORY_HVAC   = 0x0000000E,
+    // permissions for the property related with car's light
+    PERMISSION_SET_VENDOR_CATEGORY_LIGHT = 0x0000000F,
+    PERMISSION_GET_VENDOR_CATEGORY_LIGHT  = 0x00000010,
+
+    // permissions reserved for other vendor permission
+    PERMISSION_SET_VENDOR_CATEGORY_1  = 0x00010000,
+    PERMISSION_GET_VENDOR_CATEGORY_1   = 0x00011000,
+    PERMISSION_SET_VENDOR_CATEGORY_2  = 0x00020000,
+    PERMISSION_GET_VENDOR_CATEGORY_2   = 0x00021000,
+    PERMISSION_SET_VENDOR_CATEGORY_3  = 0x00030000,
+    PERMISSION_GET_VENDOR_CATEGORY_3   = 0x00031000,
+    PERMISSION_SET_VENDOR_CATEGORY_4  = 0x00040000,
+    PERMISSION_GET_VENDOR_CATEGORY_4   = 0x00041000,
+    PERMISSION_SET_VENDOR_CATEGORY_5  = 0x00050000,
+    PERMISSION_GET_VENDOR_CATEGORY_5   = 0x00051000,
+    PERMISSION_SET_VENDOR_CATEGORY_6  = 0x00060000,
+    PERMISSION_GET_VENDOR_CATEGORY_6   = 0x00061000,
+    PERMISSION_SET_VENDOR_CATEGORY_7  = 0x00070000,
+    PERMISSION_GET_VENDOR_CATEGORY_7   = 0x00071000,
+    PERMISSION_SET_VENDOR_CATEGORY_8  = 0x00080000,
+    PERMISSION_GET_VENDOR_CATEGORY_8   = 0x00081000,
+    PERMISSION_SET_VENDOR_CATEGORY_9  = 0x00090000,
+    PERMISSION_GET_VENDOR_CATEGORY_9   = 0x00091000,
+    PERMISSION_SET_VENDOR_CATEGORY_10 = 0x000A0000,
+    PERMISSION_GET_VENDOR_CATEGORY_10  = 0x000A1000,
+
+    // Indicate not available for android to access.
+    PERMISSION_NOT_ACCESSIBLE = 0xF0000000
 };
 
 /**
diff --git a/bluetooth/1.0/default/bluetooth_hci.cc b/bluetooth/1.0/default/bluetooth_hci.cc
index e14e3d7..a2211f4 100644
--- a/bluetooth/1.0/default/bluetooth_hci.cc
+++ b/bluetooth/1.0/default/bluetooth_hci.cc
@@ -89,6 +89,9 @@
         if (!hidl_status.isOk()) {
           ALOGE("VendorInterface -> Unable to call scoDataReceived()");
         }
+      },
+      [cb](const hidl_vec<uint8_t>&) {
+        ALOGE("VendorInterface -> No callback for ISO packets in HAL V1_0");
       });
   if (!rc) {
     auto hidl_status = cb->initializationComplete(Status::INITIALIZATION_ERROR);
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
index 98e3273..8c24f76 100644
--- a/bluetooth/1.0/default/h4_protocol.cc
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -58,6 +58,9 @@
     case HCI_PACKET_TYPE_SCO_DATA:
       sco_cb_(hci_packetizer_.GetPacket());
       break;
+    case HCI_PACKET_TYPE_ISO_DATA:
+      iso_cb_(hci_packetizer_.GetPacket());
+      break;
     default:
       LOG_ALWAYS_FATAL("%s: Unimplemented packet type %d", __func__,
                        static_cast<int>(hci_packet_type_));
diff --git a/bluetooth/1.0/default/h4_protocol.h b/bluetooth/1.0/default/h4_protocol.h
index 0d0a1ca..0c82fd6 100644
--- a/bluetooth/1.0/default/h4_protocol.h
+++ b/bluetooth/1.0/default/h4_protocol.h
@@ -31,11 +31,12 @@
 class H4Protocol : public HciProtocol {
  public:
   H4Protocol(int fd, PacketReadCallback event_cb, PacketReadCallback acl_cb,
-             PacketReadCallback sco_cb)
+             PacketReadCallback sco_cb, PacketReadCallback iso_cb)
       : uart_fd_(fd),
         event_cb_(event_cb),
         acl_cb_(acl_cb),
         sco_cb_(sco_cb),
+        iso_cb_(iso_cb),
         hci_packetizer_([this]() { OnPacketReady(); }) {}
 
   size_t Send(uint8_t type, const uint8_t* data, size_t length);
@@ -50,6 +51,7 @@
   PacketReadCallback event_cb_;
   PacketReadCallback acl_cb_;
   PacketReadCallback sco_cb_;
+  PacketReadCallback iso_cb_;
 
   HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
   hci::HciPacketizer hci_packetizer_;
diff --git a/bluetooth/1.0/default/hci_internals.h b/bluetooth/1.0/default/hci_internals.h
index 1e1f300..24e944f 100644
--- a/bluetooth/1.0/default/hci_internals.h
+++ b/bluetooth/1.0/default/hci_internals.h
@@ -24,7 +24,8 @@
   HCI_PACKET_TYPE_COMMAND = 1,
   HCI_PACKET_TYPE_ACL_DATA = 2,
   HCI_PACKET_TYPE_SCO_DATA = 3,
-  HCI_PACKET_TYPE_EVENT = 4
+  HCI_PACKET_TYPE_EVENT = 4,
+  HCI_PACKET_TYPE_ISO_DATA = 5,
 };
 
 // 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
diff --git a/bluetooth/1.0/default/test/h4_protocol_unittest.cc b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
index ba56c0d..283243d 100644
--- a/bluetooth/1.0/default/test/h4_protocol_unittest.cc
+++ b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
@@ -42,11 +42,15 @@
 static char sample_data1[100] = "A point is that which has no part.";
 static char sample_data2[100] = "A line is breadthless length.";
 static char sample_data3[100] = "The ends of a line are points.";
+static char sample_data4[100] =
+    "A plane surface is a surface which lies evenly with the straight ...";
 static char acl_data[100] =
     "A straight line is a line which lies evenly with the points on itself.";
 static char sco_data[100] =
     "A surface is that which has length and breadth only.";
 static char event_data[100] = "The edges of a surface are lines.";
+static char iso_data[100] =
+    "A plane angle is the inclination to one another of two lines in a ...";
 
 MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
   size_t length = strlen(payload) + preamble_length;
@@ -75,9 +79,9 @@
 
     int sockfd[2];
     socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
-    H4Protocol* h4_hci =
-        new H4Protocol(sockfd[0], event_cb_.AsStdFunction(),
-                       acl_cb_.AsStdFunction(), sco_cb_.AsStdFunction());
+    H4Protocol* h4_hci = new H4Protocol(
+        sockfd[0], event_cb_.AsStdFunction(), acl_cb_.AsStdFunction(),
+        sco_cb_.AsStdFunction(), iso_cb_.AsStdFunction());
     fd_watcher_.WatchFdForNonBlockingReads(
         sockfd[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
     protocol_ = h4_hci;
@@ -184,9 +188,35 @@
     }
   }
 
+  void WriteAndExpectInboundIsoData(char* payload) {
+    // h4 type[1] + handle[2] + size[1]
+    char preamble[4] = {HCI_PACKET_TYPE_ISO_DATA, 20, 17, 0};
+    preamble[3] = strlen(payload) & 0xFF;
+
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(iso_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
+                                             payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    // Fail if it takes longer than 100 ms.
+    auto timeout_time =
+        std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait_until(lock, timeout_time);
+    }
+  }
+
   testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
   testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
   testing::MockFunction<void(const hidl_vec<uint8_t>&)> sco_cb_;
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> iso_cb_;
   async::AsyncFdWatcher fd_watcher_;
   H4Protocol* protocol_;
   int fake_uart_;
@@ -197,6 +227,7 @@
   SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1);
   SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2);
   SendAndReadUartOutbound(HCI_PACKET_TYPE_SCO_DATA, sample_data3);
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_ISO_DATA, sample_data4);
 }
 
 // Ensure we properly parse data coming from the UART
@@ -204,6 +235,7 @@
   WriteAndExpectInboundAclData(acl_data);
   WriteAndExpectInboundScoData(sco_data);
   WriteAndExpectInboundEvent(event_data);
+  WriteAndExpectInboundIsoData(iso_data);
 }
 
 }  // namespace implementation
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index d56e344..d809313 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -162,14 +162,14 @@
 bool VendorInterface::Initialize(
     InitializeCompleteCallback initialize_complete_cb,
     PacketReadCallback event_cb, PacketReadCallback acl_cb,
-    PacketReadCallback sco_cb) {
+    PacketReadCallback sco_cb, PacketReadCallback iso_cb) {
   if (g_vendor_interface) {
     ALOGE("%s: No previous Shutdown()?", __func__);
     return false;
   }
   g_vendor_interface = new VendorInterface();
   return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
-                                  sco_cb);
+                                  sco_cb, iso_cb);
 }
 
 void VendorInterface::Shutdown() {
@@ -185,7 +185,8 @@
 bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
                            PacketReadCallback event_cb,
                            PacketReadCallback acl_cb,
-                           PacketReadCallback sco_cb) {
+                           PacketReadCallback sco_cb,
+                           PacketReadCallback iso_cb) {
   initialize_complete_cb_ = initialize_complete_cb;
 
   // Initialize vendor interface
@@ -248,7 +249,7 @@
 
   if (fd_count == 1) {
     hci::H4Protocol* h4_hci =
-        new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb);
+        new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb);
     fd_watcher_.WatchFdForNonBlockingReads(
         fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
     hci_ = h4_hci;
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index 1d69040..040f31a 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -38,7 +38,7 @@
  public:
   static bool Initialize(InitializeCompleteCallback initialize_complete_cb,
                          PacketReadCallback event_cb, PacketReadCallback acl_cb,
-                         PacketReadCallback sco_cb);
+                         PacketReadCallback sco_cb, PacketReadCallback iso_cb);
   static void Shutdown();
   static VendorInterface* get();
 
@@ -51,7 +51,7 @@
 
   bool Open(InitializeCompleteCallback initialize_complete_cb,
             PacketReadCallback event_cb, PacketReadCallback acl_cb,
-            PacketReadCallback sco_cb);
+            PacketReadCallback sco_cb, PacketReadCallback iso_cb);
   void Close();
 
   void OnTimeout();
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
index beb9a3e..ef02eff 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
@@ -24,8 +24,9 @@
 #include <utils/Log.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <chrono>
 #include <queue>
@@ -137,30 +138,12 @@
   std::chrono::steady_clock::time_point start_time_;
 };
 
-// Test environment for Bluetooth HIDL HAL.
-class BluetoothHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static BluetoothHidlEnvironment* Instance() {
-    static BluetoothHidlEnvironment* instance = new BluetoothHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override {
-    registerTestService<IBluetoothHci>();
-  }
-
- private:
-  BluetoothHidlEnvironment() {}
-};
-
 // The main test class for Bluetooth HIDL HAL.
-class BluetoothHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class BluetoothHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
     // currently test passthrough mode only
-    bluetooth =
-        ::testing::VtsHalHidlTargetTestBase::getService<IBluetoothHci>();
+    bluetooth = IBluetoothHci::getService(GetParam());
     ASSERT_NE(bluetooth, nullptr);
     ALOGI("%s: getService() for bluetooth is %s", __func__,
           bluetooth->isRemote() ? "remote" : "local");
@@ -617,10 +600,10 @@
 }
 
 // Empty test: Initialize()/Close() are called in SetUp()/TearDown().
-TEST_F(BluetoothHidlTest, InitializeAndClose) {}
+TEST_P(BluetoothHidlTest, InitializeAndClose) {}
 
 // Send an HCI Reset with sendHciCommand and wait for a command complete event.
-TEST_F(BluetoothHidlTest, HciReset) {
+TEST_P(BluetoothHidlTest, HciReset) {
   hidl_vec<uint8_t> cmd = COMMAND_HCI_RESET;
   bluetooth->sendHciCommand(cmd);
 
@@ -628,7 +611,7 @@
 }
 
 // Read and check the HCI version of the controller.
-TEST_F(BluetoothHidlTest, HciVersionTest) {
+TEST_P(BluetoothHidlTest, HciVersionTest) {
   hidl_vec<uint8_t> cmd = COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION;
   bluetooth->sendHciCommand(cmd);
 
@@ -649,7 +632,7 @@
 }
 
 // Send an unknown HCI command and wait for the error message.
-TEST_F(BluetoothHidlTest, HciUnknownCommand) {
+TEST_P(BluetoothHidlTest, HciUnknownCommand) {
   hidl_vec<uint8_t> cmd = COMMAND_HCI_SHOULD_BE_UNKNOWN;
   bluetooth->sendHciCommand(cmd);
 
@@ -676,14 +659,14 @@
 }
 
 // Enter loopback mode, but don't send any packets.
-TEST_F(BluetoothHidlTest, WriteLoopbackMode) {
+TEST_P(BluetoothHidlTest, WriteLoopbackMode) {
   std::vector<uint16_t> sco_connection_handles;
   std::vector<uint16_t> acl_connection_handles;
   enterLoopbackMode(sco_connection_handles, acl_connection_handles);
 }
 
 // Enter loopback mode and send single packets.
-TEST_F(BluetoothHidlTest, LoopbackModeSinglePackets) {
+TEST_P(BluetoothHidlTest, LoopbackModeSinglePackets) {
   setBufferSizes();
 
   std::vector<uint16_t> sco_connection_handles;
@@ -720,7 +703,7 @@
 }
 
 // Enter loopback mode and send packets for bandwidth measurements.
-TEST_F(BluetoothHidlTest, LoopbackModeBandwidth) {
+TEST_P(BluetoothHidlTest, LoopbackModeBandwidth) {
   setBufferSizes();
 
   std::vector<uint16_t> sco_connection_handles;
@@ -758,11 +741,8 @@
   }
 }
 
-int main(int argc, char** argv) {
-  ::testing::AddGlobalTestEnvironment(BluetoothHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  BluetoothHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, BluetoothHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IBluetoothHci::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/bluetooth/1.1/Android.bp b/bluetooth/1.1/Android.bp
new file mode 100644
index 0000000..4204aed
--- /dev/null
+++ b/bluetooth/1.1/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.bluetooth@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IBluetoothHci.hal",
+        "IBluetoothHciCallbacks.hal",
+    ],
+    interfaces: [
+        "android.hardware.bluetooth@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/bluetooth/1.1/IBluetoothHci.hal b/bluetooth/1.1/IBluetoothHci.hal
new file mode 100644
index 0000000..0f69c6e
--- /dev/null
+++ b/bluetooth/1.1/IBluetoothHci.hal
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth@1.1;
+
+import @1.0::HciPacket;
+import @1.0::IBluetoothHci;
+import IBluetoothHciCallbacks;
+
+/**
+ * The Host Controller Interface (HCI) is the layer defined by the Bluetooth
+ * specification between the software that runs on the host and the Bluetooth
+ * controller chip. This boundary is the natural choice for a Hardware
+ * Abstraction Layer (HAL). Dealing only in HCI packets and events simplifies
+ * the stack and abstracts away power management, initialization, and other
+ * implementation-specific details related to the hardware.
+ */
+interface IBluetoothHci extends @1.0::IBluetoothHci {
+    /**
+     * Same as @1.0, but uses 1.1 Callbacks version
+     */
+    initialize_1_1(@1.1::IBluetoothHciCallbacks callback);
+
+    /**
+     * Send an ISO data packet (as specified in the Bluetooth Specification
+     * V6.0) to the Bluetooth controller.
+     * Packets must be processed in order.
+     * @param data HCI data packet to be sent
+     */
+    sendIsoData(HciPacket data);
+};
diff --git a/bluetooth/1.1/IBluetoothHciCallbacks.hal b/bluetooth/1.1/IBluetoothHciCallbacks.hal
new file mode 100644
index 0000000..62cbe45
--- /dev/null
+++ b/bluetooth/1.1/IBluetoothHciCallbacks.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth@1.1;
+
+import @1.0::HciPacket;
+import @1.0::IBluetoothHciCallbacks;
+
+/**
+ * The interface from the Bluetooth Controller to the stack.
+ */
+interface IBluetoothHciCallbacks extends @1.0::IBluetoothHciCallbacks {
+    /**
+     * Send a ISO data packet form the controller to the host.
+     * @param data the ISO HCI packet to be passed to the host stack
+     */
+    isoDataReceived(HciPacket data);
+};
diff --git a/bluetooth/1.1/default/Android.bp b/bluetooth/1.1/default/Android.bp
new file mode 100644
index 0000000..4f7fecb
--- /dev/null
+++ b/bluetooth/1.1/default/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+    name: "android.hardware.bluetooth@1.1-service",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.bluetooth@1.1-service.rc"],
+    srcs: [
+        "service.cpp",
+        "bluetooth_hci.cc",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libdl",
+        "libbase",
+        "libutils",
+        "libhardware",
+        "libhidlbase",
+        "android.hardware.bluetooth@1.0-impl",
+        "android.hardware.bluetooth@1.1",
+    ],
+
+    static_libs: [
+        "android.hardware.bluetooth-hci",
+    ],
+}
diff --git a/bluetooth/1.1/default/OWNERS b/bluetooth/1.1/default/OWNERS
new file mode 100644
index 0000000..0c01df6
--- /dev/null
+++ b/bluetooth/1.1/default/OWNERS
@@ -0,0 +1,3 @@
+zachoverflow@google.com
+mylesgw@google.com
+jpawlowski@google.com
diff --git a/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc b/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc
new file mode 100644
index 0000000..49f0be3
--- /dev/null
+++ b/bluetooth/1.1/default/android.hardware.bluetooth@1.1-service.rc
@@ -0,0 +1,9 @@
+service vendor.bluetooth-1-1 /vendor/bin/hw/android.hardware.bluetooth@1.1-service
+    interface android.hardware.bluetooth@1.1::IBluetoothHci default
+    interface android.hardware.bluetooth@1.0::IBluetoothHci default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    writepid /dev/stune/foreground/tasks
+
diff --git a/bluetooth/1.1/default/bluetooth_hci.cc b/bluetooth/1.1/default/bluetooth_hci.cc
new file mode 100644
index 0000000..7ccce80
--- /dev/null
+++ b/bluetooth/1.1/default/bluetooth_hci.cc
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.bluetooth@1.1-impl"
+#include "bluetooth_hci.h"
+
+#include <log/log.h>
+
+#include "vendor_interface.h"
+
+using android::hardware::bluetooth::V1_0::implementation::VendorInterface;
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_1 {
+namespace implementation {
+
+static const uint8_t HCI_DATA_TYPE_COMMAND = 1;
+static const uint8_t HCI_DATA_TYPE_ACL = 2;
+static const uint8_t HCI_DATA_TYPE_SCO = 3;
+static const uint8_t HCI_DATA_TYPE_ISO = 5;
+
+class BluetoothDeathRecipient : public hidl_death_recipient {
+ public:
+  BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
+
+  virtual void serviceDied(
+      uint64_t /*cookie*/,
+      const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+    ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
+    has_died_ = true;
+    mHci->close();
+  }
+  sp<IBluetoothHci> mHci;
+  bool getHasDied() const { return has_died_; }
+  void setHasDied(bool has_died) { has_died_ = has_died; }
+
+ private:
+  bool has_died_;
+};
+
+BluetoothHci::BluetoothHci()
+    : death_recipient_(new BluetoothDeathRecipient(this)) {}
+
+Return<void> BluetoothHci::initialize_1_1(
+    const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb) {
+  ALOGI("BluetoothHci::initialize_1_1()");
+  if (cb == nullptr) {
+    ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
+    return Void();
+  }
+
+  death_recipient_->setHasDied(false);
+  cb->linkToDeath(death_recipient_, 0);
+
+  bool rc = VendorInterface::Initialize(
+      [cb](bool status) {
+        auto hidl_status = cb->initializationComplete(
+            status ? V1_0::Status::SUCCESS
+                   : V1_0::Status::INITIALIZATION_ERROR);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call initializationComplete()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->hciEventReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call hciEventReceived()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->aclDataReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call aclDataReceived()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->scoDataReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call scoDataReceived()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->isoDataReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call isoDataReceived()");
+        }
+      });
+  if (!rc) {
+    auto hidl_status =
+        cb->initializationComplete(V1_0::Status::INITIALIZATION_ERROR);
+    if (!hidl_status.isOk()) {
+      ALOGE("VendorInterface -> Unable to call initializationComplete(ERR)");
+    }
+  }
+
+  unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
+    if (death_recipient->getHasDied())
+      ALOGI("Skipping unlink call, service died.");
+    else
+      cb->unlinkToDeath(death_recipient);
+  };
+
+  return Void();
+}
+
+class OldCbWrapper : public V1_1::IBluetoothHciCallbacks {
+ public:
+  const ::android::sp<V1_0::IBluetoothHciCallbacks> old_cb_;
+  OldCbWrapper(const ::android::sp<V1_0::IBluetoothHciCallbacks>& old_cb)
+      : old_cb_(old_cb) {}
+
+  virtual ~OldCbWrapper() = default;
+
+  Return<void> initializationComplete(V1_0::Status status) override {
+    return old_cb_->initializationComplete(status);
+  };
+
+  Return<void> hciEventReceived(
+      const ::android::hardware::hidl_vec<uint8_t>& event) override {
+    return old_cb_->hciEventReceived(event);
+  };
+
+  Return<void> aclDataReceived(
+      const ::android::hardware::hidl_vec<uint8_t>& data) override {
+    return old_cb_->aclDataReceived(data);
+  };
+
+  Return<void> scoDataReceived(
+      const ::android::hardware::hidl_vec<uint8_t>& data) override {
+    return old_cb_->scoDataReceived(data);
+  };
+
+  Return<void> isoDataReceived(
+      const ::android::hardware::hidl_vec<uint8_t>&) override {
+    ALOGE("Please use HAL V1_1 for ISO.");
+    return Void();
+  };
+};
+
+Return<void> BluetoothHci::initialize(
+    const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb) {
+  ALOGE("Using initialize from HAL V1_0 instead of initialize_1_1.");
+  return initialize_1_1(new OldCbWrapper(cb));
+}
+
+Return<void> BluetoothHci::close() {
+  ALOGI("BluetoothHci::close()");
+  unlink_cb_(death_recipient_);
+  VendorInterface::Shutdown();
+  return Void();
+}
+
+Return<void> BluetoothHci::sendHciCommand(const hidl_vec<uint8_t>& command) {
+  sendDataToController(HCI_DATA_TYPE_COMMAND, command);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& data) {
+  sendDataToController(HCI_DATA_TYPE_ACL, data);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& data) {
+  sendDataToController(HCI_DATA_TYPE_SCO, data);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendIsoData(const hidl_vec<uint8_t>& data) {
+  sendDataToController(HCI_DATA_TYPE_ISO, data);
+  return Void();
+}
+
+void BluetoothHci::sendDataToController(const uint8_t type,
+                                        const hidl_vec<uint8_t>& data) {
+  VendorInterface::get()->Send(type, data.data(), data.size());
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.1/default/bluetooth_hci.h b/bluetooth/1.1/default/bluetooth_hci.h
new file mode 100644
index 0000000..5f59cb0
--- /dev/null
+++ b/bluetooth/1.1/default/bluetooth_hci.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
+#define HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
+
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHciCallbacks.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include <functional>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+class BluetoothDeathRecipient;
+
+class BluetoothHci : public V1_1::IBluetoothHci {
+ public:
+  BluetoothHci();
+  Return<void> initialize(
+      const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb) override;
+  Return<void> initialize_1_1(
+      const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb) override;
+  Return<void> sendHciCommand(const hidl_vec<uint8_t>& packet) override;
+  Return<void> sendAclData(const hidl_vec<uint8_t>& data) override;
+  Return<void> sendScoData(const hidl_vec<uint8_t>& data) override;
+  Return<void> sendIsoData(const hidl_vec<uint8_t>& data) override;
+  Return<void> close() override;
+
+ private:
+  void sendDataToController(const uint8_t type, const hidl_vec<uint8_t>& data);
+  ::android::sp<BluetoothDeathRecipient> death_recipient_;
+  std::function<void(sp<BluetoothDeathRecipient>&)> unlink_cb_;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
diff --git a/bluetooth/1.1/default/service.cpp b/bluetooth/1.1/default/service.cpp
new file mode 100644
index 0000000..affa855
--- /dev/null
+++ b/bluetooth/1.1/default/service.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "android.hardware.bluetooth@1.1-service"
+
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "bluetooth_hci.h"
+
+// Generated HIDL files
+using android::hardware::bluetooth::V1_1::IBluetoothHci;
+using android::hardware::bluetooth::V1_1::implementation::BluetoothHci;
+
+using android::sp;
+using android::status_t;
+
+int main() {
+  ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/);
+
+  sp bluetoothHci = new BluetoothHci();
+  const status_t status = bluetoothHci->registerAsService();
+  if (status != ::android::OK) {
+    ALOGE("Cannot register Bluetooth HAL service");
+    return 1;  // or handle error
+  }
+
+  ::android::hardware::joinRpcThreadpool();
+  return 1;  // joinRpcThreadpool should never return
+}
diff --git a/bluetooth/1.1/vts/OWNERS b/bluetooth/1.1/vts/OWNERS
new file mode 100644
index 0000000..ff6fd93
--- /dev/null
+++ b/bluetooth/1.1/vts/OWNERS
@@ -0,0 +1,6 @@
+zachoverflow@google.com
+siyuanh@google.com
+mylesgw@google.com
+jpawlowski@google.com
+hsz@google.com
+
diff --git a/vibrator/1.4/vts/functional/Android.bp b/bluetooth/1.1/vts/functional/Android.bp
similarity index 65%
rename from vibrator/1.4/vts/functional/Android.bp
rename to bluetooth/1.1/vts/functional/Android.bp
index 202a824..8d6d749 100644
--- a/vibrator/1.4/vts/functional/Android.bp
+++ b/bluetooth/1.1/vts/functional/Android.bp
@@ -15,19 +15,13 @@
 //
 
 cc_test {
-    name: "VtsHalVibratorV1_4TargetTest",
+    name: "VtsHalBluetoothV1_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
-    srcs: ["VtsHalVibratorV1_4TargetTest.cpp"],
+    srcs: ["VtsHalBluetoothV1_1TargetTest.cpp"],
     static_libs: [
-        "android.hardware.vibrator@1.0",
-        "android.hardware.vibrator@1.1",
-        "android.hardware.vibrator@1.2",
-        "android.hardware.vibrator@1.3",
-        "android.hardware.vibrator@1.4",
+        "android.hardware.bluetooth@1.1",
+        "android.hardware.bluetooth@1.0",
+        "libbluetooth-types",
     ],
-    test_suites: [
-        "general-tests",
-        "vts-core",
-    ],
+    test_suites: ["general-tests", "vts-core"],
 }
-
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp
new file mode 100644
index 0000000..659b2c8
--- /dev/null
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.cpp
@@ -0,0 +1,760 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "bluetooth_hidl_hal_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/bluetooth/1.0/types.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHciCallbacks.h>
+#include <hardware/bluetooth.h>
+#include <utils/Log.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <chrono>
+#include <queue>
+#include <thread>
+
+using ::android::sp;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::V1_0::Status;
+using ::android::hardware::bluetooth::V1_1::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_1::IBluetoothHciCallbacks;
+
+#define HCI_MINIMUM_HCI_VERSION 5  // Bluetooth Core Specification 3.0 + HS
+#define HCI_MINIMUM_LMP_VERSION 5  // Bluetooth Core Specification 3.0 + HS
+#define NUM_HCI_COMMANDS_BANDWIDTH 1000
+#define NUM_SCO_PACKETS_BANDWIDTH 1000
+#define NUM_ACL_PACKETS_BANDWIDTH 1000
+#define WAIT_FOR_INIT_TIMEOUT std::chrono::milliseconds(2000)
+#define WAIT_FOR_HCI_EVENT_TIMEOUT std::chrono::milliseconds(2000)
+#define WAIT_FOR_SCO_DATA_TIMEOUT std::chrono::milliseconds(1000)
+#define WAIT_FOR_ACL_DATA_TIMEOUT std::chrono::milliseconds(1000)
+#define INTERFACE_CLOSE_DELAY_MS std::chrono::milliseconds(200)
+
+#define COMMAND_HCI_SHOULD_BE_UNKNOWN \
+  { 0xff, 0x3B, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }
+#define COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION \
+  { 0x01, 0x10, 0x00 }
+#define COMMAND_HCI_READ_BUFFER_SIZE \
+  { 0x05, 0x10, 0x00 }
+#define COMMAND_HCI_WRITE_LOOPBACK_MODE_LOCAL \
+  { 0x02, 0x18, 0x01, 0x01 }
+#define COMMAND_HCI_RESET \
+  { 0x03, 0x0c, 0x00 }
+#define COMMAND_HCI_WRITE_LOCAL_NAME \
+  { 0x13, 0x0c, 0xf8 }
+#define HCI_STATUS_SUCCESS 0x00
+#define HCI_STATUS_UNKNOWN_HCI_COMMAND 0x01
+
+#define EVENT_CONNECTION_COMPLETE 0x03
+#define EVENT_COMMAND_COMPLETE 0x0e
+#define EVENT_COMMAND_STATUS 0x0f
+#define EVENT_NUMBER_OF_COMPLETED_PACKETS 0x13
+#define EVENT_LOOPBACK_COMMAND 0x19
+
+#define EVENT_CODE_BYTE 0
+#define EVENT_LENGTH_BYTE 1
+#define EVENT_FIRST_PAYLOAD_BYTE 2
+#define EVENT_COMMAND_STATUS_STATUS_BYTE 2
+#define EVENT_COMMAND_STATUS_ALLOWED_PACKETS_BYTE 3
+#define EVENT_COMMAND_STATUS_OPCODE_LSBYTE 4  // Bytes 4 and 5
+#define EVENT_COMMAND_COMPLETE_ALLOWED_PACKETS_BYTE 2
+#define EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE 3  // Bytes 3 and 4
+#define EVENT_COMMAND_COMPLETE_STATUS_BYTE 5
+#define EVENT_COMMAND_COMPLETE_FIRST_PARAM_BYTE 6
+#define EVENT_LOCAL_HCI_VERSION_BYTE EVENT_COMMAND_COMPLETE_FIRST_PARAM_BYTE
+#define EVENT_LOCAL_LMP_VERSION_BYTE EVENT_LOCAL_HCI_VERSION_BYTE + 3
+
+#define EVENT_CONNECTION_COMPLETE_PARAM_LENGTH 11
+#define EVENT_CONNECTION_COMPLETE_TYPE 11
+#define EVENT_CONNECTION_COMPLETE_TYPE_SCO 0
+#define EVENT_CONNECTION_COMPLETE_TYPE_ACL 1
+#define EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE 3
+#define EVENT_COMMAND_STATUS_LENGTH 4
+
+#define EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES 2
+
+#define ACL_BROADCAST_FLAG_OFFSET 6
+#define ACL_BROADCAST_FLAG_POINT_TO_POINT 0x0
+#define ACL_BROADCAST_POINT_TO_POINT \
+  (ACL_BROADCAST_FLAG_POINT_TO_POINT << ACL_BROADCAST_FLAG_OFFSET)
+
+#define ACL_PACKET_BOUNDARY_FLAG_OFFSET 4
+#define ACL_PACKET_BOUNDARY_FLAG_FIRST_AUTO_FLUSHABLE 0x2
+#define ACL_PACKET_BOUNDARY_FIRST_AUTO_FLUSHABLE \
+  (ACL_PACKET_BOUNDARY_FLAG_FIRST_AUTO_FLUSHABLE \
+   << ACL_PACKET_BOUNDARY_FLAG_OFFSET)
+
+// To be removed in VTS release builds
+#define ACL_HANDLE_QCA_DEBUG_MESSAGE 0xedc
+
+constexpr char kCallbackNameAclEventReceived[] = "aclDataReceived";
+constexpr char kCallbackNameHciEventReceived[] = "hciEventReceived";
+constexpr char kCallbackNameInitializationComplete[] = "initializationComplete";
+constexpr char kCallbackNameScoEventReceived[] = "scoDataReceived";
+constexpr char kCallbackNameIsoEventReceived[] = "isoDataReceived";
+
+class ThroughputLogger {
+ public:
+  ThroughputLogger(std::string task)
+      : task_(task), start_time_(std::chrono::steady_clock::now()) {}
+
+  ~ThroughputLogger() {
+    if (total_bytes_ == 0) return;
+    std::chrono::duration<double> duration =
+        std::chrono::steady_clock::now() - start_time_;
+    double s = duration.count();
+    if (s == 0) return;
+    double rate_kb = (static_cast<double>(total_bytes_) / s) / 1024;
+    ALOGD("%s %.1f KB/s (%zu bytes in %.3fs)", task_.c_str(), rate_kb,
+          total_bytes_, s);
+  }
+
+  void setTotalBytes(size_t total_bytes) { total_bytes_ = total_bytes; }
+
+ private:
+  size_t total_bytes_;
+  std::string task_;
+  std::chrono::steady_clock::time_point start_time_;
+};
+
+// The main test class for Bluetooth HIDL HAL.
+class BluetoothHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+  virtual void SetUp() override {
+    // currently test passthrough mode only
+    bluetooth = IBluetoothHci::getService(GetParam());
+    ASSERT_NE(bluetooth, nullptr);
+    ALOGI("%s: getService() for bluetooth is %s", __func__,
+          bluetooth->isRemote() ? "remote" : "local");
+
+    bluetooth_hci_death_recipient = new BluetoothHciDeathRecipient();
+    ASSERT_NE(bluetooth_hci_death_recipient, nullptr);
+    ASSERT_TRUE(
+        bluetooth->linkToDeath(bluetooth_hci_death_recipient, 0).isOk());
+
+    bluetooth_cb = new BluetoothHciCallbacks(*this);
+    ASSERT_NE(bluetooth_cb, nullptr);
+
+    max_acl_data_packet_length = 0;
+    max_sco_data_packet_length = 0;
+    max_acl_data_packets = 0;
+    max_sco_data_packets = 0;
+
+    initialized = false;
+    event_cb_count = 0;
+    acl_cb_count = 0;
+    sco_cb_count = 0;
+
+    ASSERT_FALSE(initialized);
+    // Should not be checked in production code
+    ASSERT_TRUE(bluetooth->initialize(bluetooth_cb).isOk());
+
+    bluetooth_cb->SetWaitTimeout(kCallbackNameInitializationComplete,
+                                 WAIT_FOR_INIT_TIMEOUT);
+    bluetooth_cb->SetWaitTimeout(kCallbackNameHciEventReceived,
+                                 WAIT_FOR_HCI_EVENT_TIMEOUT);
+    bluetooth_cb->SetWaitTimeout(kCallbackNameAclEventReceived,
+                                 WAIT_FOR_ACL_DATA_TIMEOUT);
+    bluetooth_cb->SetWaitTimeout(kCallbackNameScoEventReceived,
+                                 WAIT_FOR_SCO_DATA_TIMEOUT);
+
+    EXPECT_TRUE(
+        bluetooth_cb->WaitForCallback(kCallbackNameInitializationComplete)
+            .no_timeout);
+
+    ASSERT_TRUE(initialized);
+  }
+
+  virtual void TearDown() override {
+    ALOGI("TearDown");
+    // Should not be checked in production code
+    ASSERT_TRUE(bluetooth->close().isOk());
+    std::this_thread::sleep_for(INTERFACE_CLOSE_DELAY_MS);
+    handle_no_ops();
+    EXPECT_EQ(static_cast<size_t>(0), event_queue.size());
+    EXPECT_EQ(static_cast<size_t>(0), sco_queue.size());
+    EXPECT_EQ(static_cast<size_t>(0), acl_queue.size());
+    EXPECT_EQ(static_cast<size_t>(0), iso_queue.size());
+  }
+
+  void setBufferSizes();
+
+  // Functions called from within tests in loopback mode
+  void sendAndCheckHCI(int num_packets);
+  void sendAndCheckSCO(int num_packets, size_t size, uint16_t handle);
+  void sendAndCheckACL(int num_packets, size_t size, uint16_t handle);
+
+  // Helper functions to try to get a handle on verbosity
+  void enterLoopbackMode(std::vector<uint16_t>* sco_handles,
+                         std::vector<uint16_t>* acl_handles);
+  void handle_no_ops();
+  void wait_for_event(bool timeout_is_error);
+  void wait_for_command_complete_event(hidl_vec<uint8_t> cmd);
+  int wait_for_completed_packets_event(uint16_t handle);
+
+  class BluetoothHciDeathRecipient : public hidl_death_recipient {
+   public:
+    void serviceDied(
+        uint64_t /*cookie*/,
+        const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/)
+        override {
+      FAIL();
+    }
+  };
+
+  // A simple test implementation of BluetoothHciCallbacks.
+  class BluetoothHciCallbacks
+      : public ::testing::VtsHalHidlTargetCallbackBase<BluetoothHidlTest>,
+        public IBluetoothHciCallbacks {
+    BluetoothHidlTest& parent_;
+
+   public:
+    BluetoothHciCallbacks(BluetoothHidlTest& parent) : parent_(parent){};
+
+    virtual ~BluetoothHciCallbacks() = default;
+
+    Return<void> initializationComplete(Status status) override {
+      parent_.initialized = (status == Status::SUCCESS);
+      NotifyFromCallback(kCallbackNameInitializationComplete);
+      ALOGV("%s (status = %d)", __func__, static_cast<int>(status));
+      return Void();
+    };
+
+    Return<void> hciEventReceived(
+        const ::android::hardware::hidl_vec<uint8_t>& event) override {
+      parent_.event_cb_count++;
+      parent_.event_queue.push(event);
+      NotifyFromCallback(kCallbackNameHciEventReceived);
+      ALOGV("Event received (length = %d)", static_cast<int>(event.size()));
+      return Void();
+    };
+
+    Return<void> aclDataReceived(
+        const ::android::hardware::hidl_vec<uint8_t>& data) override {
+      parent_.acl_cb_count++;
+      parent_.acl_queue.push(data);
+      NotifyFromCallback(kCallbackNameAclEventReceived);
+      return Void();
+    };
+
+    Return<void> scoDataReceived(
+        const ::android::hardware::hidl_vec<uint8_t>& data) override {
+      parent_.sco_cb_count++;
+      parent_.sco_queue.push(data);
+      NotifyFromCallback(kCallbackNameScoEventReceived);
+      return Void();
+    };
+
+    Return<void> isoDataReceived(
+        const ::android::hardware::hidl_vec<uint8_t>& data) override {
+      parent_.iso_cb_count++;
+      parent_.iso_queue.push(data);
+      NotifyFromCallback(kCallbackNameIsoEventReceived);
+      return Void();
+    };
+  };
+
+  sp<IBluetoothHci> bluetooth;
+  sp<BluetoothHciCallbacks> bluetooth_cb;
+  sp<BluetoothHciDeathRecipient> bluetooth_hci_death_recipient;
+  std::queue<hidl_vec<uint8_t>> event_queue;
+  std::queue<hidl_vec<uint8_t>> acl_queue;
+  std::queue<hidl_vec<uint8_t>> sco_queue;
+  std::queue<hidl_vec<uint8_t>> iso_queue;
+
+  bool initialized;
+
+  int event_cb_count;
+  int sco_cb_count;
+  int acl_cb_count;
+  int iso_cb_count;
+
+  int max_acl_data_packet_length;
+  int max_sco_data_packet_length;
+  int max_acl_data_packets;
+  int max_sco_data_packets;
+};
+
+// Discard NO-OPs from the event queue.
+void BluetoothHidlTest::handle_no_ops() {
+  while (event_queue.size() > 0) {
+    hidl_vec<uint8_t> event = event_queue.front();
+    EXPECT_GE(event.size(),
+              static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+    bool event_is_no_op =
+        (event[EVENT_CODE_BYTE] == EVENT_COMMAND_COMPLETE) &&
+        (event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE] == 0x00) &&
+        (event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1] == 0x00);
+    event_is_no_op |= (event[EVENT_CODE_BYTE] == EVENT_COMMAND_STATUS) &&
+                      (event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE] == 0x00) &&
+                      (event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1] == 0x00);
+    if (event_is_no_op) {
+      event_queue.pop();
+    } else {
+      break;
+    }
+  }
+  // To be removed in VTS release builds
+  while (acl_queue.size() > 0) {
+    hidl_vec<uint8_t> acl_packet = acl_queue.front();
+    uint16_t connection_handle = acl_packet[1] & 0xF;
+    connection_handle <<= 8;
+    connection_handle |= acl_packet[0];
+    bool packet_is_no_op = connection_handle == ACL_HANDLE_QCA_DEBUG_MESSAGE;
+    if (packet_is_no_op) {
+      acl_queue.pop();
+    } else {
+      break;
+    }
+  }
+}
+
+// Receive an event, discarding NO-OPs.
+void BluetoothHidlTest::wait_for_event(bool timeout_is_error = true) {
+  hidl_vec<uint8_t> event;
+  do {
+    bool no_timeout =
+        bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived).no_timeout;
+    EXPECT_TRUE(no_timeout || !timeout_is_error);
+    if (no_timeout && timeout_is_error) {
+      EXPECT_LT(static_cast<size_t>(0), event_queue.size());
+    }
+    if (event_queue.size() == 0) {
+      // WaitForCallback timed out.
+      return;
+    }
+    handle_no_ops();
+  } while (event_queue.size() == 0);
+}
+
+// Wait until a COMMAND_COMPLETE is received.
+void BluetoothHidlTest::wait_for_command_complete_event(hidl_vec<uint8_t> cmd) {
+  wait_for_event();
+  hidl_vec<uint8_t> event = event_queue.front();
+  event_queue.pop();
+
+  EXPECT_GT(event.size(),
+            static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+  EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+}
+
+// Send the command to read the controller's buffer sizes.
+void BluetoothHidlTest::setBufferSizes() {
+  hidl_vec<uint8_t> cmd = COMMAND_HCI_READ_BUFFER_SIZE;
+  bluetooth->sendHciCommand(cmd);
+
+  wait_for_event();
+  if (event_queue.size() == 0) return;
+
+  hidl_vec<uint8_t> event = event_queue.front();
+  event_queue.pop();
+
+  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+  EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+
+  max_acl_data_packet_length =
+      event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 1] +
+      (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 2] << 8);
+  max_sco_data_packet_length = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 3];
+  max_acl_data_packets = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 4] +
+                         (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 5] << 8);
+  max_sco_data_packets = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 6] +
+                         (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 7] << 8);
+
+  ALOGD("%s: ACL max %d num %d SCO max %d num %d", __func__,
+        static_cast<int>(max_acl_data_packet_length),
+        static_cast<int>(max_acl_data_packets),
+        static_cast<int>(max_sco_data_packet_length),
+        static_cast<int>(max_sco_data_packets));
+}
+
+// Send an HCI command (in Loopback mode) and check the response.
+void BluetoothHidlTest::sendAndCheckHCI(int num_packets) {
+  ThroughputLogger logger = {__func__};
+  int command_size = 0;
+  for (int n = 0; n < num_packets; n++) {
+    // Send an HCI packet
+    std::vector<uint8_t> write_name = COMMAND_HCI_WRITE_LOCAL_NAME;
+    // With a name
+    char new_name[] = "John Jacob Jingleheimer Schmidt ___________________0";
+    size_t new_name_length = strlen(new_name);
+    for (size_t i = 0; i < new_name_length; i++)
+      write_name.push_back(static_cast<uint8_t>(new_name[i]));
+    // And the packet number
+    size_t i = new_name_length - 1;
+    for (int digits = n; digits > 0; digits = digits / 10, i--)
+      write_name[i] = static_cast<uint8_t>('0' + digits % 10);
+    // And padding
+    for (size_t i = 0; i < 248 - new_name_length; i++)
+      write_name.push_back(static_cast<uint8_t>(0));
+
+    hidl_vec<uint8_t> cmd = write_name;
+    bluetooth->sendHciCommand(cmd);
+
+    // Check the loopback of the HCI packet
+    wait_for_event();
+    if (event_queue.size() == 0) return;
+
+    hidl_vec<uint8_t> event = event_queue.front();
+    event_queue.pop();
+    size_t compare_length =
+        (cmd.size() > static_cast<size_t>(0xff) ? static_cast<size_t>(0xff)
+                                                : cmd.size());
+    EXPECT_GT(event.size(), compare_length + EVENT_FIRST_PAYLOAD_BYTE - 1);
+
+    EXPECT_EQ(EVENT_LOOPBACK_COMMAND, event[EVENT_CODE_BYTE]);
+    EXPECT_EQ(compare_length, event[EVENT_LENGTH_BYTE]);
+
+    // Don't compare past the end of the event.
+    if (compare_length + EVENT_FIRST_PAYLOAD_BYTE > event.size()) {
+      compare_length = event.size() - EVENT_FIRST_PAYLOAD_BYTE;
+      ALOGE("Only comparing %d bytes", static_cast<int>(compare_length));
+    }
+
+    if (n == num_packets - 1) {
+      command_size = cmd.size();
+    }
+
+    for (size_t i = 0; i < compare_length; i++)
+      EXPECT_EQ(cmd[i], event[EVENT_FIRST_PAYLOAD_BYTE + i]);
+  }
+  logger.setTotalBytes(command_size * num_packets * 2);
+}
+
+// Send a SCO data packet (in Loopback mode) and check the response.
+void BluetoothHidlTest::sendAndCheckSCO(int num_packets, size_t size,
+                                        uint16_t handle) {
+  ThroughputLogger logger = {__func__};
+  for (int n = 0; n < num_packets; n++) {
+    // Send a SCO packet
+    hidl_vec<uint8_t> sco_packet;
+    std::vector<uint8_t> sco_vector;
+    sco_vector.push_back(static_cast<uint8_t>(handle & 0xff));
+    sco_vector.push_back(static_cast<uint8_t>((handle & 0x0f00) >> 8));
+    sco_vector.push_back(static_cast<uint8_t>(size & 0xff));
+    sco_vector.push_back(static_cast<uint8_t>((size & 0xff00) >> 8));
+    for (size_t i = 0; i < size; i++) {
+      sco_vector.push_back(static_cast<uint8_t>(i + n));
+    }
+    sco_packet = sco_vector;
+    bluetooth->sendScoData(sco_vector);
+
+    // Check the loopback of the SCO packet
+    EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameScoEventReceived)
+                    .no_timeout);
+    hidl_vec<uint8_t> sco_loopback = sco_queue.front();
+    sco_queue.pop();
+
+    EXPECT_EQ(sco_packet.size(), sco_loopback.size());
+    size_t successful_bytes = 0;
+
+    for (size_t i = 0; i < sco_packet.size(); i++) {
+      if (sco_packet[i] == sco_loopback[i]) {
+        successful_bytes = i;
+      } else {
+        ALOGE("Miscompare at %d (expected %x, got %x)", static_cast<int>(i),
+              sco_packet[i], sco_loopback[i]);
+        ALOGE("At %d (expected %x, got %x)", static_cast<int>(i + 1),
+              sco_packet[i + 1], sco_loopback[i + 1]);
+        break;
+      }
+    }
+    EXPECT_EQ(sco_packet.size(), successful_bytes + 1);
+  }
+  logger.setTotalBytes(num_packets * size * 2);
+}
+
+// Send an ACL data packet (in Loopback mode) and check the response.
+void BluetoothHidlTest::sendAndCheckACL(int num_packets, size_t size,
+                                        uint16_t handle) {
+  ThroughputLogger logger = {__func__};
+  for (int n = 0; n < num_packets; n++) {
+    // Send an ACL packet
+    hidl_vec<uint8_t> acl_packet;
+    std::vector<uint8_t> acl_vector;
+    acl_vector.push_back(static_cast<uint8_t>(handle & 0xff));
+    acl_vector.push_back(static_cast<uint8_t>((handle & 0x0f00) >> 8) |
+                         ACL_BROADCAST_POINT_TO_POINT |
+                         ACL_PACKET_BOUNDARY_FIRST_AUTO_FLUSHABLE);
+    acl_vector.push_back(static_cast<uint8_t>(size & 0xff));
+    acl_vector.push_back(static_cast<uint8_t>((size & 0xff00) >> 8));
+    for (size_t i = 0; i < size; i++) {
+      acl_vector.push_back(static_cast<uint8_t>(i + n));
+    }
+    acl_packet = acl_vector;
+    bluetooth->sendAclData(acl_vector);
+
+    // Check the loopback of the ACL packet
+    EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameAclEventReceived)
+                    .no_timeout);
+    hidl_vec<uint8_t> acl_loopback = acl_queue.front();
+    acl_queue.pop();
+
+    EXPECT_EQ(acl_packet.size(), acl_loopback.size());
+    size_t successful_bytes = 0;
+
+    for (size_t i = 0; i < acl_packet.size(); i++) {
+      if (acl_packet[i] == acl_loopback[i]) {
+        successful_bytes = i;
+      } else {
+        ALOGE("Miscompare at %d (expected %x, got %x)", static_cast<int>(i),
+              acl_packet[i], acl_loopback[i]);
+        ALOGE("At %d (expected %x, got %x)", static_cast<int>(i + 1),
+              acl_packet[i + 1], acl_loopback[i + 1]);
+        break;
+      }
+    }
+    EXPECT_EQ(acl_packet.size(), successful_bytes + 1);
+  }
+  logger.setTotalBytes(num_packets * size * 2);
+}
+
+// Return the number of completed packets reported by the controller.
+int BluetoothHidlTest::wait_for_completed_packets_event(uint16_t handle) {
+  int packets_processed = 0;
+  wait_for_event(false);
+  if (event_queue.size() == 0) {
+    ALOGW("%s: WaitForCallback timed out.", __func__);
+    return packets_processed;
+  }
+  while (event_queue.size() > 0) {
+    hidl_vec<uint8_t> event = event_queue.front();
+    event_queue.pop();
+
+    EXPECT_EQ(EVENT_NUMBER_OF_COMPLETED_PACKETS, event[EVENT_CODE_BYTE]);
+    EXPECT_EQ(1, event[EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES]);
+
+    uint16_t event_handle = event[3] + (event[4] << 8);
+    EXPECT_EQ(handle, event_handle);
+
+    packets_processed += event[5] + (event[6] << 8);
+  }
+  return packets_processed;
+}
+
+// Send local loopback command and initialize SCO and ACL handles.
+void BluetoothHidlTest::enterLoopbackMode(std::vector<uint16_t>* sco_handles,
+                                          std::vector<uint16_t>* acl_handles) {
+  hidl_vec<uint8_t> cmd = COMMAND_HCI_WRITE_LOOPBACK_MODE_LOCAL;
+  bluetooth->sendHciCommand(cmd);
+
+  // Receive connection complete events with data channels
+  int connection_event_count = 0;
+  bool command_complete_received = false;
+  while (true) {
+    wait_for_event(false);
+    if (event_queue.size() == 0) {
+      // Fail if there was no event received or no connections completed.
+      EXPECT_TRUE(command_complete_received);
+      EXPECT_LT(0, connection_event_count);
+      return;
+    }
+    hidl_vec<uint8_t> event = event_queue.front();
+    event_queue.pop();
+    EXPECT_GT(event.size(),
+              static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+    if (event[EVENT_CODE_BYTE] == EVENT_CONNECTION_COMPLETE) {
+      EXPECT_GT(event.size(),
+                static_cast<size_t>(EVENT_CONNECTION_COMPLETE_TYPE));
+      EXPECT_EQ(event[EVENT_LENGTH_BYTE],
+                EVENT_CONNECTION_COMPLETE_PARAM_LENGTH);
+      uint8_t connection_type = event[EVENT_CONNECTION_COMPLETE_TYPE];
+
+      EXPECT_TRUE(connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO ||
+                  connection_type == EVENT_CONNECTION_COMPLETE_TYPE_ACL);
+
+      // Save handles
+      uint16_t handle = event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE] |
+                        event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE + 1] << 8;
+      if (connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO)
+        sco_handles->push_back(handle);
+      else
+        acl_handles->push_back(handle);
+
+      ALOGD("Connect complete type = %d handle = %d",
+            event[EVENT_CONNECTION_COMPLETE_TYPE], handle);
+      connection_event_count++;
+    } else {
+      EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+      EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+      EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+      EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+      command_complete_received = true;
+    }
+  }
+}
+
+// Empty test: Initialize()/Close() are called in SetUp()/TearDown().
+TEST_P(BluetoothHidlTest, InitializeAndClose) {}
+
+// Send an HCI Reset with sendHciCommand and wait for a command complete event.
+TEST_P(BluetoothHidlTest, HciReset) {
+  hidl_vec<uint8_t> cmd = COMMAND_HCI_RESET;
+  bluetooth->sendHciCommand(cmd);
+
+  wait_for_command_complete_event(cmd);
+}
+
+// Read and check the HCI version of the controller.
+TEST_P(BluetoothHidlTest, HciVersionTest) {
+  hidl_vec<uint8_t> cmd = COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION;
+  bluetooth->sendHciCommand(cmd);
+
+  wait_for_event();
+  if (event_queue.size() == 0) return;
+
+  hidl_vec<uint8_t> event = event_queue.front();
+  event_queue.pop();
+  EXPECT_GT(event.size(), static_cast<size_t>(EVENT_LOCAL_LMP_VERSION_BYTE));
+
+  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+  EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+
+  EXPECT_LE(HCI_MINIMUM_HCI_VERSION, event[EVENT_LOCAL_HCI_VERSION_BYTE]);
+  EXPECT_LE(HCI_MINIMUM_LMP_VERSION, event[EVENT_LOCAL_LMP_VERSION_BYTE]);
+}
+
+// Send an unknown HCI command and wait for the error message.
+TEST_P(BluetoothHidlTest, HciUnknownCommand) {
+  hidl_vec<uint8_t> cmd = COMMAND_HCI_SHOULD_BE_UNKNOWN;
+  bluetooth->sendHciCommand(cmd);
+
+  wait_for_event();
+  if (event_queue.size() == 0) return;
+
+  hidl_vec<uint8_t> event = event_queue.front();
+  event_queue.pop();
+
+  EXPECT_GT(event.size(),
+            static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+  if (event[EVENT_CODE_BYTE] == EVENT_COMMAND_COMPLETE) {
+    EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+    EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+    EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
+              event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+  } else {
+    EXPECT_EQ(EVENT_COMMAND_STATUS, event[EVENT_CODE_BYTE]);
+    EXPECT_EQ(cmd[0], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE]);
+    EXPECT_EQ(cmd[1], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1]);
+    EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
+              event[EVENT_COMMAND_STATUS_STATUS_BYTE]);
+  }
+}
+
+// Enter loopback mode, but don't send any packets.
+TEST_P(BluetoothHidlTest, WriteLoopbackMode) {
+  std::vector<uint16_t> sco_connection_handles;
+  std::vector<uint16_t> acl_connection_handles;
+  enterLoopbackMode(&sco_connection_handles, &acl_connection_handles);
+}
+
+// Enter loopback mode and send single packets.
+TEST_P(BluetoothHidlTest, LoopbackModeSinglePackets) {
+  setBufferSizes();
+
+  std::vector<uint16_t> sco_connection_handles;
+  std::vector<uint16_t> acl_connection_handles;
+  enterLoopbackMode(&sco_connection_handles, &acl_connection_handles);
+
+  sendAndCheckHCI(1);
+
+  // This should work, but breaks on some current platforms.  Figure out how to
+  // grandfather older devices but test new ones.
+  if (0 && sco_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_sco_data_packet_length);
+    sendAndCheckSCO(1, max_sco_data_packet_length, sco_connection_handles[0]);
+    int sco_packets_sent = 1;
+    int completed_packets =
+        wait_for_completed_packets_event(sco_connection_handles[0]);
+    if (sco_packets_sent != completed_packets) {
+      ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+            sco_packets_sent, completed_packets);
+    }
+  }
+
+  if (acl_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_acl_data_packet_length);
+    sendAndCheckACL(1, max_acl_data_packet_length, acl_connection_handles[0]);
+    int acl_packets_sent = 1;
+    int completed_packets =
+        wait_for_completed_packets_event(acl_connection_handles[0]);
+    if (acl_packets_sent != completed_packets) {
+      ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+            acl_packets_sent, completed_packets);
+    }
+  }
+}
+
+// Enter loopback mode and send packets for bandwidth measurements.
+TEST_P(BluetoothHidlTest, LoopbackModeBandwidth) {
+  setBufferSizes();
+
+  std::vector<uint16_t> sco_connection_handles;
+  std::vector<uint16_t> acl_connection_handles;
+  enterLoopbackMode(&sco_connection_handles, &acl_connection_handles);
+
+  sendAndCheckHCI(NUM_HCI_COMMANDS_BANDWIDTH);
+
+  // This should work, but breaks on some current platforms.  Figure out how to
+  // grandfather older devices but test new ones.
+  if (0 && sco_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_sco_data_packet_length);
+    sendAndCheckSCO(NUM_SCO_PACKETS_BANDWIDTH, max_sco_data_packet_length,
+                    sco_connection_handles[0]);
+    int sco_packets_sent = NUM_SCO_PACKETS_BANDWIDTH;
+    int completed_packets =
+        wait_for_completed_packets_event(sco_connection_handles[0]);
+    if (sco_packets_sent != completed_packets) {
+      ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+            sco_packets_sent, completed_packets);
+    }
+  }
+
+  if (acl_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_acl_data_packet_length);
+    sendAndCheckACL(NUM_ACL_PACKETS_BANDWIDTH, max_acl_data_packet_length,
+                    acl_connection_handles[0]);
+    int acl_packets_sent = NUM_ACL_PACKETS_BANDWIDTH;
+    int completed_packets =
+        wait_for_completed_packets_event(acl_connection_handles[0]);
+    if (acl_packets_sent != completed_packets) {
+      ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+            acl_packets_sent, completed_packets);
+    }
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, BluetoothHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IBluetoothHci::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 49f9fe1..6505440 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -1494,7 +1494,7 @@
         ADD_FAILURE();
     }
 
-    std::lock_guard<std::mutex> l(mLock);
+    std::unique_lock<std::mutex> l(mLock);
     for (const auto& buf : buffers) {
         bool found = false;
         for (size_t idx = 0; idx < mOutstandingBufferIds.size(); idx++) {
@@ -1514,6 +1514,10 @@
         ALOGE("%s: unknown buffer ID %" PRIu64, __FUNCTION__, buf.bufferId);
         ADD_FAILURE();
     }
+    if (!hasOutstandingBuffersLocked()) {
+        l.unlock();
+        mFlushedCondition.notify_one();
+    }
     return Void();
 }
 
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index fb8d395..7d4f7a3 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -75,7 +75,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.bluetooth</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IBluetoothHci</name>
             <instance>default</instance>
@@ -280,7 +280,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.media.c2</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IComponentStore</name>
             <regex-instance>default[0-9]*</regex-instance>
diff --git a/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy b/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy
index 937fddd..a609620 100644
--- a/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy
+++ b/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy
@@ -45,6 +45,7 @@
 getdents64: 1
 clock_gettime: 1
 getpid: 1
+gettid: 1
 
 # used during process crash by crash_dump to dump process info
 rt_sigprocmask: 1
diff --git a/current.txt b/current.txt
index 74586b7..d5082af 100644
--- a/current.txt
+++ b/current.txt
@@ -579,12 +579,14 @@
 9d8ee57c490ffeaa28f702eaea8d198cb510e4bbfb99e6cb5f63e73341057c7c android.hardware.neuralnetworks@1.1::types
 fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice
 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel
-71c0f7127335e5b74d1615d5e7f129831b43ffbae5318ad0924d7d8d8910a859 android.hardware.neuralnetworks@1.2::types
+72de91c3feba4b19c159cd1c413cbea596b78240caa43e31194e20e6f5b05c49 android.hardware.neuralnetworks@1.2::types
 a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types
 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
 fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
 
 # HALs released in Android R
+79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci
+40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks
 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
 c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas
@@ -594,17 +596,22 @@
 ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
 db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types
+c228aaa27f66c48e147159a4f4996c5273191fece1b08de31bd171c61334855e android.hardware.keymaster@4.1::IKeymasterDevice
+adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
+7a04ea5595ed418ca3e91c28b8bd7353dd988be9be7b0c8c9e64fb4b77bd4523 android.hardware.keymaster@4.1::types
+df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
+a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice
 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel
 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types
+103cb87c5ed46851badac097f8d190da60f39b5ab32d60e2e93f64d3014ea75c android.hardware.neuralnetworks@1.3::types
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
 a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
 44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
 c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types
-41c602462ccd1b19cfd645994be4de4c07fc197ff58a54e84476b31908e61e21 android.hardware.radio@1.5::types
-a8691c71747c3f14f7a043598e856425077f755e55990507a9132ad62f8ab3f7 android.hardware.radio@1.5::IRadio
+274fb1254a6d1a97824ec5c880eeefc0e410dc6d3a2a4c34052201169d2b7de0 android.hardware.radio@1.5::types
+c8e81d912827a5d49b2ddcdc4eb4556c5d231a899a1dca879309e04210daa4a0 android.hardware.radio@1.5::IRadio
 a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication
-15daf260aaf6781b911450bc94e1a164901f9c0fe0bda68f8434f0a903f66e05 android.hardware.radio@1.5::IRadioResponse
+260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse
\ No newline at end of file
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
new file mode 100644
index 0000000..497c0f8
--- /dev/null
+++ b/graphics/common/aidl/Android.bp
@@ -0,0 +1,20 @@
+aidl_interface {
+    name: "vintf-graphics-common",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "android/hardware/graphics/common/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl b/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl
new file mode 100644
index 0000000..2428135
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Blend modes, settable per layer.
+ */
+@VintfStability
+@Backing(type="int")
+enum BlendMode {
+    INVALID = 0,
+
+    /** colorOut = colorSrc */
+    NONE = 1,
+
+    /** colorOut = colorSrc + colorDst * (1 - alphaSrc) */
+    PREMULTIPLIED = 2,
+
+    /** colorOut = colorSrc * alphaSrc + colorDst * (1 - alphaSrc) */
+    COVERAGE = 3,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl b/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl
new file mode 100644
index 0000000..562a664
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard chroma siting
+ */
+@VintfStability
+@Backing(type="long")
+enum ChromaSiting {
+    /* This format does not have chroma siting. */
+    NONE = 0,
+
+    /* This format has chroma siting but the type being used is unknown. */
+    UNKNOWN = 1,
+
+    /* Cb and Cr are sited interstitially, halfway between alternate luma samples.
+     * This is used by 4:2:0 for JPEG/JFIF, H.261, MPEG-1. */
+    SITED_INTERSTITIAL = 2,
+
+    /* Cb and Cr are horizontally sited coincident with a luma sample.
+     * Cb and Cr are vertically sited interstitially.
+     * This is used by 4:2:0 for MPEG-2 frame pictures. */
+    COSITED_HORIZONTAL = 3,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl b/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl
new file mode 100644
index 0000000..4cca1ba
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard compression strategies
+ */
+@VintfStability
+@Backing(type="long")
+enum Compression {
+    /* Represents all uncompressed buffers */
+    NONE = 0,
+
+    /* VESA Display Stream Compression (DSC) */
+    DISPLAY_STREAM_COMPRESSION = 1,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
new file mode 100644
index 0000000..81a21ab
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
@@ -0,0 +1,682 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+@VintfStability
+@Backing(type="int")
+enum Dataspace {
+    /**
+     * Default-assumption data space, when not explicitly specified.
+     *
+     * It is safest to assume the buffer is an image with sRGB primaries and
+     * encoding ranges, but the consumer and/or the producer of the data may
+     * simply be using defaults. No automatic gamma transform should be
+     * expected, except for a possible display gamma transform when drawn to a
+     * screen.
+     */
+    UNKNOWN = 0x0,
+
+    /**
+     * Arbitrary dataspace with manually defined characteristics.  Definition
+     * for colorspaces or other meaning must be communicated separately.
+     *
+     * This is used when specifying primaries, transfer characteristics,
+     * etc. separately.
+     *
+     * A typical use case is in video encoding parameters (e.g. for H.264),
+     * where a colorspace can have separately defined primaries, transfer
+     * characteristics, etc.
+     */
+    ARBITRARY = 0x1,
+
+    /**
+     * Color-description aspects
+     *
+     * The following aspects define various characteristics of the color
+     * specification. These represent bitfields, so that a data space value
+     * can specify each of them independently.
+     */
+
+    STANDARD_SHIFT = 16,
+
+    /**
+     * Standard aspect
+     *
+     * Defines the chromaticity coordinates of the source primaries in terms of
+     * the CIE 1931 definition of x and y specified in ISO 11664-1.
+     */
+    STANDARD_MASK = 63 << 16, // 63 << STANDARD_SHIFT = 0x3F
+
+    /**
+     * Chromacity coordinates are unknown or are determined by the application.
+     * Implementations shall use the following suggested standards:
+     *
+     * All YCbCr formats: BT709 if size is 720p or larger (since most video
+     *                    content is letterboxed this corresponds to width is
+     *                    1280 or greater, or height is 720 or greater).
+     *                    BT601_625 if size is smaller than 720p or is JPEG.
+     * All RGB formats:   BT709.
+     *
+     * For all other formats standard is undefined, and implementations should use
+     * an appropriate standard for the data represented.
+     */
+    STANDARD_UNSPECIFIED = 0 << 16, // STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.300   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT709 = 1 << 16,  // 1 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+     *  for RGB conversion from the one purely determined by the primaries
+     *  to minimize the color shift into RGB space that uses BT.709
+     *  primaries.
+     */
+    STANDARD_BT601_625 = 2 << 16, // 2 << STANDARD_SHIFT,
+
+    /**
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT601_625_UNADJUSTED = 3 << 16, // 3 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.310   0.595
+     *  blue            0.155   0.070
+     *  red             0.630   0.340
+     *  white (D65)     0.3127  0.3290
+     *
+     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+     *  for RGB conversion from the one purely determined by the primaries
+     *  to minimize the color shift into RGB space that uses BT.709
+     *  primaries.
+     */
+    STANDARD_BT601_525 = 4 << 16, // 4 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.310   0.595
+     *  blue            0.155   0.070
+     *  red             0.630   0.340
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+     * for RGB conversion (as in SMPTE 240M).
+     */
+    STANDARD_BT601_525_UNADJUSTED = 5 << 16, // 5 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.170   0.797
+     *  blue            0.131   0.046
+     *  red             0.708   0.292
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT2020 = 6 << 16, // 6 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.170   0.797
+     *  blue            0.131   0.046
+     *  red             0.708   0.292
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+     * for RGB conversion using the linear domain.
+     */
+    STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16, // 7 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x      y
+     *  green           0.21   0.71
+     *  blue            0.14   0.08
+     *  red             0.67   0.33
+     *  white (C)       0.310  0.316
+     *
+     * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT470M = 8 << 16, // 8 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.243   0.692
+     *  blue            0.145   0.049
+     *  red             0.681   0.319
+     *  white (C)       0.310   0.316
+     *
+     * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_FILM = 9 << 16, // 9 << STANDARD_SHIFT
+
+    /**
+     * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3)
+     * Primaries:       x       y
+     *  green           0.265   0.690
+     *  blue            0.150   0.060
+     *  red             0.680   0.320
+     *  white (D65)     0.3127  0.3290
+     */
+    STANDARD_DCI_P3 = 10 << 16, // 10 << STANDARD_SHIFT
+
+    /**
+     * Adobe RGB
+     * Primaries:       x       y
+     *  green           0.210   0.710
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     */
+    STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT
+
+
+
+    TRANSFER_SHIFT = 22,
+
+    /**
+     * Transfer aspect
+     *
+     * Transfer characteristics are the opto-electronic transfer characteristic
+     * at the source as a function of linear optical intensity (luminance).
+     *
+     * For digital signals, E corresponds to the recorded value. Normally, the
+     * transfer function is applied in RGB space to each of the R, G and B
+     * components independently. This may result in color shift that can be
+     * minized by applying the transfer function in Lab space only for the L
+     * component. Implementation may apply the transfer function in RGB space
+     * for all pixel formats if desired.
+     */
+
+    TRANSFER_MASK = 31 << 22, // 31 << TRANSFER_SHIFT = 0x1F
+
+    /**
+     * Transfer characteristics are unknown or are determined by the
+     * application.
+     *
+     * Implementations should use the following transfer functions:
+     *
+     * For YCbCr formats: use TRANSFER_SMPTE_170M
+     * For RGB formats: use TRANSFER_SRGB
+     *
+     * For all other formats transfer function is undefined, and implementations
+     * should use an appropriate standard for the data represented.
+     */
+    TRANSFER_UNSPECIFIED = 0 << 22, // 0 << TRANSFER_SHIFT
+
+    /**
+     * Transfer characteristic curve:
+     *  E = L
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_LINEAR = 1 << 22, // 1 << TRANSFER_SHIFT
+
+    /**
+     * Transfer characteristic curve:
+     *
+     * E = 1.055 * L^(1/2.4) - 0.055  for 0.0031308 <= L <= 1
+     *   = 12.92 * L                  for 0 <= L < 0.0031308
+     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *     E - corresponding electrical signal
+     */
+    TRANSFER_SRGB = 2 << 22, // 2 << TRANSFER_SHIFT
+
+    /**
+     * BT.601 525, BT.601 625, BT.709, BT.2020
+     *
+     * Transfer characteristic curve:
+     *  E = 1.099 * L ^ 0.45 - 0.099  for 0.018 <= L <= 1
+     *    = 4.500 * L                 for 0 <= L < 0.018
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_SMPTE_170M = 3 << 22, // 3 << TRANSFER_SHIFT
+
+    /**
+     * Assumed display gamma 2.2.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.2)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_GAMMA2_2 = 4 << 22, // 4 << TRANSFER_SHIFT
+
+    /**
+     *  display gamma 2.6.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.6)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_GAMMA2_6 = 5 << 22, // 5 << TRANSFER_SHIFT
+
+    /**
+     *  display gamma 2.8.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.8)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_GAMMA2_8 = 6 << 22, // 6 << TRANSFER_SHIFT
+
+    /**
+     * SMPTE ST 2084 (Dolby Perceptual Quantizer)
+     *
+     * Transfer characteristic curve:
+     *  E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
+     *  c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
+     *  c2 = 32 * 2413 / 4096 = 18.8515625
+     *  c3 = 32 * 2392 / 4096 = 18.6875
+     *  m = 128 * 2523 / 4096 = 78.84375
+     *  n = 0.25 * 2610 / 4096 = 0.1593017578125
+     *      L - luminance of image 0 <= L <= 1 for HDR colorimetry.
+     *          L = 1 corresponds to 10000 cd/m2
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_ST2084 = 7 << 22, // 7 << TRANSFER_SHIFT
+
+    /**
+     * ARIB STD-B67 Hybrid Log Gamma
+     *
+     * Transfer characteristic curve:
+     *  E = r * L^0.5                 for 0 <= L <= 1
+     *    = a * ln(L - b) + c         for 1 < L
+     *  a = 0.17883277
+     *  b = 0.28466892
+     *  c = 0.55991073
+     *  r = 0.5
+     *      L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
+     *          to reference white level of 100 cd/m2
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_HLG = 8 << 22, // 8 << TRANSFER_SHIFT
+
+    RANGE_SHIFT = 27,
+
+    /**
+     * Range aspect
+     *
+     * Defines the range of values corresponding to the unit range of 0-1.
+     * This is defined for YCbCr only, but can be expanded to RGB space.
+     */
+    RANGE_MASK = 7 << 27, // 7 << RANGE_SHIFT = 0x7
+
+    /**
+     * Range is unknown or are determined by the application.  Implementations
+     * shall use the following suggested ranges:
+     *
+     * All YCbCr formats: limited range.
+     * All RGB or RGBA formats (including RAW and Bayer): full range.
+     * All Y formats: full range
+     *
+     * For all other formats range is undefined, and implementations should use
+     * an appropriate range for the data represented.
+     */
+    RANGE_UNSPECIFIED = 0 << 27, // 0 << RANGE_SHIFT = 0x0
+
+    /**
+     * Full range uses all values for Y, Cb and Cr from
+     * 0 to 2^b-1, where b is the bit depth of the color format.
+     */
+    RANGE_FULL = 1 << 27, // 1 << RANGE_SHIFT = 0x8000000
+
+    /**
+     * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
+     * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
+     * the color format.
+     *
+     * E.g. For 8-bit-depth formats:
+     * Luma (Y) samples should range from 16 to 235, inclusive
+     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+     *
+     * For 10-bit-depth formats:
+     * Luma (Y) samples should range from 64 to 940, inclusive
+     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+     */
+    RANGE_LIMITED = 2 << 27, // 2 << RANGE_SHIFT = 0x10000000
+
+    /**
+     * Extended range is used for scRGB. Intended for use with
+     * floating point pixel formats. [0.0 - 1.0] is the standard
+     * sRGB space. Values outside the range 0.0 - 1.0 can encode
+     * color outside the sRGB gamut.
+     * Used to blend / merge multiple dataspaces on a single display.
+     */
+    RANGE_EXTENDED = 3 << 27, // 3 << RANGE_SHIFT = 0x18000000
+
+    /**
+     * sRGB linear encoding:
+     *
+     * The red, green, and blue components are stored in sRGB space, but
+     * are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are encoded using the full range ([0,255] for 8-bit) for all
+     * components.
+     */
+    SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // deprecated, use V0_SRGB_LINEAR
+
+    V0_SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
+
+
+    /**
+     * scRGB linear encoding:
+     *
+     * The red, green, and blue components are stored in extended sRGB space,
+     * but are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are floating point.
+     * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+     * Values beyond the range [0.0 - 1.0] would correspond to other colors
+     * spaces and/or HDR content.
+     */
+    V0_SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
+
+
+    /**
+     * sRGB gamma encoding:
+     *
+     * The red, green and blue components are stored in sRGB space, and
+     * converted to linear space when read, using the SRGB transfer function
+     * for each of the R, G and B components. When written, the inverse
+     * transformation is performed.
+     *
+     * The alpha component, if present, is always stored in linear space and
+     * is left unmodified when read or written.
+     *
+     * Use full range and BT.709 standard.
+     */
+    SRGB = 1 << 16 | 2 << 22 | 1 << 27, // deprecated, use V0_SRGB
+
+    V0_SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
+
+
+    /**
+     * scRGB:
+     *
+     * The red, green, and blue components are stored in extended sRGB space,
+     * but are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are floating point.
+     * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+     * Values beyond the range [0.0 - 1.0] would correspond to other colors
+     * spaces and/or HDR content.
+     */
+    V0_SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
+
+    /**
+     * YCbCr Colorspaces
+     * -----------------
+     *
+     * Primaries are given using (x,y) coordinates in the CIE 1931 definition
+     * of x and y specified by ISO 11664-1.
+     *
+     * Transfer characteristics are the opto-electronic transfer characteristic
+     * at the source as a function of linear optical intensity (luminance).
+     */
+
+    /**
+     * JPEG File Interchange Format (JFIF)
+     *
+     * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
+     *
+     * Use full range, BT.601 transfer and BT.601_625 standard.
+     */
+    JFIF = 2 << 16 | 3 << 22 | 1 << 27, // deprecated, use V0_JFIF
+
+    V0_JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
+
+    /**
+     * ITU-R Recommendation 601 (BT.601) - 625-line
+     *
+     * Standard-definition television, 625 Lines (PAL)
+     *
+     * Use limited range, BT.601 transfer and BT.601_625 standard.
+     */
+    BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_625
+
+    V0_BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+
+    /**
+     * ITU-R Recommendation 601 (BT.601) - 525-line
+     *
+     * Standard-definition television, 525 Lines (NTSC)
+     *
+     * Use limited range, BT.601 transfer and BT.601_525 standard.
+     */
+    BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_525
+
+    V0_BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+    /**
+     * ITU-R Recommendation 709 (BT.709)
+     *
+     * High-definition television
+     *
+     * Use limited range, BT.709 transfer and BT.709 standard.
+     */
+    BT709 = 1 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT709
+
+    V0_BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+
+    /**
+     * SMPTE EG 432-1 and SMPTE RP 431-2.
+     *
+     * Digital Cinema DCI-P3
+     *
+     * Use full range, linear transfer and D65 DCI-P3 standard
+     */
+    DCI_P3_LINEAR = 10 << 16 | 1 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL
+
+
+    /**
+     * SMPTE EG 432-1 and SMPTE RP 431-2.
+     *
+     * Digital Cinema DCI-P3
+     *
+     * Use full range, gamma 2.6 transfer and D65 DCI-P3 standard
+     * Note: Application is responsible for gamma encoding the data as
+     * a 2.6 gamma encoding is not supported in HW.
+     */
+    DCI_P3 = 10 << 16 | 5 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_GAMMA2_6 | RANGE_FULL
+
+
+    /**
+     * Display P3
+     *
+     * Display P3 uses same primaries and white-point as DCI-P3
+     * linear transfer function makes this the same as DCI_P3_LINEAR.
+     */
+    DISPLAY_P3_LINEAR = 10 << 16 | 1 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL
+
+
+    /**
+     * Display P3
+     *
+     * Use same primaries and white-point as DCI-P3
+     * but sRGB transfer function.
+     */
+    DISPLAY_P3 = 10 << 16 | 2 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL
+
+
+    /**
+     * Adobe RGB
+     *
+     * Use full range, gamma 2.2 transfer and Adobe RGB primaries
+     * Note: Application is responsible for gamma encoding the data as
+     * a 2.2 gamma encoding is not supported in HW.
+     */
+    ADOBE_RGB = 11 << 16 | 4 << 22 | 1 << 27, // STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL
+
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, linear transfer and BT2020 standard
+     */
+    BT2020_LINEAR = 6 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_LINEAR | RANGE_FULL
+
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, BT.709 transfer and BT2020 standard
+     */
+    BT2020 = 6 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard
+     */
+    BT2020_PQ = 6 << 16 | 7 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL
+
+
+    /**
+     * Data spaces for non-color formats
+     */
+
+    /**
+     * The buffer contains depth ranging measurements from a depth camera.
+     * This value is valid with formats:
+     *    HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement
+     *       and an associated confidence value. The 3 MSBs of the sample make
+     *       up the confidence value, and the low 13 LSBs of the sample make up
+     *       the depth measurement.
+     *       For the confidence section, 0 means 100% confidence, 1 means 0%
+     *       confidence. The mapping to a linear float confidence value between
+     *       0.f and 1.f can be obtained with
+     *         float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f;
+     *       The depth measurement can be extracted simply with
+     *         uint16_t range = (depthSample & 0x1FFF);
+     *    HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as
+     *       a variable-length float (x,y,z, confidence) coordinate point list.
+     *       The point cloud will be represented with the android_depth_points
+     *       structure.
+     */
+    DEPTH = 0x1000,
+
+    /**
+     * The buffer contains sensor events from sensor direct report.
+     * This value is valid with formats:
+     *    HAL_PIXEL_FORMAT_BLOB: an array of sensor event structure that forms
+     *       a lock free queue. Format of sensor event structure is specified
+     *       in Sensors HAL.
+     */
+    SENSOR = 0x1001,
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use limited range, BT.709 transfer and BT2020 standard
+     */
+    BT2020_ITU = 6 << 16 | 3 << 22 | 2 << 27, // 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 = 6 << 16 | 7 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED
+    BT2020_ITU_HLG = 6 << 16 | 8 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED
+    BT2020_HLG = 6 << 16 | 8 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_FULL
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, sRGB transfer and BT2020 standard
+     */
+    DISPLAY_BT2020 = 6 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SRGB | RANGE_FULL
+
+    /**
+     * ISO 16684-1:2011(E)
+     *
+     * Embedded depth metadata following the dynamic depth specification.
+     */
+    DYNAMIC_DEPTH = 0x1002,
+
+    /**
+     * JPEG APP segments format as specified by JEIDA spec
+     *
+     * The buffer must only contain APP1 (Application Marker) segment followed
+     * by zero or more APPn segments, as is specified by JEITA CP-3451C section 4.5.4.
+     * The APP1 segment optionally contains a thumbnail. The buffer will not
+     * contain main compressed image.
+     *
+     * This value is valid with formats:
+     *    HAL_PIXEL_FORMAT_BLOB: JPEG APP segments optionally containing thumbnail image
+     * in APP1. BLOB buffer with this dataspace is output by HAL, and used by
+     * camera framework to encode into a HEIC image.
+     */
+    JPEG_APP_SEGMENTS = 0x1003,
+
+    /**
+     * ISO/IEC 23008-12
+     *
+     * High Efficiency Image File Format (HEIF)
+     *
+     * This value is valid with formats:
+     *    HAL_PIXEL_FORMAT_BLOB: A HEIC image encoded by HEIC or HEVC encoder
+     * according to ISO/IEC 23008-12.
+     */
+    HEIF = 0x1004,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl
new file mode 100644
index 0000000..04d8710
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * This struct is used for types that are commonly extended by vendors. For example, buffer
+ * compression is typically SoC specific. It is not possible for Android to define every possible
+ * proprietary vendor compression strategy. Instead, compression is represented using this
+ * ExtendableType that can support standard compression strategies while still allowing
+ * every vendor to easily add their own non-standard definitions.
+ */
+@VintfStability
+parcelable ExtendableType {
+    /**
+     * Name of the stable aidl interface whose value is stored in this structure.
+     *
+     * For standard types, the "name" field will be set to the stable aidl name of the type such as
+     * "android.hardware.graphics.common.Compression".
+     *
+     * For custom vendor types, the "name" field will be set to the name of the custom
+     * @VendorStability vendor AIDL interface such as
+     * "vendor.mycompanyname.graphics.common.Compression". The name of the vendor extension should
+     * contain the name of the company that owns the extension. Including the company
+     * name in the "name" field prevents type collisions between different vendors.
+     */
+    @utf8InCpp String name;
+
+    /**
+     * Enum value of the from the stable aidl interface
+     *
+     * For standard types, the "value" field will be set to an enum value from that stable aidl
+     * type such as "NONE".
+     *
+     * For vendor types, the "value" field should be set to the enum value from the custom
+     * @VendorStability vendor AIDL interface extended type such as "MY_COMPRESSION_TYPE1".
+     */
+    long value = 0;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl b/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl
new file mode 100644
index 0000000..a3f1baa
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard interlaced strategies
+ */
+@VintfStability
+@Backing(type="long")
+enum Interlaced {
+    /* The buffer is not interlaced. */
+    NONE = 0,
+
+    /* The buffer's planes are interlaced horizontally. The height of each interlaced plane is
+     * 1/2 the height of the buffer's height. */
+    TOP_BOTTOM = 1,
+
+    /* The buffer's planes are interlaced vertically. The width of each interlaced plane is
+     * 1/2 the width of the buffer's width. */
+    RIGHT_LEFT = 2,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
new file mode 100644
index 0000000..168028d
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+import android.hardware.graphics.common.PlaneLayoutComponent;
+import android.hardware.graphics.common.Rect;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe the plane layout of a buffer.
+ *
+ * PlaneLayout uses the following definitions:
+ *
+ * - Component - a component is one channel of a pixel. For example, an RGBA format has
+ *      four components: R, G, B and A.
+ * - Sample - a sample is comprised of all the components in a given plane. For example,
+ *      a buffer with one Y plane and one CbCr plane has one plane with a sample of Y
+ *      and one plane with a sample of CbCr.
+ * - Pixel - a pixel is comprised of all the (non-metadata/raw) components in buffer across
+ *      all planes. For example, a buffer with a plane of Y and a plane of CbCr has a pixel
+ *      of YCbCr.
+ */
+
+@VintfStability
+parcelable PlaneLayout {
+    /**
+     * An list of plane layout components. This list of components should include
+     * every component in this plane. For example, a CbCr plane should return a
+     * vector of size two with one PlaneLayoutComponent for Cb and one for Cr.
+     */
+    PlaneLayoutComponent[] components;
+
+    /**
+     * Offset to the first byte of the plane (in bytes), from the start of the allocation.
+     */
+    long offsetInBytes;
+
+    /**
+     * Bits per sample increment (aka column increment): describes the distance
+     * in bits from one sample to the next sample (to the right) on the same row for the
+     * the component plane.
+     *
+     * The default value is 0. Return the default value if the increment is undefined, unknown,
+     * or variable.
+     *
+     * This can be negative. A negative increment indicates that the samples are read from
+     * right to left.
+     */
+    long sampleIncrementInBits;
+
+    /**
+     * Horizontal stride: number of bytes between two vertically adjacent
+     * samples in given plane. This can be mathematically described by:
+     *
+     * strideInBytes = ALIGN(widthInSamples * bps / 8, alignment)
+     *
+     * where,
+     *
+     * bps: average bits per sample
+     * alignment (in bytes): dependent upon pixel format and usage
+     *
+     * strideInBytes can contain additional padding beyond the widthInSamples.
+     *
+     * The default value is 0. Return the default value if the stride is undefined, unknown,
+     * or variable.
+     *
+     * This can be negative. A negative stride indicates that the rows are read from
+     * bottom to top.
+     */
+    long strideInBytes;
+
+    /**
+     * Dimensions of plane (in samples).
+     *
+     * This is the number of samples in the plane, even if subsampled.
+     *
+     * See 'strideInBytes' for relationship between strideInBytes and widthInSamples.
+     */
+    long widthInSamples;
+    long heightInSamples;
+
+    /**
+     * Can be used to get the total size in bytes of any memory used by the plane
+     * including extra padding. This should not include any extra metadata used to describe the
+     * plane.
+     */
+    long totalSizeInBytes;
+
+    /**
+     * Horizontal and vertical subsampling. Must be a positive power of 2.
+     *
+     * These fields indicate the number of horizontally or vertically adjacent pixels that use
+     * the same pixel data. A value of 1 indicates no subsampling.
+     */
+    long horizontalSubsampling;
+    long verticalSubsampling;
+
+    /**
+     * Some buffer producers require extra padding to their output buffer; therefore the
+     * physical size of the native buffer will be larger than its logical size.
+     * The crop rectangle determines the offset and logical size of the buffer that should be
+     * read by consumers.
+     *
+     * The crop rectangle is measured in samples and is relative to the offset of the
+     * plane. Valid crop rectangles are within the boundaries of the plane:
+     * [0, 0, widthInSamples, heightInSamples].
+     *
+     * The default crop rectangle is a rectangle the same size as the plane:
+     * [0, 0, widthInSamples, heightInSamples].
+     */
+    Rect crop;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
new file mode 100644
index 0000000..3fca53b
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+import android.hardware.graphics.common.ExtendableType;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe the type and location of a component in a
+ * buffer's plane.
+ *
+ * PlaneLayoutComponent uses the following definitions:
+ *
+ * - Component - a component is one channel of a pixel. For example, an RGBA format has
+ *      four components: R, G, B and A.
+ * - Sample - a sample is comprised of all the components in a given plane. For example,
+ *      a buffer with one Y plane and one CbCr plane has one plane with a sample of Y
+ *      and one plane with a sample of CbCr.
+ * - Pixel - a pixel is comprised of all the (non-metadata/raw) components in buffer across
+ *      all planes. For example, a buffer with a plane of Y and a plane of CbCr has a pixel
+ *      of YCbCr.
+ */
+
+@VintfStability
+parcelable PlaneLayoutComponent {
+    /**
+     * The type of this plane layout component.
+     *
+     * android.hardware.graphics.common.PlaneLayoutComponent defines the standard
+     * plane layout component types. Vendors may extend this type to include any
+     * non-standard plane layout component types. For instructions on how to
+     * create a vendor extension, refer to ExtendableType.aidl.
+     */
+    ExtendableType type;
+
+    /**
+     * Offset in bits to the first instance of this component in the plane.
+     * This is relative to the plane's offset (PlaneLayout::offset).
+     *
+     * If the offset cannot be described using a int64_t, this should be set to -1.
+     * For example, if the plane is compressed and the offset is not defined or
+     * relevant, return -1.
+     */
+    long offsetInBits;
+
+    /**
+     * The number of bits used per component in the plane.
+     *
+     * If the plane layout component cannot be described using componentSizeInBits, this
+     * should be set to -1. For example, if the component varies in size throughout
+     * the plane, return -1.
+     */
+    long sizeInBits;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
new file mode 100644
index 0000000..18c4a2e
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard plane layout component types
+ *
+ * The enum values have been taken directly from gralloc1's android_flex_component for compatiblity
+ * reasons. However, unlike gralloc1's android_flex_component, this field is NOT a bit field.
+ * A plane's components should NOT be expressed by bitwise OR-ing different
+ * PlaneLayoutComponentTypes together.
+ */
+@VintfStability
+@Backing(type="long")
+enum PlaneLayoutComponentType {
+    /* Luma */
+    Y = 1 << 0,
+    /* Chroma blue */
+    CB = 1 << 1,
+    /* Chroma red */
+    CR = 1 << 2,
+
+    /* Red */
+    R = 1 << 10,
+    /* Green */
+    G = 1 << 11,
+    /* Blue */
+    B = 1 << 12,
+
+    /* Alpha */
+    A = 1 << 30,
+}
diff --git a/vibrator/1.4/types.hal b/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
similarity index 62%
copy from vibrator/1.4/types.hal
copy to graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
index acc49b1..1a3bc11 100644
--- a/vibrator/1.4/types.hal
+++ b/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
+/**
+ * Copyright (c) 2019, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,9 +14,16 @@
  * limitations under the License.
  */
 
-package android.hardware.vibrator@1.4;
+package android.hardware.graphics.common;
 
-enum Capabilities : uint32_t {
-    ON_COMPLETION_CALLBACK = 1 << 0,
-    PERFORM_COMPLETION_CALLBACK = 1 << 1,
-};
+/**
+ * General purpose definition of a rectangle.
+ */
+
+@VintfStability
+parcelable Rect {
+    int left;
+    int top;
+    int right;
+    int bottom;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
new file mode 100644
index 0000000..060d12c
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -0,0 +1,282 @@
+/**
+ * Copyright (c) 2019,libgralloctypes_helper The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard metadata types.
+ *
+ * This is an enum that defines the common types of gralloc 4 buffer metadata. The comments for
+ * each enum include a description of the metadata that is associated with the type.
+ *
+ * IMapper@4.x must support getting the following standard buffer metadata types. IMapper@4.x may
+ * support setting these standard buffer metadata types as well.
+ */
+@VintfStability
+@Backing(type="long")
+enum StandardMetadataType {
+    INVALID = 0,
+
+    /**
+     * Can be used to get the random ID of the buffer. This ID should be psuedorandom with
+     * sufficient entropy.
+     *
+     * This ID should only be used for debugging purposes. It cannot be used as a basis for any
+     * control flows.
+     *
+     * The buffer ID is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The buffer ID is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    BUFFER_ID = 1,
+
+    /**
+     * Can be used to get the name passed in by the client at allocation time in the
+     * BufferDescriptorInfo.
+     *
+     * The buffer name is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The buffer name is a string.
+     *
+     * When it is encoded into a byte stream, the length of the string is written using 8 bytes in
+     * little endian. It is followed by a char array of the string's
+     * characters. The array is not null-terminated.
+     */
+    NAME = 2,
+
+    /**
+     * Can be used to get the number of elements per buffer row requested at allocation time in
+     * the BufferDescriptorInfo.
+     *
+     * The width is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The width is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    WIDTH = 3,
+
+    /**
+     * Can be used to get the number of elements per buffer column requested at allocation time in
+     * the BufferDescriptorInfo.
+     *
+     * The height is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The height is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    HEIGHT = 4,
+
+    /**
+     * Can be used to get the number of layers requested at allocation time in the
+     * BufferDescriptorInfo.
+     *
+     * The layer count is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The layer count is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    LAYER_COUNT = 5,
+
+    /**
+     * Can be used to get the buffer format requested at allocation time in the
+     * BufferDescriptorInfo.
+     *
+     * The requested pixel format is determined at allocation time and should not change during
+     * the lifetime of the buffer.
+     *
+     * The requested pixel format is a android.hardware.graphics.common@1.2::PixelFormat.
+     *
+     * When it is encoded into a byte stream, it is first cast to a int32_t and then represented in
+     * the byte stream by 4 bytes written in little endian.
+     */
+    PIXEL_FORMAT_REQUESTED = 6,
+
+    /**
+     * Can be used to get the fourcc code for the format. Fourcc codes are standard across all
+     * devices of the same kernel version. Fourcc codes must follow the Linux definition of a
+     * fourcc format found in: include/uapi/drm/drm_fourcc.h.
+     *
+     * The pixel format fourcc code is represented by a uint32_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 4 bytes written in little endian.
+     */
+    PIXEL_FORMAT_FOURCC = 7,
+
+    /**
+     * Can be used to get the modifier for the format. Together fourcc and modifier describe the
+     * real pixel format. Each fourcc and modifier pair is unique and must fully define the format
+     * and layout of the buffer. Modifiers can change any property of the buffer. Modifiers must
+     * follow the Linux definition of a modifier found in: include/uapi/drm/drm_fourcc.h.
+     *
+     * The pixel format modifier is represented by a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    PIXEL_FORMAT_MODIFIER = 8,
+
+    /**
+     * Can be used to get the usage requested at allocation time in the BufferDescriptorInfo.
+     *
+     * The usage is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The usage is a uint64_t bit field of android.hardware.graphics.common@1.2::BufferUsage's.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    USAGE = 9,
+
+    /**
+     * Can be used to get the total size in bytes of any memory used by the buffer including its
+     * metadata and extra padding. This is the total number of bytes used by the buffer allocation.
+     *
+     * The allocation size is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    ALLOCATION_SIZE = 10,
+
+    /**
+     * Can be used to get if a buffer has protected content. If the buffer does not have protected
+     * content, this should return 0. If a buffer has protected content, this should return 1.
+     *
+     * In future versions, this field will be extended to expose more information about the type
+     * of protected content in the buffer.
+     *
+     * The protected content is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    PROTECTED_CONTENT = 11,
+
+    /**
+     * Can be used to get the compression strategy of the buffer. If the device has more than one
+     * compression strategy, it should have different unique values for each compression
+     * strategy.
+     *
+     * Compression is a stable aidl android.hardware.graphics.common.ExtendableType.
+     *
+     * android.hardware.graphics.common.Compression defines the standard compression
+     * strategies. Vendors may extend this type to include any compression strategies.
+     *
+     * When it is encoded into a byte stream, the length of the name field string is written using
+     * 8 bytes in little endian. It is followed by a char array of the string's
+     * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+     * in little endian.
+     */
+    COMPRESSION = 12,
+
+    /**
+     * Can be used to get how the buffer's planes are interlaced.
+     *
+     * Interlaced is a stable aidl android.hardware.graphics.common.ExtendableType.
+     *
+     * android.hardware.graphics.common.Interlaced defines the standard interlaced
+     * strategies. Vendors may extend this type to include any non-standard interlaced
+     * strategies.
+     *
+     * When it is encoded into a byte stream, the length of the name field string is written using
+     * 8 bytes in little endian. It is followed by a char array of the string's
+     * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+     * in little endian.
+     */
+    INTERLACED = 13,
+
+    /**
+     * Can be used to get the chroma siting of a buffer.
+     *
+     * Chroma siting is a stable aidl android.hardware.graphics.common.ExtendableType.
+     *
+     * android.hardware.graphics.common.ChromaSiting defines the standard chroma
+     * sitings. Vendors may extend this type to include any non-standard chroma sitings.
+     *
+     * When it is encoded into a byte stream, the length of the name field string is written using
+     * 8 bytes in little endian. It is followed by a char array of the string's
+     * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+     * in little endian.
+     */
+    CHROMA_SITING = 14,
+
+    /**
+     * Can be used to get the PlaneLayout(s) of the buffer. There should be one PlaneLayout per
+     * plane in the buffer. For example if the buffer only has one plane, only one PlaneLayout
+     * should be returned.
+     *
+     * If the buffer has planes interlaced through time, the returned PlaneLayout structs should be
+     * ordered by time. The nth PlaneLayout should be from the same time or earlier than the
+     * n+1 PlaneLayout.
+     *
+     * The plane layout is a list of stable aidl android.hardware.graphics.common.PlaneLayout's.
+     *
+     * When it is encoded into a byte stream, the total number of PlaneLayouts is written using
+     * 8 bytes in little endian. It is followed by each PlaneLayout.
+     *
+     * To encode a PlaneLayout, write the length of its PlaneLayoutComponent[] components
+     * field as 8 bytes in little endian and then encode each of its components. Finally, write the
+     * following fields in this order each as 8 bytes in little endian: offsetInBytes,
+     * sampleIncrementInBits, strideInBytes, widthInSamples, totalSizeInBytes,
+     * horizontalSubsampling, verticalSubsampling.
+     *
+     * To encode a PlaneLayoutComponent, encode its PlaneLayoutComponentType type field. Next
+     * encode offsetInBits followed by sizeInBits each as 8 bytes in little endian.
+     *
+     * To encode a PlaneLayoutComponentType, write the length of the name field string as
+     * 8 bytes in little endian. It is followed by a char array of the string's
+     * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+     * in little endian.
+     */
+    PLANE_LAYOUTS = 15,
+
+    /**
+     * Can be used to get or set the dataspace of the buffer. The framework may attempt to set
+     * this value.
+     *
+     * The default dataspace is Dataspace::UNKNOWN. If this dataspace is set to any valid value
+     * other than Dataspace::UNKNOWN, this dataspace overrides all other dataspaces. For example,
+     * if the buffer has Dataspace::DISPLAY_P3 and it is being displayed on a composer Layer that
+     * is Dataspace::sRGB, the buffer should be treated as a DISPLAY_P3 buffer.
+     *
+     * The dataspace is a stable aidl android.hardware.graphics.common.Dataspace.
+     *
+     * When it is encoded into a byte stream, it is first cast to a int32_t and then represented in
+     * the byte stream by 4 bytes written in little endian.
+     */
+    DATASPACE = 16,
+
+    /**
+     * Can be used to get or set the BlendMode. The framework may attempt to set this value.
+     *
+     * The default blend mode is INVALID. If the BlendMode is set to any
+     * valid value other than INVALID, this BlendMode overrides all other
+     * dataspaces. For a longer description of this behavior see MetadataType::DATASPACE.
+     *
+     * The blend mode is a stable aidl android.hardware.graphics.common.BlendMode.
+     *
+     * When it is encoded into a byte stream, it is first cast to a int32_t and then represented by
+     * 4 bytes written in little endian.
+     */
+    BLEND_MODE = 17,
+}
diff --git a/health/storage/1.0/vts/functional/Android.bp b/health/storage/1.0/vts/functional/Android.bp
index 87502f8..a30cdde 100644
--- a/health/storage/1.0/vts/functional/Android.bp
+++ b/health/storage/1.0/vts/functional/Android.bp
@@ -22,6 +22,6 @@
     shared_libs: [
         "libhidlbase",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp b/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp
index 2365124..eaa44ec 100644
--- a/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp
+++ b/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/health/storage/1.0/IStorage.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
 #include <unistd.h>
 #include <thread>
 
@@ -101,25 +102,10 @@
     Result mResult{Result::UNKNOWN_ERROR};
 };
 
-/** Test environment for Health Storage HIDL HAL. */
-class HealthStorageHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    /** get the test environment singleton */
-    static HealthStorageHidlEnvironment* Instance() {
-        static HealthStorageHidlEnvironment* instance = new HealthStorageHidlEnvironment();
-        return instance;
-    }
-    virtual void registerTestServices() override { registerTestService<IStorage>(); }
-
-   private:
-    HealthStorageHidlEnvironment() {}
-};
-
-class HealthStorageHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class HealthStorageHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        fs = ::testing::VtsHalHidlTargetTestBase::getService<IStorage>(
-            HealthStorageHidlEnvironment::Instance()->getServiceName<IStorage>());
+        fs = IStorage::getService(GetParam());
 
         ASSERT_NE(fs, nullptr);
         LOG(INFO) << "Service is remote " << fs->isRemote();
@@ -153,7 +139,7 @@
 /**
  * Ensure garbage collection works on null callback.
  */
-TEST_F(HealthStorageHidlTest, GcNullCallback) {
+TEST_P(HealthStorageHidlTest, GcNullCallback) {
     auto ret = fs->garbageCollect(kDevGcTimeoutSec, nullptr);
 
     ASSERT_OK(ret);
@@ -167,28 +153,20 @@
 /**
  * Ensure garbage collection works on non-null callback.
  */
-TEST_F(HealthStorageHidlTest, GcNonNullCallback) {
+TEST_P(HealthStorageHidlTest, GcNonNullCallback) {
     sp<GcCallback> cb = new GcCallback();
     auto ret = fs->garbageCollect(kDevGcTimeoutSec, cb);
     ASSERT_OK(ret);
     cb->waitForResult(kDevGcTimeout + kDevGcTolerance + kRpcTime, Result::SUCCESS);
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, HealthStorageHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IStorage::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 }  // namespace V1_0
 }  // namespace storage
 }  // namespace health
 }  // namespace hardware
 }  // namespace android
-
-int main(int argc, char** argv) {
-    using ::android::hardware::configureRpcThreadpool;
-    using ::android::hardware::health::storage::V1_0::HealthStorageHidlEnvironment;
-
-    configureRpcThreadpool(1, false /* callerWillJoin*/);
-    ::testing::AddGlobalTestEnvironment(HealthStorageHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    HealthStorageHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index a7cbb36..0e12283 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -4338,25 +4338,29 @@
  * to specify how many following bytes will be used to encode the length.
  */
 TEST_F(AttestationTest, AttestationApplicationIDLengthProperlyEncoded) {
-    auto creation_time = std::chrono::system_clock::now();
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                 .EcdsaSigningKey(EcCurve::P_256)
-                                                 .Digest(Digest::SHA_2_256)));
+    std::vector<uint32_t> app_id_lengths{143, 258};
+    for (uint32_t length : app_id_lengths) {
+        auto creation_time = std::chrono::system_clock::now();
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                     .EcdsaSigningKey(EcCurve::P_256)
+                                                     .Digest(Digest::SHA_2_256)));
 
-    hidl_vec<hidl_vec<uint8_t>> cert_chain;
-    const string app_id(143, 'a');
-    ASSERT_EQ(ErrorCode::OK,
-              AttestKey(AuthorizationSetBuilder()
-                                .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
-                                .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id)),
-                        &cert_chain));
-    EXPECT_GE(cert_chain.size(), 2U);
+        hidl_vec<hidl_vec<uint8_t>> cert_chain;
+        const string app_id(length, 'a');
+        ASSERT_EQ(ErrorCode::OK,
+                  AttestKey(AuthorizationSetBuilder()
+                                    .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                                    .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id)),
+                            &cert_chain));
+        EXPECT_GE(cert_chain.size(), 2U);
 
-    EXPECT_TRUE(verify_attestation_record("challenge", app_id,                    //
-                                          key_characteristics_.softwareEnforced,  //
-                                          key_characteristics_.hardwareEnforced,  //
-                                          SecLevel(), cert_chain[0], creation_time));
+        EXPECT_TRUE(verify_attestation_record("challenge", app_id,                    //
+                                              key_characteristics_.softwareEnforced,  //
+                                              key_characteristics_.hardwareEnforced,  //
+                                              SecLevel(), cert_chain[0], creation_time));
+        CheckedDeleteKey();
+    }
 }
 /*
  * AttestationTest.AesAttestation
@@ -4600,6 +4604,57 @@
     }
 }
 
+typedef KeymasterHidlTest TransportLimitTest;
+
+/*
+ * TransportLimitTest.LargeFinishInput
+ *
+ * Verifies that passing large input data to finish either succeeds or fails as expected.
+ */
+TEST_F(TransportLimitTest, LargeFinishInput) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::ECB)
+                                                 .Padding(PaddingMode::NONE)));
+
+    for (int msg_size = 10 /*1KB*/; msg_size <= 17 /*128KB*/; msg_size++) {
+        auto cipher_params =
+                AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+
+        AuthorizationSet out_params;
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
+
+        string plain_message = std::string(1 << msg_size, 'x');
+        string encrypted_message;
+        auto rc = Finish(plain_message, &encrypted_message);
+
+        if (rc == ErrorCode::OK) {
+            EXPECT_EQ(plain_message.size(), encrypted_message.size())
+                    << "Encrypt finish returned OK, but did not consume all of the given input";
+        } else {
+            EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
+                    << "Encrypt finish failed in an unexpected way when given a large input";
+            continue;
+        }
+        cipher_params.push_back(out_params);
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
+
+        string decrypted_message;
+        rc = Finish(encrypted_message, &decrypted_message);
+
+        if (rc == ErrorCode::OK) {
+            EXPECT_EQ(plain_message.size(), decrypted_message.size())
+                    << "Decrypt finish returned OK, did not consume all of the given input";
+        } else {
+            EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
+                    << "Encrypt finish failed in an unexpected way when given a large input";
+        }
+    }
+
+    CheckedDeleteKey();
+}
 
 }  // namespace test
 }  // namespace V4_0
diff --git a/media/c2/1.1/Android.bp b/media/c2/1.1/Android.bp
new file mode 100644
index 0000000..c3e30b2
--- /dev/null
+++ b/media/c2/1.1/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.media.c2@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IComponent.hal",
+        "IComponentStore.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.omx@1.0",
+        "android.hardware.media@1.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/media/c2/1.1/IComponent.hal b/media/c2/1.1/IComponent.hal
new file mode 100644
index 0000000..97382dd
--- /dev/null
+++ b/media/c2/1.1/IComponent.hal
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2@1.1;
+
+import android.hardware.media.c2@1.0::IComponent;
+import android.hardware.media.c2@1.0::Status;
+
+/**
+ * Interface for a Codec2 component corresponding to API level 1.0 or below.
+ * Components have two states: stopped and running. The running state has three
+ * sub-states: executing, tripped and error.
+ *
+ * All methods in `IComponent` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status.
+ *
+ * @note This is an extension of version 1.0 of `IComponent`. The purpose of the
+ * extension is to add support for tunneling.
+ */
+interface IComponent extends @1.0::IComponent {
+    /**
+      * Configures a component for a tunneled playback mode.
+      *
+      * A successful call to this method puts the component in the *tunneled*
+      * mode. In this mode, the output `Worklet`s returned in
+      * IComponentListener::onWorkDone() may not contain any buffers. The output
+      * buffers are passed directly to the consumer end of a buffer queue whose
+      * producer side is configured with the returned @p sidebandStream passed
+      * to IGraphicBufferProducer::setSidebandStream().
+      *
+      * The component is initially in the non-tunneled mode by default. The
+      * tunneled mode can be toggled on only before the component starts
+      * processing. Once the component is put into the tunneled mode, it shall
+      * stay in the tunneled mode until and only until reset() is called.
+      *
+      * @param avSyncHwId A resource ID for hardware sync. The generator of sync
+      *     IDs must ensure that this number is unique among all services at any
+      *     given time. For example, if both the audio HAL and the tuner HAL
+      *     support this feature, sync IDs from the audio HAL must not clash
+      *     with sync IDs from the tuner HAL.
+      * @return status Status of the call, which may be
+      *   - `OK`        - The operation completed successfully. In this case,
+      *                   @p sidebandHandle shall not be a null handle.
+      *   - `OMITTED`   - The component does not support video tunneling.
+      *   - `BAD_STATE` - The component is already running.
+      *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+      *   - `CORRUPTED` - Some unknown error occurred.
+      * @return sidebandHandle Codec-allocated sideband stream handle. This can
+      *     be passed to IGraphicBufferProducer::setSidebandStream() to
+      *     establish a direct channel to the consumer.
+      */
+     configureVideoTunnel(
+             uint32_t avSyncHwId
+         ) generates (
+             Status status,
+             handle sidebandHandle
+         );
+};
diff --git a/media/c2/1.1/IComponentStore.hal b/media/c2/1.1/IComponentStore.hal
new file mode 100644
index 0000000..38e0fc6
--- /dev/null
+++ b/media/c2/1.1/IComponentStore.hal
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2@1.1;
+
+import android.hardware.media.bufferpool@2.0::IClientManager;
+import android.hardware.media.c2@1.0::IComponentListener;
+import android.hardware.media.c2@1.0::IComponentStore;
+import android.hardware.media.c2@1.0::Status;
+
+import IComponent;
+
+/**
+ * Entry point for Codec2 HAL.
+ *
+ * All methods in `IComponentStore` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status. The only exceptions are getPoolClientManager() and getConfigurable(),
+ * which must always return immediately.
+ *
+ * @note This is an extension of version 1.0 of `IComponentStore`. The purpose
+ * of the extension is to add support for tunneling.
+ */
+interface IComponentStore extends @1.0::IComponentStore {
+    /**
+     * Creates a component by name.
+     *
+     * @param name Name of the component to create. This must match one of the
+     *     names returned by listComponents().
+     * @param listener Callback receiver.
+     * @param pool `IClientManager` object of the BufferPool in the client
+     *     process. This may be null if the client does not own a BufferPool.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The component was created successfully.
+     *   - `NOT_FOUND` - There is no component with the given name.
+     *   - `NO_MEMORY` - Not enough memory to create the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return comp The created component if @p status is `OK`.
+     *
+     * @sa IComponentListener.
+     */
+    createComponent_1_1(
+            string name,
+            IComponentListener listener,
+            IClientManager pool
+        ) generates (
+            Status status,
+            IComponent comp
+        );
+};
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index 837ced5..ef71ea8 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -2448,15 +2448,17 @@
      *       then clipping is disabled.
      *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
      *       this scalar must be of the type {@link OperandType::FLOAT32},
-     *       otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16},
-     *       this scalar must be of type {@link OperandType::FLOAT16}.
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
      * * 50: The clipping threshold for the output from the
      *       projection layer, such that values are bound within
      *       [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
      *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
      *       this scalar must be of the type {@link OperandType::FLOAT32},
-     *       otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16},
-     *       this scalar must be of type {@link OperandType::FLOAT16}.
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
      * * 51: merge_outputs
      *       An {@link OperandType::BOOL} scalar specifying if the outputs
      *       from forward and backward cells should be merged.
@@ -4124,7 +4126,6 @@
      * * 0: A tensor of the same type and shape as input1 and input2.
      *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
      *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
-     *
      */
     SELECT = 84,
 
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index bdca0e9..fc727b7 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -71,5 +71,5 @@
     header_libs: [
         "libneuralnetworks_headers",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: ["general-tests"],
 }
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index aacb385..c1bf494 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -58,8 +58,20 @@
 using V1_1::ExecutionPreference;
 using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
 
+namespace {
+
+enum class Executor { ASYNC, SYNC, BURST };
+
 enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
 
+struct TestConfig {
+    Executor executor;
+    MeasureTiming measureTiming;
+    OutputType outputType;
+};
+
+}  // namespace
+
 Model createModel(const TestModel& testModel) {
     // Model operands.
     hidl_vec<Operand> operands(testModel.operands.size());
@@ -194,31 +206,31 @@
     return android::nn::ExecutionBurstController::create(preparedModel,
                                                          std::chrono::microseconds{0});
 }
-enum class Executor { ASYNC, SYNC, BURST };
 
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
-                           Executor executor, MeasureTiming measure, OutputType outputType) {
+                           const TestConfig& testConfig) {
     // If output0 does not have size larger than one byte, we can not test with insufficient buffer.
-    if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) {
+    if (testConfig.outputType == OutputType::INSUFFICIENT &&
+        !isOutputSizeGreaterThanOne(testModel, 0)) {
         return;
     }
 
     Request request = createRequest(testModel);
-    if (outputType == OutputType::INSUFFICIENT) {
+    if (testConfig.outputType == OutputType::INSUFFICIENT) {
         makeOutputInsufficientSize(/*outputIndex=*/0, &request);
     }
 
     ErrorStatus executionStatus;
     hidl_vec<OutputShape> outputShapes;
     Timing timing;
-    switch (executor) {
+    switch (testConfig.executor) {
         case Executor::ASYNC: {
             SCOPED_TRACE("asynchronous");
 
             // launch execution
             sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-            Return<ErrorStatus> executionLaunchStatus =
-                    ExecutePreparedModel(preparedModel, request, measure, executionCallback);
+            Return<ErrorStatus> executionLaunchStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, executionCallback);
             ASSERT_TRUE(executionLaunchStatus.isOk());
             EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
 
@@ -234,8 +246,8 @@
             SCOPED_TRACE("synchronous");
 
             // execute
-            Return<ErrorStatus> executionReturnStatus =
-                    ExecutePreparedModel(preparedModel, request, measure, &outputShapes, &timing);
+            Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, &outputShapes, &timing);
             ASSERT_TRUE(executionReturnStatus.isOk());
             executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
 
@@ -258,14 +270,14 @@
             // execute burst
             int n;
             std::tie(n, outputShapes, timing, std::ignore) =
-                    controller->compute(request, measure, keys);
+                    controller->compute(request, testConfig.measureTiming, keys);
             executionStatus = nn::convertResultCodeToErrorStatus(n);
 
             break;
         }
     }
 
-    if (outputType != OutputType::FULLY_SPECIFIED &&
+    if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
         executionStatus == ErrorStatus::GENERAL_FAILURE) {
         LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
                      "execute model that it does not support.";
@@ -274,7 +286,7 @@
                   << std::endl;
         GTEST_SKIP();
     }
-    if (measure == MeasureTiming::NO) {
+    if (testConfig.measureTiming == MeasureTiming::NO) {
         EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
         EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
     } else {
@@ -283,7 +295,7 @@
         }
     }
 
-    switch (outputType) {
+    switch (testConfig.outputType) {
         case OutputType::FULLY_SPECIFIED:
             // If the model output operands are fully specified, outputShapes must be either
             // either empty, or have the same number of elements as the number of outputs.
@@ -321,44 +333,29 @@
 
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
                            bool testDynamicOutputShape) {
+    std::initializer_list<OutputType> outputTypesList;
+    std::initializer_list<MeasureTiming> measureTimingList;
+    std::initializer_list<Executor> executorList;
+
     if (testDynamicOutputShape) {
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
+        outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
+        measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+        executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
     } else {
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
+        outputTypesList = {OutputType::FULLY_SPECIFIED};
+        measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+        executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+    }
+
+    for (const OutputType outputType : outputTypesList) {
+        for (const MeasureTiming measureTiming : measureTimingList) {
+            for (const Executor executor : executorList) {
+                const TestConfig testConfig = {.executor = executor,
+                                               .measureTiming = measureTiming,
+                                               .outputType = outputType};
+                EvaluatePreparedModel(preparedModel, testModel, testConfig);
+            }
+        }
     }
 }
 
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 86ab287..db86bf6 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -73,6 +73,4510 @@
     BASE_MAX        = 0xFFFF,
 };
 
+/**
+ * Operation types.
+ *
+ * The type of an operation in a model.
+ */
+enum OperationType : int32_t {
+
+    /**
+     * Adds two tensors, element-wise.
+     *
+     * Takes two input tensors of identical {@link OperandType} and compatible
+     * dimensions. The output is the sum of both input tensors, optionally
+     * modified by an activation function.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the output is the maximum size along each dimension of the
+     * input operands. It starts with the trailing dimensions, and works its
+     * way forward.
+     *
+     * Example:
+     *
+     *     input1.dimension = {4, 1, 2}
+     *     input2.dimension = {5, 4, 3, 1}
+     *     output.dimension = {5, 4, 3, 2}
+     *
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+     *      as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
+     * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     *
+     * Outputs:
+     * * 0: The sum, a tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    ADD = @1.2::OperationType:ADD,
+
+    /**
+     * Performs a 2-D average pooling operation.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, channel] =
+     *         sum_{di, dj}(
+     *             input[b, strides[1] * i + di, strides[2] * j + dj, channel]
+     *         ) / sum(1)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
+     *       Set to true to specify NCHW data layout for input0 and output0.
+     *       Available since HAL version 1.2.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    AVERAGE_POOL_2D = @1.2::OperationType:AVERAGE_POOL_2D,
+
+    /**
+     * Concatenates the input tensors along the given dimension.
+     *
+     * The input tensors must have identical {@link OperandType} and the same
+     * dimensions except the dimension along the concatenation axis.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (full support since HAL version 1.2, see the input section)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0 ~ n-1: The list of n input tensors, of shape
+     *            [D0, D1, ..., Daxis(i), ..., Dm].
+     *            Before HAL version 1.2, all input tensors of
+     *            {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *            must have the same scale and zeroPoint as the output tensor.
+     *            Since HAL version 1.2, zero-sized tensors are supported.
+     * * n: An {@link OperandType::INT32} scalar, specifying the
+     *      concatenation axis.
+     *
+     * Outputs:
+     * * 0: The output, a tensor of the same {@link OperandType} as the input
+     *      tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm].
+     *      Since HAL version 1.2, for a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint values can be different from
+     *      input tensors. Before HAL version 1.2 they have to be the same as for the input tensors.
+     */
+    CONCATENATION = @1.2::OperationType:CONCATENATION,
+
+    /**
+     * Performs a 2-D convolution operation.
+     *
+     * The CONV_2D op sweeps a 2-D filter that can mix channels together over a
+     * batch of images, applying the filter to each window of each image of the
+     * appropriate size.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, channel] =
+     *         sum_{di, dj, k} (
+     *             input[b, strides[1] * i + di, strides[2] * j + dj, k] *
+     *             filter[channel, di, dj, k]
+     *         ) + bias[channel]
+     *
+     * Supported tensor {@link OperandType} configurations:
+     * * 32 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias.
+     *
+     * * Quantized:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * Available since HAL version 1.2:
+     * * 16 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
+     *
+     * * Quantized with symmetric per channel quantization for the filter:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output.
+     * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+     * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+     * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_in], specifying the
+     *      filter.
+     *      For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     * * 11: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on width dimension. If this input is set,
+     *      input 12 (dilation factor for height) must be specified as well.
+     *      Available since HAL version 1.2.
+     * * 12: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on height dimension. If this input is set,
+     *      input 11 (dilation factor for width) must be specified as well.
+     *      Available since HAL version 1.2.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_in], specifying the
+     *      filter.
+     *      For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     * * 8: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on width dimension. If this input is set,
+     *      input 9 (dilation factor for height) must be specified as well.
+     *      Available since HAL version 1.2.
+     * * 9: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on height dimension. If this input is set,
+     *      input 8 (dilation factor for width) must be specified as well.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth_out].
+     *      Before HAL version 1.2, for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the following condition must be satisfied: output_scale > input_scale * filter_scale
+     */
+    CONV_2D = @1.2::OperationType:CONV_2D,
+
+    /**
+     * Performs a depthwise 2-D convolution operation.
+     *
+     * Given an input tensor of shape [batches, height, width, depth_in] and a
+     * filter tensor of shape [1, filter_height, filter_width, depth_out]
+     * containing depth_out convolutional filters of depth 1, DEPTHWISE_CONV
+     * applies a different filter to each input channel (expanding from 1
+     * channel to channel_multiplier channels for each), then concatenates the
+     * results together.
+     *
+     * The output has depth_out = depth_in * depth_multiplier channels.
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, k * channel_multiplier + q] =
+     *         sum_{di, dj} (
+     *             input[b, strides[1] * i + di, strides[2] * j + dj, k] *
+     *             filter[1, di, dj, k * channel_multiplier + q]
+     *         ) + bias[k * channel_multiplier + q]
+     *
+     * Supported tensor {@link OperandType} configurations:
+     * * 32 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias.
+     *
+     * * Quantized:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * Available since HAL version 1.2:
+     * * 16 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
+     *
+     * * Quantized with symmetric per channel quantization for the filter:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output.
+     * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+     * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+     * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
+     *      specifying the filter.
+     *      For tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 3.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 9: An {@link OperandType::INT32} scalar, specifying the depthwise
+     *      multiplier.
+     * * 10: An {@link OperandType::INT32} scalar, and has to be one of the
+     *       {@link FusedActivationFunc} values. Specifies the activation to
+     *       invoke on the result.
+     * * 11: An optional {@link OperandType::BOOL} scalar, default to false.
+     *       Set to true to specify NCHW data layout for input0 and output0.
+     *       Available since HAL version 1.2.
+     * * 12: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on width dimension. If this input is set,
+     *      input 13 (dilation factor for height) must be specified as well.
+     *      Available since HAL version 1.2.
+     * * 13: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on height dimension. If this input is set,
+     *      input 12 (dilation factor for width) must be specified as well.
+     *      Available since HAL version 1.2.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
+     *      specifying the filter.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32}
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+     *      and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the depthwise
+     *      multiplier.
+     * * 7: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 8: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     * * 9: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on width dimension. If this input is set,
+     *      input 10 (dilation factor for height) must be specified as well.
+     *      Available since HAL version 1.2.
+     * * 10: An optional {@link OperandType::INT32} scalar, specifying the dilation
+     *      factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+     *      cells between each filter element on height dimension. If this input is set,
+     *      input 9 (dilation factor for width) must be specified as well.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth_out]. Before HAL version 1.2, for
+     *      output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the following condition must be satisfied:
+     *      output_scale > input_scale * filter_scale
+     */
+    DEPTHWISE_CONV_2D = @1.2::OperationType:DEPTHWISE_CONV_2D,
+
+    /**
+     * Rearranges data from depth into blocks of spatial data.
+     *
+     * More specifically, this op outputs a copy of the input tensor where
+     * values from the depth dimension are moved in spatial blocks to the height
+     * and width dimensions. The value block_size indicates the input block size
+     * and how the data is moved.
+     *
+     * Chunks of data of size block_size * block_size from depth are rearranged
+     * into non-overlapping blocks of size block_size x block_size.
+     *
+     * The width of the output tensor is input_depth * block_size, whereas the
+     * height is input_height * block_size. The depth of the input tensor must
+     * be divisible by block_size * block_size
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the block_size.
+     *      block_size must be >=1 and block_size * block_size must be a divisor
+     *      of the input depth.
+     * * 2: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape [batch, height*block_size,
+     *      width*block_size, depth/(block_size*block_size)].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    DEPTH_TO_SPACE = @1.2::OperationType:DEPTH_TO_SPACE,
+
+    /**
+     * Dequantizes the input tensor.
+     *
+     * The formula is:
+     *
+     *     output = (input - zeroPoint) * scale.
+     *
+     * Supported input tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_SYMM} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} (since HAL version 1.2)
+     *
+     * Supported output tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}.
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: A tensor with the same shape as input0.
+     */
+    DEQUANTIZE = @1.2::OperationType:DEQUANTIZE,
+
+    /**
+     * Looks up sub-tensors in the input tensor.
+     *
+     * This operator takes for input a tensor of values (Values) and
+     * a one-dimensional tensor of selection indices (Lookups).
+     * The output tensor is the concatenation of sub-tensors of Values as
+     * selected by Lookups.
+     *
+     * Think of Values as being sliced along its first dimension:
+     * The entries in Lookups select which slices are concatenated together
+     * to create the output tensor.
+     *
+     * For example, if Values has shape of [40, 200, 300] and
+     * Lookups has shape of [3], all three values found in Lookups are
+     * expected to be between 0 and 39. The resulting tensor must
+     * have shape of [3, 200, 300].
+     *
+     * If a value in Lookups is out of bounds, the operation must fail
+     * and an error must be reported.
+     *
+     * Supported value tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported value tensor rank: from 2
+     *
+     * Inputs:
+     * * 0: Lookups. A 1-D tensor of {@link OperandType::TENSOR_INT32}.
+     *      The values are indices into the first dimension of Values.
+     * * 1: Values. An n-D tensor, where n >= 2, from which sub-tensors are
+     *      extracted.
+     *
+     * Output:
+     * * 0: A n-D tensor with the same rank and shape as the Values
+     *      tensor, except for the first dimension which has the same size
+     *      as Lookups' only dimension.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input1.
+     */
+    EMBEDDING_LOOKUP = @1.2::OperationType:EMBEDDING_LOOKUP,
+
+    /**
+     * Computes element-wise floor() on the input tensor.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor, of the same {@link OperandType} and dimensions as
+     *      the input tensor.
+     */
+    FLOOR = @1.2::OperationType:FLOOR,
+
+    /**
+     * Denotes a fully (densely) connected layer, which connects all elements
+     * in the input tensor with each element in the output tensor.
+     *
+     * This layer implements the operation:
+     *
+     *     outputs = activation(inputs * weights’ + bias)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor of at least rank 2, specifying the input. If rank is
+     *      greater than 2, then it gets flattened to a 2-D Tensor. The
+     *      (flattened) 2-D Tensor is reshaped (if necessary) to
+     *      [batch_size, input_size], where "input_size" corresponds to the
+     *      number of inputs to the layer, matching the second dimension of
+     *      weights, and "batch_size" is calculated by dividing the number of
+     *      elements by "input_size".
+     *      Since HAL version 1.2, zero batch_size is supported for this tensor.
+     * * 1: A 2-D tensor, specifying the weights, of shape
+     *      [num_units, input_size], where "num_units" corresponds to the number
+     *      of output nodes.
+     * * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input
+     *      tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
+     *      also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
+     *      of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
+     *      of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
+     *      bias_scale == input_scale * filter_scale.
+     * * 3: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     *
+     * Outputs:
+     * * 0: The output tensor, of shape [batch_size, num_units]. Before HAL version 1.2, for
+     *      output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following
+     *      condition must be satisfied: output_scale > input_scale * filter_scale.
+     */
+    FULLY_CONNECTED = @1.2::OperationType:FULLY_CONNECTED,
+
+    /**
+     * Looks up sub-tensors in the input tensor using a key-value map.
+     *
+     * This operator takes for input a tensor of values (Values),
+     * a one-dimensional tensor of selection values (Lookups) and
+     * a one-dimensional tensor that maps these values to Values
+     * indexes. The output tensor is the concatenation of sub-tensors of
+     * Values as selected by Lookups via Keys.
+     *
+     * Think of Values as being sliced along its outer-most dimension.
+     * The output is a concatenation of selected slices, with one slice
+     * for each entry of Lookups. The slice selected is the one at the
+     * same index as the Maps entry that matches the value in Lookups.
+     *
+     * For a hit, the corresponding sub-tensor of Values is included
+     * in the Output tensor. For a miss, the corresponding sub-tensor in
+     * Output must have zero values.
+     *
+     * For example, if Values has shape of [40, 200, 300],
+     * Keys should have a shape of [40]. If Lookups tensor has shape
+     * of [3], three slices are being concatenated, so the resulting tensor
+     * must have the shape of [3, 200, 300]. If the first entry in Lookups
+     * has the value 123456, that value must be located in Keys tensor.
+     * If the sixth entry of Keys contains 123456, the sixth slice of Values
+     * must be selected. If no entry in Keys has 123456, a slice of zeroes
+     * must be concatenated.
+     *
+     * Supported value tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported value tensor rank: from 2
+     *
+     * Inputs:
+     * * 0: Lookups. A 1-D {@link OperandType::TENSOR_INT32} tensor with
+     *      shape [ k ].
+     * * 1: Keys. A 1-D {@link OperandType::TENSOR_INT32} tensor with shape
+     *      [ n ]; Keys and Values pair represent a map, i.e., the ith element
+     *      in Keys (Keys[i]) is the key to select the ith sub-tensor in Values
+     *      (Values[i]), where 0 <= i <= n-1. Keys tensor *MUST* be sorted in
+     *      ascending order.
+     * * 2: Values. A tensor with shape of [ n, … ]; i.e., the first dimension
+     *      must be n.
+     *
+     * Outputs:
+     * * 0: Output. A tensor with shape [ k …].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input2.
+     * * 1: Hits. A boolean tensor with shape [ k ] indicates whether the lookup
+     *      hits (True) or not (False).
+     *      Stored as {@link OperandType::TENSOR_QUANT8_ASYMM} with offset 0
+     *      and scale 1.0f.
+     *      A non-zero byte represents True, a hit. A zero indicates otherwise.
+     */
+    HASHTABLE_LOOKUP = @1.2::OperationType:HASHTABLE_LOOKUP,
+
+    /**
+     * Applies L2 normalization along the depth dimension.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[batch, row, col, channel] =
+     *         input[batch, row, col, channel] /
+     *         sqrt(sum_{c} pow(input[batch, row, col, c], 2))
+     *
+     * For input tensor with rank less than 4, independently normalizes each
+     * 1-D slice along dimension dim.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+     *
+     * Supported tensor rank: up to 4
+     * Tensors with rank less than 4 are only supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be normalized.
+     * * 1: An optional {@link OperandType::INT32} scalar, default to -1,
+     *      specifying the dimension normalization would be performed on.
+     *      Negative index is used to specify axis from the end (e.g. -1 for
+     *      the last axis). Must be in the range [-n, n).
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} and same shape as input0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale must be 1.f / 128 and the zeroPoint must be 128.
+     */
+    L2_NORMALIZATION = @1.2::OperationType:L2_NORMALIZATION,
+
+    /**
+     * Performs an 2-D L2 pooling operation.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, c] =
+     *         sqrt(sum_{di, dj} pow(input[b, strides[1] * i + di, strides[2] * j + dj, c], 2) /
+     *              sum(1))
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
+     *       Set to true to specify NCHW data layout for input0 and output0.
+     *       Available since HAL version 1.2.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth].
+     */
+    L2_POOL_2D = @1.2::OperationType:L2_POOL_2D,
+
+    /**
+     * Applies Local Response Normalization along the depth dimension.
+     *
+     * The 4-D input tensor is treated as a 3-D array of 1-D vectors (along the
+     * last dimension), and each vector is normalized independently. Within a
+     * given vector, each component is divided by the weighted, squared sum of
+     * inputs within depth_radius.
+     *
+     * The output is calculated using this formula:
+     *
+     *     sqr_sum[a, b, c, d] = sum(
+     *         pow(input[a, b, c, d - depth_radius : d + depth_radius + 1], 2))
+     *     output = input / pow((bias + alpha * sqr_sum), beta)
+     *
+     * For input tensor with rank less than 4, independently normalizes each
+     * 1-D slice along specified dimension.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: up to 4
+     * Tensors with rank less than 4 are only supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the radius of
+     *      the normalization window.
+     * * 2: A scalar, specifying the bias, must not be zero.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the bias
+     *      value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias
+     *      value must be of {@link OperandType::FLOAT32}.
+     * * 3: A scalar, specifying the scale factor, alpha.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the
+     *      alpha value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the
+     *      alpha value must be of {@link OperandType::FLOAT32}.
+     * * 4: A scalar, specifying the exponent, beta.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the beta
+     *      value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the beta
+     *      value must be of {@link OperandType::FLOAT32}.
+     * * 5: An optional {@link OperandType::INT32} scalar, default to -1,
+     *      specifying the dimension normalization would be performed on.
+     *      Negative index is used to specify axis from the end (e.g. -1 for
+     *      the last axis). Must be in the range [-n, n).
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    LOCAL_RESPONSE_NORMALIZATION = @1.2::OperationType:LOCAL_RESPONSE_NORMALIZATION,
+
+    /**
+     * Computes sigmoid activation on the input tensor element-wise.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = 1 / (1 + exp(-input))
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale must be 1.f / 256 and the zeroPoint must be 0.
+     */
+    LOGISTIC = @1.2::OperationType:LOGISTIC,
+
+    /**
+     * Projects an input to a bit vector via locality senstive hashing.
+     *
+     * Supported input tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported input tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: Hash functions. Dim.size == 2, DataType: Float.
+     *      Tensor[0].Dim[0]: Number of hash functions.
+     *      Tensor[0].Dim[1]: Number of projected output bits generated by each
+     *      hash function.
+     *      If the projection type is Sparse:
+     *      Tensor[0].Dim[1] + ceil(log2(Tensor[0].Dim[0])) <= 32
+     *
+     * * 1: Input. Dim.size >= 1, no restriction on DataType.
+     * * 2: Weight. Optional. Dim.size == 1, DataType: Float.
+     *      If not set, each input element is considered to have the same weight
+     *      of 1.0.
+     *      Tensor[1].Dim[0] == Tensor[2].Dim[0]
+     * * 3: Type:
+     *        Sparse:
+     *          Value LSHProjectionType_SPARSE(=3) (since HAL version 1.2).
+     *          Computed bit vector is considered to be sparse.
+     *          Each output element is an int32 made up of multiple bits
+     *          computed from hash functions.
+     *
+     *          NOTE: To avoid collisions across hash functions, an offset value
+     *          of k * (1 << Tensor[0].Dim[1]) will be added to each signature,
+     *          where k is the index of the hash function.
+     *
+     *          Value LSHProjectionType_SPARSE_DEPRECATED(=1).
+     *          Legacy behavior that does not include the offset value.
+     *
+     *        Dense:
+     *          Value LSHProjectionType_DENSE(=2).
+     *          Computed bit vector is considered to be dense. Each output
+     *          element represents a bit and can take the value of either
+     *          0 or 1.
+     *
+     * Outputs:
+     * * 0: If the projection type is Sparse:
+     *      Output.Dim == { Tensor[0].Dim[0] }
+     *      A tensor of int32 that represents hash signatures.
+     *
+     *      If the projection type is Dense:
+     *      Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] }
+     *      A flattened tensor that represents projected bit vectors.
+     * The offset value for sparse projections was added in HAL version 1.2.
+     */
+    LSH_PROJECTION = @1.2::OperationType:LSH_PROJECTION,
+
+    /**
+     * Performs a single time step in a Long Short-Term Memory (LSTM) layer
+     *
+     * The LSTM operation is described by the following equations.
+     *
+     * \f{eqnarray*}{
+     * i_t =& \sigma(W_{xi}x_t+W_{hi}h_{t-1}+W_{ci}C_{t-1}+b_i) & \\
+     * f_t =& \sigma(W_{xf}x_t+W_{hf}h_{t-1}+W_{cf}C_{t-1}+b_f) & \\
+     * C_t =& clip(f_t \odot C_{t-1} + i_t \odot
+     *        g(W_{xc}x_t+W_{hc}h_{t-1}+b_c),\ t_{cell}) & \\
+     * o_t =& \sigma(W_{xo}x_t+W_{ho}h_{t-1}+W_{co}C_t+b_o) & \\
+     *      & & \\
+     *      & clip(W_{proj}(o_t \odot g(C_t))+b_{proj},\ t_{proj})
+     *      & if\ there\ is\ a\ projection; \\
+     * h_t =& & \\
+     *      & o_t \odot g(C_t) & otherwise. \\
+     * \f}
+     * Where:
+     * * \f$x_t\f$ is the input,
+     * * \f$i_t\f$ is the input gate,
+     * * \f$f_t\f$ is the forget gate,
+     * * \f$C_t\f$ is the cell state,
+     * * \f$o_t\f$ is the output,
+     * * \f$h_t\f$ is the output state,
+     * * \f$\sigma\f$ is the logistic sigmoid function,
+     * * \f$g\f$ is the cell input and cell output activation function, usually
+     *   \f$tahn\f$,
+     * * \f$W_{xi}\f$ is the input-to-input weight matrix,
+     * * \f$W_{hi}\f$ is the recurrent to input weight matrix,
+     * * \f$W_{ci}\f$ is the cell-to-input weight matrix,
+     * * \f$b_i\f$ is the input gate bias,
+     * * \f$W_{xf}\f$ is the input-to-forget weight matrix,
+     * * \f$W_{hf}\f$ is the recurrent-to-forget weight matrix,
+     * * \f$W_{cf}\f$ is the cell-to-forget weight matrix,
+     * * \f$b_f\f$ is the forget gate bias,
+     * * \f$W_{xc}\f$ is the input-to-cell weight matrix,
+     * * \f$W_{hc}\f$ is the recurrent-to-cell weight matrix,
+     * * \f$b_c\f$ is the cell bias,
+     * * \f$W_{xo}\f$ is the input-to-output weight matrix,
+     * * \f$W_{ho}\f$ is the recurrent-to-output weight matrix,
+     * * \f$W_{co}\f$ is the cell-to-output weight matrix,
+     * * \f$b_o\f$ is the output gate bias,
+     * * \f$W_{proj}\f$ is the projection weight matrix,
+     * * \f$b_{proj}\f$ is the projection bias,
+     * * \f$t_{cell}\f$ is the threshold for clipping the cell state, and
+     * * \f$t_{proj}\f$ is the threshold for clipping the projected output.
+     * * \f$\odot\f$ is the
+     *   <a href="https://en.wikipedia.org/wiki/Hadamard_product_(matrices)">
+     *   Hadamard product</a> that takes two matrices and produces another
+     *   matrix, each element of which is the product of the corresponding
+     *   elements of the input matrices.
+     *
+     * Since HAL version 1.2 LSTM supports layer normalization.
+     * In case layer normalization is used, the inputs to internal activation
+     * functions (sigmoid and \f$g\f$) are normalized, rescaled and recentered
+     * following an approach from section 3.1 from
+     * https://arxiv.org/pdf/1607.06450.pdf
+     *
+     * The operation has the following independently optional inputs:
+     * * The cell-to-input weights (\f$W_{ci}\f$), cell-to-forget weights
+     *   (\f$W_{cf}\f$) and cell-to-output weights (\f$W_{co}\f$) either all
+     *   have values or neither of them have values (i.e., all set to null). If
+     *   they have values, the peephole optimization is used.
+     * * The input-to-input weights (\f$W_{xi}\f$), recurrent-to-input weights
+     *   (\f$W_{hi}\f$) and input gate bias (\f$b_i\f$) either all have values,
+     *   or none of them have values. If they have no values, coupling of input
+     *   and forget gates (CIFG) is used, in which case the input gate
+     *   (\f$i_t\f$) is calculated using the following equation instead.
+     *   \f{eqnarray*}{
+     *   i_t = 1 - f_t
+     *   \f}
+     *   In case peephole optimization is used and CIFG is not used
+     *   cell-to-input (\f$W_{ci}\f$) weights must be present. Otherwise, the
+     *   cell-to-input weights must have no value.
+     * * The projection weights (\f$W_{proj}\f$) is required only for the
+     *   recurrent projection layer, and should otherwise have no value.
+     * * The projection bias (\f$b_{proj}\f$) may (but not required to) have a
+     *   value if the recurrent projection layer exists, and should otherwise
+     *   have no value.
+     * * (HAL version 1.2 or later) The four layer normalization weights either all have
+     *   values or none of them have values. Additionally, if CIFG is used,
+     *   input layer normalization weights tensor is omitted and the other layer
+     *   normalization weights either all have values or none of them have
+     *   values. Layer normalization is used when the values of all the layer
+     *   normalization weights are present.
+     *
+     * References:
+     *
+     * The default non-peephole non-CIFG implementation is based on:
+     * http://www.bioinf.jku.at/publications/older/2604.pdf
+     * S. Hochreiter and J. Schmidhuber. "Long Short-Term Memory". Neural
+     * Computation, 9(8):1735-1780, 1997.
+     *
+     * The peephole implementation and projection layer is based on:
+     * https://research.google.com/pubs/archive/43905.pdf
+     * Hasim Sak, Andrew Senior, and Francoise Beaufays. "Long short-term memory
+     * recurrent neural network architectures for large scale acoustic
+     * modeling." INTERSPEECH, 2014.
+     * (However, the concept of peephole optimization was introduced in work
+     * prior to this paper.)
+     *
+     * The coupling of input and forget gate (CIFG) is based on:
+     * http://arxiv.org/pdf/1503.04069.pdf
+     * Greff et al. "LSTM: A Search Space Odyssey"
+     *
+     * The layer normalization is based on:
+     * https://arxiv.org/pdf/1607.06450.pdf
+     * Jimmy Ba et al. "Layer Normalization"
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * All input and output tensors must be of the same type.
+     *
+     * Inputs:
+     * * 0: The input (\f$x_t\f$).
+     *      A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+     *      corresponds to the batching dimension, and “input_size” is the size
+     *      of the input.
+     * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of cell units.
+     * * 2: The input-to-forget weights (\f$W_{xf}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 3: The input-to-cell weights (\f$W_{xc}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 4: The input-to-output weights (\f$W_{xo}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional.
+     *      A 2-D tensor of shape [num_units, output_size], where “output_size”
+     *      corresponds to either the number of cell units (i.e., “num_units”),
+     *      or the second dimension of the “projection_weights”, if defined.
+     * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 8: The recurrent-to-output weights (\f$W_{ho}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 12:The input gate bias (\f$b_i\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 13:The forget gate bias (\f$b_f\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 14:The cell bias (\f$b_c\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 15:The output gate bias (\f$b_o\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 16:The projection weights (\f$W_{proj}\f$). Optional.
+     *      A 2-D tensor of shape [output_size, num_units].
+     * * 17:The projection bias (\f$b_{proj}\f$). Optional.
+     *      A 1-D tensor of shape [output_size].
+     * * 18:The output state (in) (\f$h_{t-1}\f$).
+     *      A 2-D tensor of shape [batch_size, output_size].
+     * * 19:The cell state (in) (\f$C_{t-1}\f$).
+     *      A 2-D tensor of shape [batch_size, num_units].
+     * * 20:The activation function (\f$g\f$).
+     *      A value indicating the activation function:
+     *      <ul>
+     *      <li>0: None;
+     *      <li>1: Relu;
+     *      <li>3: Relu6;
+     *      <li>4: Tanh;
+     *      <li>6: Sigmoid.
+     *      </ul>
+     * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such
+     *      that values are bound within [-cell_clip, cell_clip]. If set to 0.0
+     *      then clipping is disabled.
+     *      Until HAL version 1.2 this scalar must be of type {@link
+     *      OperandType::FLOAT32}. Since HAL version 1.2, if all the input
+     *      tensors have type {@link OperandType::TENSOR_FLOAT32}, this
+     *      scalar must be of the type {@link OperandType::FLOAT32},
+     *      otherwise if all the input tensors have the type {@link
+     *      OperandType::TENSOR_FLOAT16}, this scalar must be of type {@link
+     *      OperandType::FLOAT16}.
+     * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the
+     *      projection layer, such that values are bound within
+     *      [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
+     *      Until HAL version 1.2 this scalar must be of type {@link
+     *      OperandType::FLOAT32}. Since HAL version 1.2, if all the input
+     *      tensors have type {@link OperandType::TENSOR_FLOAT32}, this
+     *      scalar must be of the type {@link OperandType::FLOAT32},
+     *      otherwise if all the input tensors have the type {@link
+     *      OperandType::TENSOR_FLOAT16}, this scalar must be of type {@link
+     *      OperandType::FLOAT16}.
+     * Since HAL version 1.2 there are additional inputs to this op:
+     * * 23:The input layer normalization weights.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at input gate.
+     * * 24:The forget layer normalization weights.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at forget gate.
+     * * 25:The cell layer normalization weights.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at cell gate.
+     * * 26:The output layer normalization weights.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at output gate.
+     *
+     * Outputs:
+     * * 0: The scratch buffer.
+     *      A 2-D tensor of shape [batch_size, num_units * 3] with CIFG, or
+     *      [batch_size, num_units * 4] without CIFG.
+     * * 1: The output state (out) (\f$h_t\f$).
+     *      A 2-D tensor of shape [batch_size, output_size].
+     * * 2: The cell state (out) (\f$C_t\f$).
+     *      A 2-D tensor of shape [batch_size, num_units].
+     * * 3: The output (\f$o_t\f$).
+     *      A 2-D tensor of shape [batch_size, output_size]. This is effectively
+     *      the same as the current “output state (out)” value.
+     */
+    LSTM = @1.2::OperationType:LSTM,
+
+    /**
+     * Performs an 2-D max pooling operation.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, channel] =
+     *         max_{di, dj} (
+     *             input[b, strides[1] * i + di, strides[2] * j + dj, channel]
+     *         )
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 10: An optional {@link OperandType::BOOL} scalar, default to false.
+     *       Set to true to specify NCHW data layout for input0 and output0.
+     *       Available since HAL version 1.2.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the filter
+     *      width.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the filter
+     *      height.
+     * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 7: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    MAX_POOL_2D = @1.2::OperationType:MAX_POOL_2D,
+
+    /**
+     * Multiplies two tensors, element-wise.
+     *
+     * Takes two input tensors of identical {@link OperandType} and compatible
+     * dimensions. The output is the product of both input tensors, optionally
+     * modified by an activation function.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the resulting output is the maximum size along each dimension
+     * of the input operands. It starts with the trailing dimensions, and works
+     * its way forward.
+     *
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+     *      as input0.
+     * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     *
+     * Outputs:
+     * * 0: The product, a tensor of the same {@link OperandType} as input0.
+     *      For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      the following condition must be satisfied:
+     *      output_scale > input1_scale * input2_scale.
+     */
+    MUL = @1.2::OperationType:MUL,
+
+    /**
+     * Computes rectified linear activation on the input tensor element-wise.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = max(0, input)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RELU = @1.2::OperationType:RELU,
+
+    /**
+     * Computes rectified linear 1 activation on the input tensor element-wise.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = min(1.f, max(-1.f, input))
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of the same shape as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RELU1 = @1.2::OperationType:RELU1,
+
+    /**
+     * Computes rectified linear 6 activation on the input tensor element-wise.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = min(6, max(0, input))
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RELU6 = @1.2::OperationType:RELU6,
+
+    /**
+     * Reshapes a tensor.
+     *
+     * Given tensor, this operation returns a tensor that has the same values as
+     * tensor, but with a newly specified shape.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the tensor to be reshaped.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}, defining the
+     *      shape of the output tensor. The number of elements implied by shape
+     *      must be the same as the number of elements in the input tensor.
+     *
+     *      If one component of shape is the special value -1, the size of that
+     *      dimension is computed so that the total size remains constant. In
+     *      particular, a shape of [-1] flattens into 1-D. At most one component
+     *      of shape can be -1.
+     *
+     * Outputs:
+     * * 0: The output tensor, of shape specified by the input shape.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RESHAPE = @1.2::OperationType:RESHAPE,
+
+    /**
+     * Resizes images to given size using the bilinear interpretation.
+     *
+     * Resized images must be distorted if their output aspect ratio is not the
+     * same as input aspect ratio. The corner pixels of output may not be the
+     * same as corner pixels of input.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Both resizing by shape and resizing by scale are supported.
+     *
+     * Inputs (resizing by shape):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input.
+     *      Since HAL version 1.2, zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the output
+     *      width of the output tensor.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
+     * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Inputs (resizing by scale, since HAL version 1.2):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input. Zero batches is supported for this tensor.
+     * * 1: A scalar, specifying width_scale, the scaling factor of the width
+     *      dimension from the input tensor to the output tensor. The output
+     *      width is calculated as new_width = floor(width * width_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 2: A scalar, specifying height_scale, the scaling factor of the height
+     *      dimension from the input tensor to the output tensor. The output
+     *      height is calculated as new_height = floor(height * height_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, new_height, new_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RESIZE_BILINEAR = @1.2::OperationType:RESIZE_BILINEAR,
+
+    /**
+     * A basic recurrent neural network layer.
+     *
+     * This layer implements the operation:
+     * outputs = state = activation(inputs * input_weights +
+     *                              state * recurrent_weights + bias)
+     *
+     * Where:
+     * * “input_weights” is a weight matrix that multiplies the inputs;
+     * * “recurrent_weights” is a weight matrix that multiplies the current
+     *    “state” which itself is the output from the previous time step
+     *    computation;
+     * * “bias” is a bias vector (added to each output vector in the batch);
+     * * “activation” is the function passed as the “fused_activation_function”
+     *   argument (if not “NONE”).
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * The input tensors must all be the same type.
+     *
+     * Inputs:
+     * * 0: input.
+     *      A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+     *      corresponds to the batching dimension, and “input_size” is the size
+     *      of the input.
+     * * 1: weights.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of units.
+     * * 2: recurrent_weights.
+     *      A 2-D tensor of shape [num_units, num_units], with columns
+     *      corresponding to the weights from each unit.
+     * * 3: bias.
+     *      A 1-D tensor of shape [num_units].
+     * * 4: hidden state (in).
+     *      A 2-D tensor of shape [batch_size, num_units].
+     * * 5: fused_activation_function.
+     *      An optional {@link FusedActivationFunc} value indicating the
+     *      activation function. If “NONE” is specified then it results in a
+     *      linear activation.
+     *
+     * Outputs:
+     * * 0: hidden state (out).
+     *      A 2-D tensor of shape [batch_size, num_units].
+     *
+     * * 1: output.
+     *      A 2-D tensor of shape [batch_size, num_units]. This is effectively
+     *      the same as the current state value.
+     */
+    RNN = @1.2::OperationType:RNN,
+
+    /**
+     * Computes the softmax activation on the input tensor element-wise, per
+     * batch, by normalizing the input vector so the maximum coefficient is
+     * zero.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output[batch, i] =
+     *         exp((input[batch, i] - max(input[batch, :])) * beta) /
+     *         sum_{k}{exp((input[batch, k] - max(input[batch, :])) * beta)}
+     *
+     * For input tensor with rank other than 2, the activation will be applied
+     * independently on each 1-D slice along specified dimension.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4.
+     * Tensors with rank other than 2 or 4 are only supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     * * 1: A scalar, specifying the positive scaling factor for the exponent,
+     *      beta. If input0 is of {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the scalar must be of
+     *      {@link OperandType::FLOAT32}.
+     *      If input0 is of {@link OperandType::TENSOR_FLOAT16}, then the
+     *      scalar must be of {@link OperandType::FLOAT16}.
+     * * 2: An optional {@link OperandType::INT32} scalar, default to -1,
+     *      specifying the dimension the activation would be performed on.
+     *      Negative index is used to specify axis from the end (e.g. -1 for
+     *      the last axis). Must be in the range [-n, n).
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale must be 1.f / 256 and the zeroPoint must be 0.
+     */
+    SOFTMAX = @1.2::OperationType:SOFTMAX,
+
+    /**
+     * Rearranges blocks of spatial data, into depth.
+     *
+     * More specifically, this op outputs a copy of the input tensor where
+     * values from the height and width dimensions are moved to the depth
+     * dimension. The value block_size indicates the input block size and how
+     * the data is moved.
+     *
+     * Chunks of data of size block_size * block_size from depth are rearranged
+     * into non-overlapping blocks of size block_size x block_size.
+     *
+     * The depth of the output tensor is input_depth * block_size * block_size.
+     * The input tensor's height and width must be divisible by block_size.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the block_size.
+     *      block_size must be >=1 and block_size must be a divisor of both the
+     *      input height and width.
+     * * 2: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape [batches, height/block_size,
+     *      width/block_size, depth_in*block_size*block_size].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    SPACE_TO_DEPTH = @1.2::OperationType:SPACE_TO_DEPTH,
+
+    /**
+     * SVDF op is a kind of stateful layer derived from the notion that a
+     * densely connected layer that's processing a sequence of input frames can
+     * be approximated by using a singular value decomposition of each of its
+     * nodes. The implementation is based on:
+     *
+     * https://research.google.com/pubs/archive/43813.pdf
+     *
+     * P. Nakkiran, R. Alvarez, R. Prabhavalkar, C. Parada.
+     * “Compressing Deep Neural Networks using a Rank-Constrained Topology”.
+     * INTERSPEECH, 2015.
+     *
+     * It processes the incoming input using a 2-stage filtering mechanism:
+     * * stage 1 performs filtering on the "features" dimension, whose outputs
+     *   get pushed into a memory of fixed-size memory_size.
+     * * stage 2 performs filtering on the "time" dimension of the memory_size
+     *   memoized outputs of stage 1.
+     *
+     * Specifically, for rank 1, this layer implements the operation:
+     *
+     *     memory = push(conv1d(inputs, weights_feature, feature_dim,
+     *                          "PADDING_VALID"));
+     *     outputs = activation(memory * weights_time + bias);
+     *
+     * Where:
+     * * “weights_feature” is a weights matrix that processes the inputs (by
+     *   convolving the input with every “feature filter”), and whose outputs
+     *   get pushed, stacked in order, into the fixed-size “memory” (the oldest
+     *   entry gets dropped);
+     * * “weights_time” is a weights matrix that processes the “memory” (by a
+     *   batched matrix multiplication on the num_units);
+     * * “bias” is an optional bias vector (added to each output vector in the
+     *   batch); and
+     * * “activation” is the function passed as the “fused_activation_function”
+     *   argument (if not “NONE”).
+     *
+     * Each rank adds a dimension to the weights matrices by means of stacking
+     * the filters.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * All input tensors must be the same type.
+     *
+     * Inputs:
+     * * 0: input.
+     *      A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+     *      corresponds to the batching dimension, and “input_size” is the size
+     *      of the input.
+     * * 1: weights_feature.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of units.
+     * * 2: weights_time.
+     *      A 2-D tensor of shape [num_units, memory_size], where “memory_size”
+     *      corresponds to the fixed-size of the memory.
+     * * 3: bias.
+     *      An optional 1-D tensor of shape [num_units].
+     * * 4: state (in).
+     *      A 2-D tensor of shape [batch_size, (memory_size - 1) * num_units * rank].
+     * * 5: rank.
+     *      The rank of the SVD approximation.
+     * * 6: fused_activation_function.
+     *      An optional {@link FusedActivationFunc} value indicating the
+     *      activation function. If “NONE” is specified then it results in a
+     *      linear activation.
+     *
+     * Outputs:
+     * * 0: state (out).
+     *      A 2-D tensor of the same {@link OperandType} as the inputs, with shape
+     *      [batch_size, (memory_size - 1) * num_units * rank].
+     * * 1: output.
+     *      A 2-D tensor of the same {@link OperandType} as the inputs, with shape
+     *      [batch_size, num_units].
+     */
+    SVDF = @1.2::OperationType:SVDF,
+
+    /**
+     * Computes hyperbolic tangent of input tensor element-wise.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = tanh(input)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+     *
+     * Supported tensor rank: up to 4.
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale must be 1.f / 128 and the zeroPoint must be 128.
+     */
+    TANH = @1.2::OperationType:TANH,
+
+    /**
+     * BatchToSpace for N-dimensional tensors.
+     *
+     * This operation reshapes the batch dimension (dimension 0) into M + 1
+     * dimensions of shape block_shape + [batch], interleaves these blocks back
+     * into the grid defined by the spatial dimensions [1, ..., M], to obtain a
+     * result with the same rank as the input.
+     *
+     * This is the reverse of SpaceToBatch.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be reshaped
+     * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the block
+     *      sizes for each spatial dimension of the input tensor. All values
+     *      must be >= 1.
+     * * 2: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since API level 29.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    BATCH_TO_SPACE_ND = @1.2::OperationType:BATCH_TO_SPACE_ND,
+
+    /**
+     * Element-wise division of two tensors.
+     *
+     * Takes two input tensors of identical {@link OperandType} and compatible
+     * dimensions. The output is the result of dividing the first input tensor
+     * by the second, optionally modified by an activation function.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the output is the maximum size along each dimension of the
+     * input operands. It starts with the trailing dimensions, and works its way
+     * forward.
+     *
+     * Example:
+     *     input1.dimension =    {4, 1, 2}
+     *     input2.dimension = {5, 4, 3, 1}
+     *     output.dimension = {5, 4, 3, 2}
+     *
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the first input.
+     * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+     *      as input0.
+     * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     */
+    DIV = @1.2::OperationType:DIV,
+
+    /**
+     * Computes the mean of elements across dimensions of a tensor.
+     *
+     * Reduces the input tensor along the given dimensions to reduce. Unless
+     * keep_dims is true, the rank of the tensor is reduced by 1 for each entry
+     * in axis. If keep_dims is true, the reduced dimensions are retained with
+     * length 1.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Must be in the range
+     *      [-rank(input_tensor), rank(input_tensor)).
+     *
+     *      NOTE: When the operation was introduced, the documentation
+     *      incorrectly stated that if dimensions were empty, the operation
+     *      would reduce across all dimensions. This behavior was never
+     *      implemented.
+     *
+     * * 2: An {@link OperandType::INT32} scalar, keep_dims. If positive,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be same as input0.
+     */
+    MEAN = @1.2::OperationType:MEAN,
+
+    /**
+     * Pads a tensor.
+     *
+     * This operation pads a tensor according to the specified paddings.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (full support since HAL version 1.2, see the output section)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be padded.
+     * * 1: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings
+     *      for each spatial dimension of the input tensor. The shape of the
+     *      tensor must be {rank(input0), 2}.
+     *      padding[i, 0] specifies the number of elements to be padded in the
+     *      front of dimension i.
+     *      padding[i, 1] specifies the number of elements to be padded after the
+     *      end of dimension i.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0. The
+     *      output tensor has the same rank as input0, and each
+     *      dimension of the output tensor has the same size as the
+     *      corresponding dimension of the input tensor plus the size
+     *      of the padding:
+     *          output0.dimension[i] =
+     *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     *
+     *      NOTE: Before HAL version 1.2, the pad value for
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} is undefined.
+     *      Since HAL version 1.2, the pad value is always the logical zero.
+     */
+    PAD = @1.2::OperationType:PAD,
+
+    /**
+     * SpaceToBatch for N-Dimensional tensors.
+     *
+     * This operation divides "spatial" dimensions [1, ..., M] of the input into
+     * a grid of blocks of shape block_shape, and interleaves these blocks with
+     * the "batch" dimension (0) such that in the output, the spatial dimensions
+     * [1, ..., M] correspond to the position within the grid, and the batch
+     * dimension combines both the position within a spatial block and the
+     * original batch position. Prior to division into blocks, the spatial
+     * dimensions of the input are optionally zero padded according to paddings.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *   (full support since HAL version 1.2, see the output section)
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     * NCHW is supported since HAL version 1.2.
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the input.
+     * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the block
+     *      sizes for each spatial dimension of the input tensor. All values
+     *      must be >= 1.
+     * * 2: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings
+     *      for each spatial dimension of the input tensor. All values must be
+     *      >= 0. The shape of the tensor must be {M, 2}, where M is the number
+     *      of spatial dimensions.
+     *      padding[i, 0] specifies the number of element to be padded in the
+     *      front of dimension i.
+     *      padding[i, 1] specifies the number of element to be padded after the
+     *      end of dimension i.
+     * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *      Available since HAL version 1.2.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     *
+     *      NOTE: Before HAL version 1.2, the pad value for
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} is undefined.
+     *      Since HAL version 1.2, the pad value is always the logical zero.
+     */
+    SPACE_TO_BATCH_ND = @1.2::OperationType:SPACE_TO_BATCH_ND,
+
+    /**
+     * Removes dimensions of size 1 from the shape of a tensor.
+     *
+     * Given a tensor input, this operation returns a tensor of the same
+     * {@link OperandType} with all dimensions of size 1 removed. If you don't
+     * want to remove all size 1 dimensions, you can remove specific size 1
+     * dimensions by specifying the axes (input1).
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, the tensor to be squeezed.
+     * * 1: An optional 1-D tensor of {@link OperandType::TENSOR_INT32}. The
+     *      dimensions to squeeze. If specified only squeezes the dimensions
+     *      listed. Otherwise, squeezes all dimensions. The dimension index
+     *      starts at 0. An error must be reported if squeezing a dimension that
+     *      is not 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0. Contains the
+     *      same data as input, but has one or more dimensions of size 1
+     *      removed.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    SQUEEZE = @1.2::OperationType:SQUEEZE,
+
+    /**
+     * Extracts a strided slice of a tensor.
+     *
+     * Roughly speaking, this op extracts a slice of size (end - begin) / stride
+     * from the given input tensor. Starting at the location specified by begin
+     * the slice continues by adding stride to the index until all dimensions
+     * are not less than end. Note that a stride can be negative, which causes a
+     * reverse slice.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be sliced.
+     * * 1: begin, a 1-D tensor of {@link OperandType::TENSOR_INT32}. The
+     *      starts of the dimensions of the input tensor to be sliced. The
+     *      length must be of rank(input0).
+     * * 2: end, a 1-D tensor of {@link OperandType::TENSOR_INT32}. The
+     *      ends of the dimensions of the input tensor to be sliced. The length
+     *      must be of rank(input0).
+     * * 3: strides, a 1-D tensor of {@link OperandType::TENSOR_INT32}. The
+     *      strides of the dimensions of the input tensor to be sliced. The
+     *      length must be of rank(input0). The entries must be non-zero.
+     * * 4: begin_mask, an {@link OperandType::INT32} scalar. If the ith bit
+     *      of begin_mask is set, begin[i] is ignored and the fullest possible
+     *      range in that dimension is used instead.
+     * * 5: end_mask, an {@link OperandType::INT32} scalar. If the ith bit of
+     *      end_mask is set, end[i] is ignored and the fullest possible range in
+     *      that dimension is used instead.
+     * * 6: shrink_axis_mask, an {@link OperandType::INT32} scalar. If the
+     *      ith bit of shrink_axis_mask is set, the ith dimension specification
+     *      shrinks the dimensionality by 1, taking on the value at index
+     *      begin[i]. In this case, the ith specification must define a
+     *      slice of size 1, e.g. begin[i] = x, end[i] = x + 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0 and rank (n - k),
+     *      where k is the number of bits set in shrink_axis_mask.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    STRIDED_SLICE = @1.2::OperationType:STRIDED_SLICE,
+
+    /**
+     * Element-wise subtraction of two tensors.
+     *
+     * Takes two input tensors of identical {@link OperandType} and compatible
+     * dimensions. The output is the result of subtracting the second input
+     * tensor from the first one, optionally modified by an activation function.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the output is the maximum size along each dimension of the
+     * input operands. It starts with the trailing dimensions, and works its way
+     * forward.
+     *
+     * Example:
+     *     input1.dimension =    {4, 1, 2}
+     *     input2.dimension = {5, 4, 3, 1}
+     *     output.dimension = {5, 4, 3, 2}
+     *
+     * Since HAL version 1.2, generic zero-sized input tensor is supported. Zero
+     * dimension is only compatible with 0 or 1. The size of the output
+     * dimension is zero if either of corresponding input dimension is zero.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the first input.
+     * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+     *      as input0.
+     * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    SUB = @1.2::OperationType:SUB,
+
+    /**
+     * Transposes the input tensor, permuting the dimensions according to the
+     * perm tensor.
+     *
+     * The returned tensor's dimension i corresponds to the input dimension
+     * perm[i]. If perm is not given, it is set to (n-1...0), where n is the
+     * rank of the input tensor. Hence by default, this operation performs a
+     * regular matrix transpose on 2-D input Tensors.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be transposed.
+     *      Since HAL version 1.2, this tensor may be zero-sized.
+     * * 1: An optional 1-D Tensor of {@link OperandType::TENSOR_INT32},
+     *      the permutation of the dimensions of the input tensor.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    TRANSPOSE = @1.2::OperationType:TRANSPOSE,
+
+    /**
+     * Computes the absolute value of a tensor, element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    ABS = @1.2::OperationType:ABS,
+
+    /**
+     * Returns the index of the largest element along an axis.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor specifying the input. Must be non-empty.
+     * * 1: An {@link OperandType::INT32} scalar specifying the axis to
+     *      reduce across. Negative index is used to specify axis from the
+     *      end (e.g. -1 for the last axis). Must be in the range [-n, n).
+     *
+     * Outputs:
+     * * 0: An (n - 1)-D {@link OperandType::TENSOR_INT32} tensor.
+     */
+    // There is no underscore in ARG_MAX to avoid name conflict with
+    // the macro defined in libc/kernel/uapi/linux/limits.h.
+    ARGMAX = @1.2::OperationType:ARGMAX,
+
+    /**
+     * Returns the index of the smallest element along an axis.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor specifying the input. Must be non-empty.
+     * * 1: An {@link OperandType::INT32} scalar specifying the axis to
+     *      reduce across. Negative index is used to specify axis from the
+     *      end (e.g. -1 for the last axis). Must be in the range [-n, n).
+     *
+     * Outputs:
+     * * 0: An (n - 1)-D {@link OperandType::TENSOR_INT32} tensor.
+     */
+    ARGMIN = @1.2::OperationType:ARGMIN,  // See ARGMAX for naming discussion.
+
+    /**
+     * Transform axis-aligned bounding box proposals using bounding box deltas.
+     *
+     * Given the positions of bounding box proposals and the corresponding
+     * bounding box deltas for each class, return the refined bounding box
+     * regions. The resulting bounding boxes are cliped against the edges of
+     * the image.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT16_ASYMM}
+     *
+     * Inputs:
+     * * 0: A 2-D Tensor of shape [num_rois, 4], specifying the locations of the
+     *      bounding box proposals, each line with format [x1, y1, x2, y2].
+     *      For tensor of type {@link OperandType::TENSOR_QUANT16_ASYMM},
+     *      the zeroPoint must be 0 and the scale must be 0.125. Zero num_rois
+     *      is supported for this tensor.
+     * * 1: A 2-D Tensor of shape [num_rois, num_classes * 4], specifying the
+     *      bounding box delta for each region of interest and each class. The
+     *      bounding box deltas are organized in the following order
+     *      [dx, dy, dw, dh], where dx and dy is the relative correction factor
+     *      for the center position of the bounding box with respect to the width
+     *      and height, dw and dh is the log-scale relative correction factor
+     *      for the width and height. For input0 of type
+     *      {@link OperandType::TENSOR_QUANT16_ASYMM}, this tensor should be
+     *      of {@link OperandType::TENSOR_QUANT8_ASYMM}. Zero num_rois is
+     *      supported for this tensor.
+     * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_rois], specifying the batch index of each box. Boxes with
+     *      the same batch index are grouped together. Zero num_rois is
+     *      supported for this tensor.
+     * * 3: A 2-D Tensor of shape [batches, 2], specifying the information of
+     *      each image in the batch, each line with format
+     *      [image_height, image_width].
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0, with shape
+     *      [num_rois, num_classes * 4], specifying the coordinates of each
+     *      output bounding box for each class, with format [x1, y1, x2, y2].
+     *      For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the
+     *      scale must be 0.125 and the zero point must be 0.
+     */
+    AXIS_ALIGNED_BBOX_TRANSFORM = @1.2::OperationType:AXIS_ALIGNED_BBOX_TRANSFORM,
+
+    /**
+     * Performs a forward LSTM on the input followed by a backward LSTM.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: 3, either time-major or batch-major.
+     *
+     * All input and output tensors must be of the same type.
+     *
+     *
+     * Inputs:
+     * * 0: The input.
+     *      A 3-D tensor of shape:
+     *        If time-major: [max_time, batch_size, input_size]
+     *        If batch-major: [batch_size, max_time, input_size]
+     *      where "max_time" is the number of timesteps (sequence length),
+     *      "batch_size" corresponds to the batching dimension, and
+     *      "input_size" is the size of the input.
+     * * 1: The forward input-to-input weights. Optional.
+     *      A 2-D tensor of shape [fw_num_units, input_size], where “fw_num_units”
+     *      corresponds to the number of forward cell units.
+     * * 2: The forward input-to-forget weights.
+     *      A 2-D tensor of shape [fw_num_units, input_size].
+     * * 3: The forward input-to-cell weights.
+     *      A 2-D tensor of shape [fw_num_units, input_size].
+     * * 4: The forward input-to-output weights.
+     *      A 2-D tensor of shape [fw_num_units, input_size].
+     * * 5: The forward recurrent-to-input weights. Optional.
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size], where “fw_output_size”
+     *      corresponds to either the number of cell units (i.e., fw_num_units),
+     *      or the second dimension of the “fw_projection_weights”, if defined.
+     * * 6: The forward recurrent-to-forget weights.
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size].
+     * * 7: The forward recurrent-to-cell weights.
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size].
+     * * 8: The forward recurrent-to-output weights.
+     *      A 2-D tensor of shape [fw_num_units, fw_output_size].
+     * * 9: The forward cell-to-input weights. Optional.
+     *      A 1-D tensor of shape [fw_num_units].
+     * * 10: The forward cell-to-forget weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 11: The forward cell-to-output weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 12: The forward input gate bias. Optional.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 13: The forward forget gate bias.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 14: The forward cell gate bias.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 15: The forward output gate bias.
+     *       A 1-D tensor of shape [fw_num_units].
+     * * 16: The forward projection weights. Optional.
+     *       A 2-D tensor of shape [fw_output_size, fw_num_units].
+     * * 17: The forward projection bias. Optional.
+     *       A 1-D tensor of shape [fw_output_size].
+     * * 18: The backward input-to-input weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, input_size], where “bw_num_units”
+     *       corresponds to the number of backward cell units.
+     * * 19: The backward input-to-forget weights.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 20: The backward input-to-cell weights.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 21: The backward input-to-output weights.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 22: The backward recurrent-to-input weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size], where “bw_output_size”
+     *       corresponds to either the number of cell units (i.e., “bw_num_units”),
+     *       or the second dimension of the “bw_projection_weights”, if defined.
+     * * 23: The backward recurrent-to-forget weights.
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size].
+     * * 24: The backward recurrent-to-cell weights.
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size].
+     * * 25: The backward recurrent-to-output weights.
+     *       A 2-D tensor of shape [bw_num_units, bw_output_size].
+     * * 26: The backward cell-to-input weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 27: The backward cell-to-forget weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 28: The backward cell-to-output weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 29: The backward input gate bias. Optional.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 30: The backward forget gate bias.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 31: The backward cell gate bias.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 32: The backward output gate bias.
+     *       A 1-D tensor of shape [bw_num_units].
+     * * 33: The backward projection weights. Optional.
+     *       A 2-D tensor of shape [bw_output_size, bw_num_units].
+     * * 34: The backward projection bias. Optional.
+     *       A 1-D tensor of shape [bw_output_size].
+     * * 35: The forward input activation state.
+     *       A 2-D tensor of shape [batch_size, bw_output_size].
+     * * 36: The forward input cell state.
+     *       A 2-D tensor of shape [batch_size, bw_num_units].
+     * * 37: The backward input activation state.
+     *       A 2-D tensor of shape [batch_size, bw_output_size].
+     * * 38: The backward input cell state.
+     *       A 2-D tensor of shape [batch_size, bw_num_units].
+     * * 39: The auxiliary input. Optional.
+     *       A 3-D tensor of shape [max_time, batch_size, input_size], where “batch_size”
+     *       corresponds to the batching dimension, and “input_size” is the size
+     *       of the input.
+     * * 40: The forward auxiliary input-to-input weights. Optional.
+     *       A 2-D tensor of shape [fw_num_units, input_size].
+     * * 41: The forward auxiliary input-to-forget weights. Optional.
+     *       A 2-D tensor of shape [fw_num_units, input_size].
+     * * 42: The forward auxiliary input-to-cell weights. Optional.
+     *       A 2-D tensor of shape [fw_num_units, input_size].
+     * * 43: The forward auxiliary input-to-output weights. Optional.
+     *       A 2-D tensor of shape [fw_num_units, input_size].
+     * * 44: The backward auxiliary input-to-input weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 45: The backward auxiliary input-to-forget weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 46: The backward auxiliary input-to-cell weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 47: The backward auxiliary input-to-output weights. Optional.
+     *       A 2-D tensor of shape [bw_num_units, input_size].
+     * * 48: The activation function.
+     *       A value indicating the activation function:
+     *       <ul>
+     *       <li>0: None;
+     *       <li>1: Relu;
+     *       <li>3: Relu6;
+     *       <li>4: Tanh;
+     *       <li>6: Sigmoid.
+     *       </ul>
+     * * 49: The clipping threshold for the cell state, such
+     *       that values are bound within [-cell_clip, cell_clip]. If set to 0.0
+     *       then clipping is disabled.
+     *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
+     *       this scalar must be of the type {@link OperandType::FLOAT32},
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
+     * * 50: The clipping threshold for the output from the
+     *       projection layer, such that values are bound within
+     *       [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
+     *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
+     *       this scalar must be of the type {@link OperandType::FLOAT32},
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
+     * * 51: merge_outputs
+     *       An {@link OperandType::BOOL} scalar specifying if the outputs
+     *       from forward and backward cells should be merged.
+     * * 52: time_major
+     *       An {@link OperandType::BOOL} scalar specifying the shape format
+     *       of input and output tensors.
+     * * 53: The forward input layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at input gate.
+     * * 54: The forward forget layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at forget gate.
+     * * 55: The forward cell layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at cell gate.
+     * * 56: The forward output layer normalization weights. Optional.
+     *       A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+     *       to activation at output gate.
+     * * 57: The backward input layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at input gate.
+     * * 58: The backward forget layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at forget gate.
+     * * 59: The backward cell layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at cell gate.
+     * * 60: The backward output layer normalization weights. Optional.
+     *       A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+     *       to activation at output gate.
+     *
+     * Outputs:
+     * * 0: The forward output.
+     *      A 3-D tensor of shape:
+     *        If time-major and not merge_outputs:
+     *          [max_time, batch_size, fw_output_size]
+     *        If time-major and merge_outputs:
+     *          [max_time, batch_size, fw_output_size + bw_output_size]
+     *        If batch-major and not merge_outputs:
+     *          [batch_size, max_time, fw_output_size]
+     *        If batch-major and merge_outputs:
+     *          [batch_size, max_time, fw_output_size + bw_output_size]
+     * * 1: The backward output.  Unused if merge_outputs is true.
+     *      A 3-D tensor of shape:
+     *        If time-major: [max_time, batch_size, bw_output_size]
+     *        If batch-major: [batch_size, max_time, bw_output_size]
+     */
+    BIDIRECTIONAL_SEQUENCE_LSTM = @1.2::OperationType:BIDIRECTIONAL_SEQUENCE_LSTM,
+
+    /**
+     * A recurrent neural network layer that applies a basic RNN cell to a
+     * sequence of inputs in forward and backward directions.
+     *
+     * This Op unrolls the input along the sequence dimension, and implements
+     * the following operation for each element in the sequence s =
+     * 1...sequence_length:
+     *   fw_outputs[s] = fw_state = activation(inputs[s] * fw_input_weights’ +
+     *          fw_state * fw_recurrent_weights’ + fw_bias)
+     *
+     * And for each element in sequence t = sequence_length : 1
+     *   bw_outputs[t] = bw_state = activation(inputs[t] * bw_input_weights’ +
+     *          bw_state * bw_recurrent_weights’ + bw_bias)
+     *
+     * Where:
+     * * “{fw,bw}_input_weights” is a weight matrix that multiplies the inputs;
+     * * “{fw,bw}_recurrent_weights” is a weight matrix that multiplies the
+     *    current “state” which itself is the output from the previous time step
+     *    computation;
+     * * “{fw,bw}_bias” is a bias vector (added to each output vector in the
+     *    batch);
+     * * “activation” is the function passed as the “fused_activation_function”
+     *   argument (if not “NONE”).
+     *
+     * The op also supports an auxiliary input. Regular cell feeds one input
+     * into the two RNN cells in the following way:
+     *
+     *       INPUT  (INPUT_REVERSED)
+     *         |         |
+     *    ---------------------
+     *    | FW_RNN     BW_RNN |
+     *    ---------------------
+     *         |         |
+     *      FW_OUT     BW_OUT
+     *
+     * An op with an auxiliary input takes two inputs and feeds them into the
+     * RNN cells in the following way:
+     *
+     *       AUX_INPUT   (AUX_INPUT_REVERSED)
+     *           |             |
+     *     INPUT | (INPUT_R'D.)|
+     *       |   |       |     |
+     *    -----------------------
+     *    |  \  /        \    / |
+     *    | FW_RNN       BW_RNN |
+     *    -----------------------
+     *         |           |
+     *      FW_OUT      BW_OUT
+     *
+     * While stacking this op on top of itself, this allows to connect both
+     * forward and backward outputs from previous cell to the next cell's
+     * inputs.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * The input tensors must all be the same type.
+     *
+     * Inputs:
+     * * 0: input.
+     *      A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+     *      it is set to true, then the input has a shape [maxTime, batchSize,
+     *      inputSize], otherwise the input has a shape [batchSize, maxTime,
+     *      inputSize].
+     * * 1: fwWeights.
+     *      A 2-D tensor of shape [fwNumUnits, inputSize].
+     * * 2: fwRecurrentWeights.
+     *      A 2-D tensor of shape [fwNumUnits, fwNumUnits].
+     * * 3: fwBias.
+     *      A 1-D tensor of shape [fwNumUnits].
+     * * 4: fwHiddenState.
+     *      A 2-D tensor of shape [batchSize, fwNumUnits]. Specifies a hidden
+     *      state input for the first time step of the computation.
+     * * 5: bwWeights.
+     *      A 2-D tensor of shape [bwNumUnits, inputSize].
+     * * 6: bwRecurrentWeights.
+     *      A 2-D tensor of shape [bwNumUnits, bwNumUnits].
+     * * 7: bwBias.
+     *      A 1-D tensor of shape [bwNumUnits].
+     * * 8: bwHiddenState
+     *      A 2-D tensor of shape [batchSize, bwNumUnits]. Specifies a hidden
+     *      state input for the first time step of the computation.
+     * * 9: auxInput.
+     *      A 3-D tensor. The shape is the same as of the input 0.
+     * * 10:fwAuxWeights.
+     *      A 2-D tensor of shape [fwNumUnits, inputSize].
+     * * 11:bwAuxWeights.
+     *      A 2-D tensor of shape [bwNumUnits, inputSize].
+     * * 12:fusedActivationFunction.
+     *      A {@link FusedActivationFunc} value indicating the activation function. If
+     *      “NONE” is specified then it results in a linear activation.
+     * * 13:timeMajor
+     *      An {@link OperandType::BOOL} scalar specifying the shape format
+     *      of input and output tensors.
+     * * 14:mergeOutputs
+     *      An {@link OperandType::BOOL} scalar specifying if the outputs
+     *      from forward and backward cells are separate (if set to false) or
+     *      concatenated (if set to true).
+     * Outputs:
+     * * 0: fwOutput.
+     *      A 3-D tensor. The first two dimensions of the shape are defined by
+     *      the input 6 (timeMajor) and the third dimension is defined by the
+     *      input 14 (mergeOutputs). If timeMajor is set to true, then the first
+     *      two dimensions are [maxTime, batchSize], otherwise they are set to
+     *      [batchSize, maxTime]. If mergeOutputs is set to true, then the third
+     *      dimension is equal to (fwNumUnits + bwNumUnits), otherwise it is set
+     *      to fwNumUnits.
+     * * 1: bwOutput.
+     *      A 3-D tensor. If the input 14 (mergeOutputs) is set to true, then
+     *      this tensor is not produced. The shape is defined by the input 6
+     *      (timeMajor). If it is set to true, then the shape is set to
+     *      [maxTime, batchSize, bwNumUnits], otherwise the shape is set to
+     *      [batchSize, maxTime, bwNumUnits].
+     */
+    BIDIRECTIONAL_SEQUENCE_RNN = @1.2::OperationType:BIDIRECTIONAL_SEQUENCE_RNN,
+
+    /**
+     * Greedily selects a subset of bounding boxes in descending order of score.
+     *
+     * This op applies NMS algorithm to each class. In each loop of execution,
+     * the box with maximum score gets selected and removed from the pending set.
+     * The scores of the rest of boxes are lowered according to the
+     * intersection-over-union (IOU) overlapping with the previously selected
+     * boxes and a specified NMS kernel method. Any boxes with score less
+     * than a threshold are removed from the pending set.
+     *
+     * Three NMS kernels are supported:
+     * * Hard:     score_new = score_old * (1 if IoU < threshold else 0)
+     * * Linear:   score_new = score_old * (1 if IoU < threshold else 1 - IoU)
+     * * Gaussian: score_new = score_old * exp(- IoU^2 / sigma)
+     *
+     * Axis-aligned bounding boxes are represented by its upper-left corner
+     * coordinate (x1,y1) and lower-right corner coordinate (x2,y2). A valid
+     * bounding box should satisfy x1 <= x2 and y1 <= y2.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Inputs:
+     * * 0: A 2-D Tensor of shape [num_rois, num_classes], specifying the score
+     *      of each bounding box proposal. The boxes are grouped by batches in the
+     *      first dimension. Zero num_rois is supported for this tensor.
+     * * 1: A 2-D Tensor specifying the bounding boxes of shape
+     *      [num_rois, num_classes * 4], organized in the order [x1, y1, x2, y2].
+     *      The boxes are grouped by batches in the first dimension. The sequential
+     *      order of the boxes corresponds with input0. For input0 of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of
+     *      {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint of 0 and
+     *      scale of 0.125. Zero num_rois is supported for this tensor.
+     * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_rois], specifying the batch index of each box. Boxes with
+     *      the same batch index are grouped together.
+     * * 3: An {@link OperandType::FLOAT32} scalar, score_threshold. Boxes
+     *      with scores lower than the threshold are filtered before sending
+     *      to the NMS algorithm.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the maximum
+     *      number of selected bounding boxes for each image. Set to a negative
+     *      value for unlimited number of output bounding boxes.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the NMS
+     *      kernel method, options are 0:hard, 1:linear, 2:gaussian.
+     * * 6: An {@link OperandType::FLOAT32} scalar, specifying the IoU
+     *      threshold in hard and linear NMS kernel. This field is ignored if
+     *      gaussian kernel is selected.
+     * * 7: An {@link OperandType::FLOAT32} scalar, specifying the sigma in
+     *      gaussian NMS kernel. This field is ignored if gaussian kernel is
+     *      not selected.
+     * * 8: An {@link OperandType::FLOAT32} scalar, nms_score_threshold.
+     *      Boxes with scores lower than the threshold are dropped during the
+     *      score updating phase in soft NMS.
+     *
+     * Outputs:
+     * * 0: A 1-D Tensor of the same {@link OperandType} as input0, with shape
+     *      [num_output_rois], specifying the score of each output box. The boxes
+     *      are grouped by batches, but the sequential order in each batch is not
+     *      guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the scale and zero point must be the same as input0.
+     * * 1: A 2-D Tensor of the same {@link OperandType} as input1, with shape
+     *      [num_output_rois, 4], specifying the coordinates of each
+     *      output bounding box with the same format as input1. The sequential
+     *      order of the boxes corresponds with output0. For type of
+     *      {@link OperandType::TENSOR_QUANT16_ASYMM}, the scale must be
+     *      0.125 and the zero point must be 0.
+     * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_output_rois], specifying the class of each output box. The
+     *      sequential order of the boxes corresponds with output0.
+     * * 3: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_output_rois], specifying the batch index of each box. Boxes
+     *      with the same batch index are grouped together.
+     */
+    BOX_WITH_NMS_LIMIT = @1.2::OperationType:BOX_WITH_NMS_LIMIT,
+
+    /**
+     * Casts a tensor to a new type.
+     *
+     * This operation ignores the scale and zeroPoint of quanized tensors,
+     * e.g. it treats a {@link OperandType::TENSOR_QUANT8_ASYMM} input
+     * as a tensor of uint8 values.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: A tensor with the same shape as input0.
+     */
+    CAST = @1.2::OperationType:CAST,
+
+    /**
+     * Shuffle the channels of the input tensor.
+     *
+     * Given an input tensor and a integer value of num_groups, CHANNEL_SHUFFLE
+     * divide the channel dimension into num_groups groups, and reorganize the
+     * channels by grouping channels with the same index in each group.
+     *
+     * Along the channel dimension, the output is calculated using this formula:
+     *
+     *     output_channel[k * num_groups + g] = input_channel[g * group_size + k]
+     *
+     * where group_size = num_channels / num_groups
+     *
+     * The number of channels must be divisible by num_groups.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be shuffled.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the number of
+     *      groups.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the dimension
+     *      channel shuffle would be performed on. Negative index is used to
+     *      specify axis from the end (e.g. -1 for the last axis). Must be in
+     *      the range [-n, n).
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} and same shape as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    CHANNEL_SHUFFLE = @1.2::OperationType:CHANNEL_SHUFFLE,
+
+    /**
+     * Apply postprocessing steps to bounding box detections.
+     *
+     * Bounding box detections are generated by applying transformation on a set
+     * of predefined anchors with the bounding box deltas from bounding box
+     * regression. A final step of hard NMS is applied to limit the number of
+     * returned boxes.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Inputs:
+     * * 0: A 3-D Tensor of shape [batches, num_anchors, num_classes], specifying
+     *      the score of each anchor with each class. Class 0 for each
+     *      [batches, num_anchors, 0] is background and will be ignored.
+     * * 1: A 3-D Tensor of shape [batches, num_anchors, length_box_encoding], with
+     *      the first four values in length_box_encoding specifying the bounding
+     *      box deltas. The box deltas are encoded in the order of [dy, dx, dh, dw],
+     *      where dy and dx is the linear-scale relative correction factor for the
+     *      center position of the bounding box with respect to the width and height,
+     *      dh and dw is the log-scale relative correction factor for the width and
+     *      height. All the entries in length_box_encoding beyond the first four
+     *      values are ignored in this operation.
+     * * 2: A 2-D Tensor of shape [num_anchors, 4], specifying the shape of each
+     *      predefined anchor, with format [ctr_y, ctr_x, h, w], where ctr_y and
+     *      ctr_x are the center position of the box, and h and w are the height
+     *      and the width.
+     * * 3: An {@link OperandType::FLOAT32} scalar, specifying the scaling
+     *      factor for dy in bounding box deltas.
+     * * 4: An {@link OperandType::FLOAT32} scalar, specifying the scaling
+     *      factor for dx in bounding box deltas.
+     * * 5: An {@link OperandType::FLOAT32} scalar, specifying the scaling
+     *      factor for dh in bounding box deltas.
+     * * 6: An {@link OperandType::FLOAT32} scalar, specifying the scaling
+     *      factor for dw in bounding box deltas.
+     * * 7: An {@link OperandType::BOOL} scalar, set to true to use regular
+     *      multi-class NMS algorithm that do NMS separately for each class,
+     *      set to false for a faster algorithm that only do one single NMS
+     *      using the highest class score..
+     * * 8: An {@link OperandType::INT32} scalar, max_num_detections, specifying
+     *      the maximum number of boxes for the output. Boxes with the lowest
+     *      scores are discarded to meet the limit.
+     * * 9: An {@link OperandType::INT32} scalar, only used when input7 is
+     *      set to false, specifying the maximum number of classes per detection.
+     * * 10: An {@link OperandType::INT32} scalar, only used when input7 is
+     *       set to true, specifying the maximum number of detections when
+     *       applying NMS algorithm for each single class.
+     * * 11: A scalar, score_threshold. Boxes with scores lower than the
+     *       threshold are filtered before sending to the NMS algorithm. The
+     *       scalar must be of {@link OperandType::FLOAT16} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT16} and of
+     *       {@link OperandType::FLOAT32} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT32}.
+     * * 12: A scalar, specifying the IoU threshold for hard NMS. The scalar
+     *       must be of {@link OperandType::FLOAT16} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT16} and of
+     *       {@link OperandType::FLOAT32} if input0 is of
+     *       {@link OperandType::TENSOR_FLOAT32}.
+     * * 13: An {@link OperandType::BOOL} scalar, set to true to include
+     *       background class in the list of label map for the output, set
+     *       to false to not include the background. When the background
+     *       class is included, it has label 0 and the output classes start
+     *       at 1 in the label map, otherwise, the output classes start at 0.
+     *
+     * Outputs:
+     * * 0: A 2-D tensor of the same {@link OperandType} as input0, with shape
+     *      [batches, max_num_detections], specifying the score of each output
+     *      detections.
+     * * 1: A 3-D tensor of shape [batches, max_num_detections, 4], specifying the
+     *      coordinates of each output bounding box, with format
+     *      [y1, x1, y2, x2].
+     * * 2: A 2-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [batches, max_num_detections], specifying the class label for each
+     *      output detection.
+     * * 3: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape [batches],
+     *      specifying the number of valid output detections for each batch.
+     */
+    DETECTION_POSTPROCESSING = @1.2::OperationType:DETECTION_POSTPROCESSING,
+
+    /**
+     * For input tensors x and y, computes x == y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    EQUAL = @1.2::OperationType:EQUAL,
+
+    /**
+     * Computes exponential of x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    EXP = @1.2::OperationType:EXP,
+
+    /**
+     * Inserts a dimension of 1 into a tensor's shape.
+     *
+     * Given a tensor input, this operation inserts a dimension of 1 at the
+     * given dimension index of input's shape. The dimension index starts at
+     * zero; if you specify a negative dimension index, it is counted backward
+     * from the end.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: An {@link OperandType::INT32} scalar specifying the dimension
+     *      index to expand. Must be in the range [-(n + 1), (n + 1)).
+     *
+     * Outputs:
+     * * 0: An (n + 1)-D tensor with the same {@link OperandType} and data as
+     *      input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    EXPAND_DIMS = @1.2::OperationType:EXPAND_DIMS,
+
+    /**
+     * Gathers values along an axis.
+     *
+     * Produces an output tensor with shape
+     *     input0.dimension[:axis] + indices.dimension + input0.dimension[axis + 1:]
+     * where:
+     *     # Vector indices (output is rank(input0)).
+     *     output[a_0, ..., a_n, i, b_0, ..., b_n] =
+     *       input0[a_0, ..., a_n, indices[i], b_0, ..., b_n]
+     *
+     *     # Higher rank indices (output is rank(input0) + rank(indices) - 1).
+     *     output[a_0, ..., a_n, i, ..., j, b_0, ... b_n] =
+     *       input0[a_0, ..., a_n, indices[i, ..., j], b_0, ..., b_n]
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor from which to gather values.
+     * * 1: An {@link OperandType::INT32} scalar specifying the axis.
+     *      Negative index is used to specify axis from the end
+     *      (e.g. -1 for the last axis). Must be in the range [-n, n).
+     * * 2: A k-D tensor {@link OperandType::TENSOR_INT32} of indices.
+     *      The values must be in the bounds of the corresponding dimensions
+     *      of input0.
+     *
+     * Outputs:
+     * * 0: An (n + k - 1)-D tensor with the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    GATHER = @1.2::OperationType:GATHER,
+
+    /**
+     * Generate aixs-aligned bounding box proposals.
+     *
+     * Bounding box proposals are generated by applying transformation on a set
+     * of predefined anchors with the bounding box deltas from bounding box
+     * regression. A final step of hard NMS is applied to limit the number of
+     * returned boxes.
+     *
+     * Axis-aligned bounding boxes are represented by its upper-left corner
+     * coordinate (x1,y1) and lower-right corner coordinate (x2,y2). A valid
+     * bounding box should satisfy x1 <= x2 and y1 <= y2.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Inputs:
+     * * 0: A 4-D Tensor specifying the score of each anchor at each
+     *      location. With "NHWC" data layout, the tensor shape is
+     *      [batches, height, width, num_anchors]. With "NCHW" data layout,
+     *      the tensor shape is [batches, num_anchors, height, width].
+     * * 1: A 4-D Tensor specifying the bounding box deltas. With "NHWC" data
+     *      layout, the tensor shape is [batches, height, width, num_anchors * 4].
+     *      With "NCHW" data layout, the tensor shape is
+     *      [batches, num_anchors * 4, height, width]. The box deltas are encoded
+     *      in the order of [dx, dy, dw, dh], where dx and dy is the linear-scale
+     *      relative correction factor for the center position of the bounding box
+     *      with respect to the width and height, dw and dh is the log-scale
+     *      relative correction factor for the width and height. The last
+     *      dimensions is the channel dimension.
+     * * 2: A 2-D Tensor of shape [num_anchors, 4], specifying the shape of each
+     *      predefined anchor, with format [x1, y1, x2, y2]. For input0 of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of
+     *      {@link OperandType::TENSOR_QUANT16_SYMM}, with scale of 0.125.
+     * * 3: A 2-D Tensor of shape [batches, 2], specifying the size of
+     *      each image in the batch, with format [image_height, image_width].
+     *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM}, this
+     *      tensor should be of {@link OperandType::TENSOR_QUANT16_SYMM}, with
+     *      scale of 0.125.
+     * * 4: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the height of original image to the height of feature map.
+     * * 5: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the width of original image to the width of feature map.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the maximum
+     *      number of boxes before going into the hard NMS algorithm. Boxes
+     *      with the lowest scores are discarded to meet the limit. Set to
+     *      a non-positive value for unlimited number.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the maximum
+     *      number of boxes returning from the hard NMS algorithm. Boxes
+     *      with the lowest scores are discarded to meet the limit. Set to
+     *      a non-positive value for unlimited number.
+     * * 8: An {@link OperandType::FLOAT32} scalar, specifying the IoU
+     *      threshold for hard NMS.
+     * * 9: An {@link OperandType::FLOAT32} scalar, min_size. Boxes with
+     *      height or width lower than the absolute threshold are filtered out.
+     * * 10: An {@link OperandType::BOOL} scalar, set to true to specify
+     *       NCHW data layout for input0 and input1. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0, of shape
+     *      [num_output_rois], specifying the score of each output box.
+     *      The boxes are grouped by batches, but the sequential order in
+     *      each batch is not guaranteed. For type of
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the scale and zero
+     *      point must be the same as input0.
+     * * 1: A tensor of the same {@link OperandType} as input3, of shape
+     *      [num_output_rois, 4], specifying the coordinates of each output
+     *      bounding box for each class, with format [x1, y1, x2, y2].
+     *      The sequential order of the boxes corresponds with output0.
+     *      For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the
+     *      scale must be 0.125 and the zero point must be 0.
+     * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_output_rois], specifying the batch index of each box. Boxes
+     *      with the same batch index are grouped together.
+     */
+    GENERATE_PROPOSALS = @1.2::OperationType:GENERATE_PROPOSALS,
+
+    /**
+     * For input tensors x and y, computes x > y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    GREATER = @1.2::OperationType:GREATER,
+    /**
+     * For input tensors x and y, computes x >= y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    GREATER_EQUAL = @1.2::OperationType:GREATER_EQUAL,
+
+    /**
+     * Performs a grouped 2-D convolution operation.
+     *
+     * Given an input tensor of shape [batches, height, width, depth_in] and a
+     * filter tensor of shape [depth_out, filter_height, filter_width, depth_group]
+     * containing depth_out convolutional filters of depth depth_group, GROUPED_CONV
+     * applies a group of different filters to each input channel group, then
+     * concatenates the results together.
+     *
+     * Specifically, the input channels are divided into num_groups groups, each with
+     * depth depth_group, i.e. depth_in = num_groups * depth_group. The convolutional
+     * filters are also divided into num_groups groups, i.e. depth_out is divisible
+     * by num_groups. GROUPED_CONV applies each group of filters to the corresponding
+     * input channel group, and the result are concatenated together.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, i, j, g * channel_multiplier + q] =
+     *         sum_{di, dj, dk} (
+     *             input[b, strides[1] * i + di, strides[2] * j + dj,
+     *                   g * depth_group + dk] *
+     *             filter[g * channel_multiplier + q, di, dj, dk]
+     *         ) + bias[channel]
+     *
+     * where channel_multiplier = depth_out / num_groups
+     *
+     * Supported tensor {@link OperandType} configurations:
+     * * 16 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
+     *
+     * * 32 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias.
+     *
+     * * Quantized:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * * Quantized with symmetric per channel quantization for the filter:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output.
+     * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+     * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+     * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input, where depth_in = num_groups * depth_group.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_group], specifying
+     *      the filter, where depth_out must be divisible by num_groups.  For
+     *      tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (channelDim at
+     *      {@link SymmPerChannelQuantParams}) must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale. For filter tensor
+     *      of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
+     *      should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
+     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 9: An {@link OperandType::INT32} scalar, specifying the number of
+            groups.
+     * * 10: An {@link OperandType::INT32} scalar, and has to be one of the
+     *       {@link FusedActivationFunc} values. Specifies the activation to
+     *       invoke on the result.
+     * * 11: An {@link OperandType::BOOL} scalar, set to true to specify
+     *       NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input, where depth_in = num_groups * depth_group.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_group], specifying
+     *      the filter, where depth_out must be divisible by num_groups.  For
+     *      tensor of type {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+     *      the channel dimension (SymmPerChannelQuantParams::channelDim)
+     *      must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
+     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
+     *      of 0 and bias_scale == input_scale * filter_scale. For filter tensor
+     *      of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
+     *      should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
+     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal to
+     *      bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the number of
+     *      groups.
+     * * 7: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 8: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth_out].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    GROUPED_CONV_2D = @1.2::OperationType:GROUPED_CONV_2D,
+
+    /**
+     * Localize the maximum keypoints from heatmaps.
+     *
+     * This operation approximates the accurate maximum keypoint scores and
+     * indices after bicubic upscaling by using Taylor expansion up to the
+     * quadratic term.
+     *
+     * The bounding box is represented by its upper-left corner coordinate
+     * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image.
+     * A valid bounding box should satisfy x1 <= x2 and y1 <= y2.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Inputs:
+     * * 0: A 4-D Tensor of shape
+     *      [num_boxes, heatmap_size, heatmap_size, num_keypoints],
+     *      specifying the heatmaps, the height and width of heatmaps should
+     *      be the same, and must be greater than or equal to 2.
+     * * 1: A 2-D Tensor of shape [num_boxes, 4], specifying the bounding boxes,
+     *      each with format [x1, y1, x2, y2]. For input0 of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should
+     *      be of {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint
+     *      of 0 and scale of 0.125.
+     * * 2: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0, with shape
+     *      [num_boxes, num_keypoints], specifying score of the keypoints.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from input0 scale and zeroPoint.
+     * * 1: A tensor of the same {@link OperandType} as input1, with shape
+     *      [num_boxes, num_keypoints, 2], specifying the location of
+     *      the keypoints, the second dimension is organized as
+     *      [keypoint_x, keypoint_y].
+     *      For type of {@link OperandType::TENSOR_QUANT16_ASYMM}, the
+     *      scale must be 0.125 and the zero point must be 0.
+     */
+    HEATMAP_MAX_KEYPOINT = @1.2::OperationType:HEATMAP_MAX_KEYPOINT,
+
+    /**
+     * Applies instance normalization to the input tensor.
+     *
+     * The values in the output tensor are computed as:
+     *
+     *     output[b, h, w, c] =
+     *         (input[b, h, w, c] - mean[b, c]) * gamma /
+     *         sqrt(var[b, c] + epsilon) + beta
+     *
+     * Where the mean and variance are computed across the spatial dimensions:
+     *
+     *     mean[b, c] =
+     *         sum_{h, w}(input[b, h, w, c]) / sum(1)
+     *
+     *     var[b, c] =
+     *         sum_{h, w}(pow(input[b, h, w, c] - mean[b, c], 2)) / sum(1)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be normalized.
+     * * 1: A scalar, specifying gamma, the scale applied to the normalized
+     *      tensor. The scalar must be of {@link OperandType::FLOAT16} if
+     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} if input0 is of
+     *      {@link OperandType::TENSOR_FLOAT32}.
+     * * 2: A scalar, specifying beta, the offset applied to the normalized
+     *      tensor. The scalar must be of {@link OperandType::FLOAT16} if
+     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} if input0 is of
+     *      {@link OperandType::TENSOR_FLOAT32}.
+     * * 3: A scalar, specifying epsilon, the small value added to variance to
+     *      avoid dividing by zero. The scalar must be of {@link OperandType::FLOAT16} if
+     *      input0 is of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} if input0 is of
+     *      {@link OperandType::TENSOR_FLOAT32}.
+     * * 4: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} and same shape as input0.
+     */
+    INSTANCE_NORMALIZATION = @1.2::OperationType:INSTANCE_NORMALIZATION,
+
+    /**
+     * For input tensors x and y, computes x < y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    LESS = @1.2::OperationType:LESS,
+
+    /**
+     * For input tensors x and y, computes x <= y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    LESS_EQUAL = @1.2::OperationType:LESS_EQUAL,
+
+    /**
+     * Computes natural logarithm of x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    LOG = @1.2::OperationType:LOG,
+
+    /**
+     * Returns the truth value of x AND y element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     * * 1: A tensor of {@link OperandType::TENSOR_BOOL8} and dimensions
+     *      compatible with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    LOGICAL_AND = @1.2::OperationType:LOGICAL_AND,
+
+    /**
+     * Computes the truth value of NOT x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    LOGICAL_NOT = @1.2::OperationType:LOGICAL_NOT,
+
+    /**
+     * Returns the truth value of x OR y element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     * * 1: A tensor of {@link OperandType::TENSOR_BOOL8} and dimensions
+     *      compatible with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    LOGICAL_OR = @1.2::OperationType:LOGICAL_OR,
+
+    /**
+     * Computes the log softmax activations given logits.
+     *
+     * The output is calculated using this formula:
+     *
+     *     output = logits * beta - log(reduce_sum(exp(logits * beta), axis))
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor specifying the input logits.
+     * * 1: A scalar, specifying the positive scaling factor for the exponent,
+     *      beta.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the beta
+     *      value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the beta
+     *      value must be of {@link OperandType::FLOAT32}.
+     * * 2: An {@link OperandType::INT32} scalar specifying the axis to
+     *      reduce across. Negative index is used to specify axis from the
+     *      end (e.g. -1 for the last axis). Must be in the range [-n, n).
+     *
+     * Outputs:
+     * * 0: The output tensor of the same {@link OperandType} and shape as
+     *      input0.
+     */
+    LOG_SOFTMAX = @1.2::OperationType:LOG_SOFTMAX,
+
+    /**
+     * Returns the element-wise maximum of two tensors.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and compatible dimensions
+     *      with input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    MAXIMUM = @1.2::OperationType:MAXIMUM,
+
+    /**
+     * Returns the element-wise minimum of two tensors.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and compatible dimensions
+     *      with input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    MINIMUM = @1.2::OperationType:MINIMUM,
+
+    /**
+     * Computes numerical negative value element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    NEG = @1.2::OperationType:NEG,
+
+    /**
+     * For input tensors x and y, computes x != y elementwise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * This operation supports broadcasting.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     * * 1: A tensor of the same {@link OperandType} and dimensions compatible
+     *      with input0.
+     *
+     * Outputs:
+     * * 0: A tensor of {@link OperandType::TENSOR_BOOL8}.
+     */
+    NOT_EQUAL = @1.2::OperationType:NOT_EQUAL,
+
+    /**
+     * Pads a tensor with the given constant value according to the specified
+     * paddings.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor, specifying the tensor to be padded.
+     * * 1: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings
+     *      for each spatial dimension of the input tensor. The shape of the
+     *      tensor must be {rank(input0), 2}.
+     *      padding[i, 0] specifies the number of elements to be padded in the
+     *      front of dimension i.
+     *      padding[i, 1] specifies the number of elements to be padded after
+     *      the end of dimension i.
+     * * 2: An scalar specifying the value to use for padding input0.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT16}, the
+     *      pad value must be of {@link OperandType::FLOAT16}.
+     *      For input tensor of {@link OperandType::TENSOR_FLOAT32}, the
+     *      pad value must be of {@link OperandType::FLOAT32}.
+     *      For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the pad value must be of {@link OperandType::INT32}. The
+     *      scale and zeroPoint are assumed to be the same as in input0.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0. The
+     *      output tensor has the same rank as input0, and each
+     *      dimension of the output tensor has the same size as the
+     *      corresponding dimension of the input tensor plus the size
+     *      of the padding:
+     *          output0.dimension[i] =
+     *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    PAD_V2 = @1.2::OperationType:PAD_V2,
+
+    /**
+     * Computes the power of one value to another.
+     *
+     * Given a tensor base and a tensor exponent, this operation computes
+     * base^exponent elementwise.
+     *
+     * This operations supports broadcasting. The size of the output is the
+     * maximum size along each dimension of the input operands. It starts with
+     * the trailing dimensions, and works its way forward.
+     *
+     * For example:
+     *     base.dimension     =    {4, 1, 2}
+     *     exponent.dimension = {5, 4, 3, 1}
+     *     output.dimension   = {5, 4, 3, 2}
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A tensor specifying the base.
+     * * 1: A tensor specifying the exponent.
+     *
+     * Outputs:
+     * * 0: An output tensor.
+     */
+    POW = @1.2::OperationType:POW,
+
+    /**
+     * Parametric Rectified Linear Unit.
+     *
+     * It follows: f(x) = alpha * x for x < 0, f(x) = x for x >= 0, where alpha
+     * is a learned array with the same {@link OperandType} and compatible
+     * dimensions as input x.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the output is the maximum size along each dimension of the
+     * input operands. It starts with the trailing dimensions, and works its way
+     * forward.
+     *
+     * Example:
+     *     input.dimension  =    {4, 1, 2}
+     *     alpha.dimension  = {5, 4, 3, 1}
+     *     output.dimension = {5, 4, 3, 2}
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A tensor, specifying the input.
+     * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+     *      as input0, specifying the alpha.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be diffent from the input0 scale and zeroPoint.
+     */
+    PRELU = @1.2::OperationType:PRELU,
+
+    /**
+     * Quantizes the input tensor.
+     *
+     * The formula is:
+     *
+     *     output = max(0, min(255, round(input / scale) + zeroPoint)
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A tensor, may be zero-sized.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0, but with
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}.
+     */
+    QUANTIZE = @1.2::OperationType:QUANTIZE,
+
+    /**
+     * A version of quantized LSTM, using 16 bit quantization for internal
+     * state.
+     *
+     * There is no projection layer, so cell state size is equal to the output
+     * size.
+     *
+     * Inputs:
+     * * 0: A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [numBatches, inputSize] specifying the input to the LSTM
+     *      cell. Tensor is quantized with a fixed quantization range of
+     *      [-1, 127/128] (scale = 1/128, zeroPoint = 128).
+     * * 1: The input-to-input weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, inputSize] specifying input-to-input part of
+     *      weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 2: The input-to-forget weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, inputSize] specifying input-to-forget part of
+     *      weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 3: The input-to-cell weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, inputSize] specifying input-to-cell part of
+     *      weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 4: The input-to-output weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, inputSize] specifying input-to-output part of
+     *      weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 5: The recurrent-to-input weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, outputSize] specifying recurrent-to-input part
+     *      of weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 6: The recurrent-to-forget weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, outputSize] specifying recurrent-to-forget
+     *      part of weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 7: The recurrent-to-cell weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, outputSize] specifying recurrent-to-cell part
+     *      of weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 8: The recurrent-to-output weights.
+     *      A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [outputSize, outputSize] specifying recurrent-to-output
+     *      part of weights for fully-connected layer inside the LSTM cell.
+     *      Quantization zero point and scale must be the same across all the
+     *      weights.
+     * * 9: The input gate bias.
+     *      A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape
+     *      [outputSize] specifying the bias for the fully-connected layer
+     *      inside the LSTM cell. Bias is quantized with scale being a product
+     *      of input and weights scales and zeroPoint equal to 0.
+     * * 10:The forget gate bias.
+     *      A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape
+     *      [outputSize] specifying the bias for the fully-connected layer
+     *      inside the LSTM cell. Bias is quantized with scale being a product
+     *      of input and weights scales and zeroPoint equal to 0.
+     * * 11:The cell bias.
+     *      A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape
+     *      [outputSize] specifying the bias for the fully-connected layer
+     *      inside the LSTM cell. Bias is quantized with scale being a product
+     *      of input and weights scales and zeroPoint equal to 0.
+     * * 12:The output gate bias.
+     *      A 1-D tensor of type {@link OperandType::TENSOR_INT32} and shape
+     *      [outputSize] specifying the bias for the fully-connected layer
+     *      inside the LSTM cell. Bias is quantized with scale being a product
+     *      of input and weights scales and zeroPoint equal to 0.
+     * * 13: A 2-D tensor of type {@link OperandType::TENSOR_QUANT16_SYMM}
+     *       and shape [numBatches, outputSize] specifying the cell state from the
+     *       previous time step of the LSTM cell. It is quantized using a
+     *       quantization range of [-2^4, 2^4 * 32767/32768] (scale = 2^4 /
+     *       32768, zeroPoint = 0).
+     * * 14: A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *       and shape [numBathes, outputSize] specifying the output of the LSTM
+     *       cell from previous time-step. Tensor is quantized with a fixed
+     *       quantization range of [-1, 127/128] (scale = 1/128, zeroPoint =
+     *       128).
+     *
+     *
+     * Outputs:
+     * * 0: A 2-D tensor of type {@link OperandType::TENSOR_QUANT16_SYMM}
+     *      and shape [numBatches, outputSize] which contains a cell state from
+     *      the current time step. Tensor is quantized using a quantization
+     *      range of [-2^4, 2^4 * 32767/32768] (scale = 2^4 / 32768, zeroPoint =
+     *      0).
+     * * 1: A 2-D tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and shape [numBathes, outputSize] which contains the output value.
+     *      Tensor is quantized with a fixed quantization range of [-1, 127/128]
+     *      (scale = 1/128, zeroPoint = 128).
+     */
+    QUANTIZED_16BIT_LSTM = @1.2::OperationType:QUANTIZED_16BIT_LSTM,
+
+    /**
+     * Draws samples from a multinomial distribution.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Inputs:
+     * * 0: A 2-D tensor with shape [batches, classes], specifying the
+     *      unnormalized log-probabilities for all classes.
+     * * 1: A scalar {@link OperandType::INT32}, specifying the number of
+     *      independent samples to draw for each row slice.
+     * * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor with shape [2],
+     *      specifying seeds used to initialize the random distribution.
+     * Outputs:
+     * * 0: A 2-D {@link OperandType::TENSOR_INT32} tensor with shape
+     *      [batches, samples], containing the drawn samples.
+     */
+    RANDOM_MULTINOMIAL = @1.2::OperationType:RANDOM_MULTINOMIAL,
+
+    /**
+     * Reduces a tensor by computing the "logical and" of elements along given
+     * dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     */
+    REDUCE_ALL = @1.2::OperationType:REDUCE_ALL,
+
+    /**
+     * Reduces a tensor by computing the "logical or" of elements along given
+     * dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_BOOL8}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     */
+    REDUCE_ANY = @1.2::OperationType:REDUCE_ANY,
+
+    /**
+     * Reduces a tensor by computing the maximum of elements along given
+     * dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    REDUCE_MAX = @1.2::OperationType:REDUCE_MAX,
+
+    /**
+     * Reduces a tensor by computing the minimum of elements along given
+     * dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    REDUCE_MIN = @1.2::OperationType:REDUCE_MIN,
+
+    /**
+     * Reduces a tensor by multiplying elements along given dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     */
+    REDUCE_PROD = @1.2::OperationType:REDUCE_PROD,
+
+    /**
+     * Reduces a tensor by summing elements along given dimensions.
+     *
+     * If keep_dims is true, the reduced dimensions are
+     * retained with length 1. Otherwise, the rank of the tensor is reduced by
+     * 1 for each entry in dimensions.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * * 0: An n-D tensor.
+     * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+     *      to reduce. Dimension values must be in the range [-n, n).
+     * * 2: An {@link OperandType::BOOL} scalar, keep_dims. If true,
+     *      retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0.
+     */
+    REDUCE_SUM = @1.2::OperationType:REDUCE_SUM,
+
+    /**
+     * Select and scale the feature map of each region of interest to a unified
+     * output size by average pooling sampling points from bilinear interpolation.
+     *
+     * The region of interest is represented by its upper-left corner coordinate
+     * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image.
+     * A spatial scaling factor is applied to map into feature map coordinate.
+     * A valid region of interest should satisfy x1 <= x2 and y1 <= y2.
+     *
+     * No rounding is applied in this operation. The sampling points are unified
+     * distributed in the pooling bin and their values are calculated by bilinear
+     * interpolation.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Inputs:
+     * * 0: A 4-D tensor, specifying the feature map.
+     * * 1: A 2-D Tensor of shape [num_rois, 4], specifying the locations of
+     *      the regions of interest, each line with format [x1, y1, x2, y2].
+     *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM},
+     *      with zeroPoint of 0 and scale of 0.125. Zero num_rois is
+     *      supported for this tensor.
+     * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_rois], specifying the batch index of each box. Boxes with
+     *      the same batch index are grouped together. Zero num_rois is
+     *      supported for this tensor.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the output
+     *      width of the output tensor.
+     * * 5: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the height of original image to the height of feature map.
+     * * 6: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the width of original image to the width of feature map.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the number of
+     *      sampling points in height dimension used to compute the output.
+     *      Set to 0 for adaptive value of ceil(roi_height/out_height).
+     * * 8: An {@link OperandType::INT32} scalar, specifying the number of
+     *      sampling points in width dimension used to compute the output.
+     *      Set to 0 for adaptive value of ceil(roi_width/out_width).
+     * * 9: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0. The output
+     *      shape is [num_rois, out_height, out_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from the input0 scale and zeroPoint.
+     */
+    ROI_ALIGN = @1.2::OperationType:ROI_ALIGN,
+
+    /**
+     * Select and scale the feature map of each region of interest to a unified
+     * output size by max-pooling.
+     *
+     * The region of interest is represented by its upper-left corner coordinate
+     * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image.
+     * A spatial scaling factor is applied to map into feature map coordinate.
+     * A valid region of interest should satisfy x1 <= x2 and y1 <= y2.
+     *
+     * Rounding is applied in this operation to ensure integer boundary for
+     * regions of interest and pooling bins.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Inputs:
+     * * 0: A 4-D tensor, specifying the feature map.
+     * * 1: A 2-D Tensor of shape [num_rois, 4], specifying the locations of
+     *      the regions of interest, each line with format [x1, y1, x2, y2].
+     *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM},
+     *      with zeroPoint of 0 and scale of 0.125.
+     * * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
+     *      [num_rois], specifying the batch index of each box. Boxes with
+     *      the same batch index are grouped together.
+     * * 3: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the output
+     *      width of the output tensor.
+     * * 5: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the height of original image to the height of feature map.
+     * * 6: An {@link OperandType::FLOAT32} scalar, specifying the ratio
+     *      from the width of original image to the width of feature map.
+     * * 7: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: A tensor of the same {@link OperandType} as input0. The output
+     *      shape is [num_rois, out_height, out_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    ROI_POOLING = @1.2::OperationType:ROI_POOLING,
+
+    /**
+     * Computes reciprocal of square root of x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    RSQRT = @1.2::OperationType:RSQRT,
+
+    /**
+     * Using a tensor of booleans c and input tensors x and y select values
+     * elementwise from both input tensors:
+     *
+     * O[i] = C[i] ? x[i] : y[i].
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A tensor of type {@link OperandType::TENSOR_BOOL8} acting as a
+     *      mask that chooses, based on the value at each element, whether the
+     *      corresponding element in the output should be taken from input1 (if
+     *      true) or input2 (if false).
+     * * 1: An input tensor of the same shape as input0.
+     * * 2: An input tensor of the same shape and type as input1.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+     *      the scales and zeroPoint can be different from input1 scale and zeroPoint.
+     *
+     * Outputs:
+     * * 0: A tensor of the same type and shape as input1 and input2.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    SELECT = @1.2::OperationType:SELECT,
+
+    /**
+     * Computes sin of x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    SIN = @1.2::OperationType:SIN,
+
+    /**
+     * Extracts a slice of specified size from the input tensor starting at a
+     * specified location.
+     *
+     * The starting location is specified as a 1-D tensor containing offsets
+     * for each dimension. The size is specified as a 1-D tensor containing
+     * either size of a slice along corresponding dimension or -1. In the latter
+     * case, all the remaining elements in dimension are included in the slice.
+     *
+     * A sum of begin offset and a size of a slice must not exceed size of a
+     * corresponding dimension.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor to take slice from, may be zero-sized.
+     * * 1: A 1-D tensor of type {@link OperandType::TENSOR_INT32} specifying
+     *      the beginning indices of the slice in each dimension.
+     * * 2: A 1-D tensor of type {@link OperandType::TENSOR_INT32} specifying
+     *      the size of the slice in each dimension.
+     *
+     * Outputs:
+     * * 0: An n-D tensor of the same type as the input containing the slice.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      its scale and zeroPoint has to be same as the input0 scale and zeroPoint.
+     */
+    SLICE = @1.2::OperationType:SLICE,
+
+    /**
+     * Splits a tensor along a given axis into num_splits subtensors.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: An n-D tensor to split.
+     * * 1: An {@link OperandType::INT32} scalar specifying the axis along
+     *      which to split.
+     * * 2: An {@link OperandType::INT32} scalar indicating the number of
+     *      splits along given axis. Must evenly divide axis size.
+     *
+     * Outputs:
+     * * 0 ~ (num_splits - 1): Resulting subtensors.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    SPLIT = @1.2::OperationType:SPLIT,
+
+    /**
+     * Computes square root of x element-wise.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: from 1.
+     *
+     * Inputs:
+     * * 0: A tensor.
+     *
+     * Outputs:
+     * * 0: The output tensor of same shape as input0.
+     */
+    SQRT = @1.2::OperationType:SQRT,
+
+    /**
+     * Constructs a tensor by tiling a given tensor.
+     *
+     * This operation creates a new tensor by replicating `input` `multiples`
+     * times. The output tensor's i-th dimension has `input.dims(i) * multiples[i]`
+     * elements, and the values of `input` are replicated `multiples[i]` times
+     * along the i-th dimension.
+     * For example, tiling `[a b c d]` by `[2]` produces `[a b c d a b c d]`.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: input, an n-D tensor specifying the input.
+     * * 1: multiples, a 1-D tensor of {@link OperandType::TENSOR_INT32}.
+     *      The length of multiples must be n.
+     *
+     * Outputs:
+     * * 0: A tiled tensor of the same {@link OperandType} and rank as `input`.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    TILE = @1.2::OperationType:TILE,
+
+    /**
+     * Finds values and indices of the k largest entries for the last dimension.
+     *
+     * Resulting values in each dimensions are sorted in descending order. If
+     * two values are equal, the one with larger index appears first.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: input, an n-D tensor specifying the input.
+     * * 1: k, an {@link OperandType::INT32} scalar, specifying the number of
+     *      top elements to look for along the last dimension.
+     *
+     * Outputs:
+     * * 0: An n-D tensor of the same type as the input, containing the k
+     *      largest elements along each last dimensional slice.
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     * * 1: An n-D tensor of type {@link OperandType::TENSOR_INT32}
+     *      containing the indices of values within the last dimension of input.
+     */
+    TOPK_V2 = @1.2::OperationType:TOPK_V2,
+
+    /**
+     * Performs the transpose of 2-D convolution operation.
+     *
+     * This operation is sometimes called "deconvolution" after Deconvolutional
+     * Networks, but is actually the transpose (gradient) of
+     * {@link OperandType::CONV_2D} rather than an actual deconvolution.
+     *
+     * The output dimensions are functions of the filter dimensions, stride, and
+     * padding.
+     *
+     * Supported tensor {@link OperandType} configurations:
+     * * 16 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT16} for input, filter, output, and bias.
+     *
+     * * 32 bit floating point:
+     * * * {@link OperandType::TENSOR_FLOAT32} for input, filter, output, and bias.
+     *
+     * * Quantized:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * * Quantized with symmetric per channel quantization for the filter:
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output.
+     * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+     * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+     * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Both explicit padding and implicit padding are supported.
+     *
+     * Inputs (explicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_in], specifying the
+     *      filter. For tensor of type
+     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
+     *      dimension (SymmPerChannelQuantParams::channelDim) must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias should be of the
+     *      same type. For input tensor of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
+     *      of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
+     *      bias_scale == input_scale * filter_scale. For filter tensor of
+     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
+     *      must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
+     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal
+     *      to bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the left, in the ‘width’ dimension.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the right, in the ‘width’ dimension.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the top, in the ‘height’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the padding on
+     *      the bottom, in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 10: An {@link OperandType::BOOL} scalar, set to true to specify
+     *       NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Inputs (implicit padding):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+     *      specifying the input.
+     * * 1: A 4-D tensor, of shape
+     *      [depth_out, filter_height, filter_width, depth_in], specifying the
+     *      filter. For tensor of type
+     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
+     *      dimension (SymmPerChannelQuantParams::channelDim) must be set to 0.
+     * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+     *      tensor of type {@link OperandType::TENSOR_FLOAT32} or
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias should be of the
+     *      same type. For input tensor of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
+     *      of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
+     *      bias_scale == input_scale * filter_scale. For filter tensor of
+     *      {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
+     *      must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
+     *      0 and bias_scale of 0. The actual scale of each value 'i' is equal
+     *      to bias_scale[i] = input_scale * filter_scale[i].
+     * * 3: An {@link OperandType::TENSOR_INT32} tensor, specifying the output
+     *      tensor shape.
+     * * 4: An {@link OperandType::INT32} scalar, specifying the implicit
+     *      padding scheme, has to be one of the
+     *      following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+     * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘width’ dimension.
+     * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+     *      walking through input in the ‘height’ dimension.
+     * * 7: An {@link OperandType::INT32} scalar, and has to be one of the
+     *      {@link FusedActivationFunc} values. Specifies the activation to
+     *      invoke on the result.
+     * * 8: An {@link OperandType::BOOL} scalar, set to true to specify
+     *      NCHW data layout for input0 and output0. Set to false for NHWC.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, out_height, out_width, depth_out].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+     */
+    TRANSPOSE_CONV_2D = @1.2::OperationType:TRANSPOSE_CONV_2D,
+
+    /**
+     * A recurrent neural network specified by an LSTM cell.
+     *
+     * Performs (fully) dynamic unrolling of input.
+     *
+     * This Op unrolls the input along the time dimension, and implements the
+     * following operation for each element in the sequence
+     * s = 1...sequence_length:
+     *   outputs[s] = projection(state = activation(LSTMOp(inputs[s])))
+     *
+     * Where LSTMOp is the LSTM op as in {@link OperandType::LSTM},
+     * the "projection" is an optional projection layer from state and output
+     * and the “activation” is the function passed as the
+     * “fused_activation_function” argument (if not “NONE”).
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * Supported tensor rank: 3, either time-major or batch-major.
+     *
+     * All input and output tensors must be of the same type.
+     *
+     * Inputs:
+     * * 0: The input (\f$x_t\f$).
+     *      A 3-D tensor of shape:
+     *        If time-major: [max_time, batch_size, input_size]
+     *        If batch-major: [batch_size, max_time, input_size]
+     *      where “max_time” is the number of timesteps (sequence length),
+     *      “batch_size” corresponds to the batching dimension, and
+     *      “input_size” is the size of the input.
+     * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional.
+     *      A 2-D tensor of shape [num_units, input_size], where “num_units”
+     *      corresponds to the number of cell units.
+     * * 2: The input-to-forget weights (\f$W_{xf}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 3: The input-to-cell weights (\f$W_{xc}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 4: The input-to-output weights (\f$W_{xo}\f$).
+     *      A 2-D tensor of shape [num_units, input_size].
+     * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional.
+     *      A 2-D tensor of shape [num_units, output_size], where “output_size”
+     *      corresponds to either the number of cell units (i.e., “num_units”),
+     *      or the second dimension of the “projection_weights”, if defined.
+     * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 8: The recurrent-to-output weights (\f$W_{ho}\f$).
+     *      A 2-D tensor of shape [num_units, output_size].
+     * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 12:The input gate bias (\f$b_i\f$). Optional.
+     *      A 1-D tensor of shape [num_units].
+     * * 13:The forget gate bias (\f$b_f\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 14:The cell bias (\f$b_c\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 15:The output gate bias (\f$b_o\f$).
+     *      A 1-D tensor of shape [num_units].
+     * * 16:The projection weights (\f$W_{proj}\f$). Optional.
+     *      A 2-D tensor of shape [output_size, num_units].
+     * * 17:The projection bias (\f$b_{proj}\f$). Optional.
+     *      A 1-D tensor of shape [output_size].
+     * * 18:The output state (in) (\f$h_{t-1}\f$).
+     *      A 2-D tensor of shape [batch_size, output_size].
+     * * 19:The cell state (in) (\f$C_{t-1}\f$).
+     *      A 2-D tensor of shape [batch_size, num_units].
+     * * 20:The activation function (\f$g\f$).
+     *      A value indicating the activation function:
+     *      <ul>
+     *      <li>0: None;
+     *      <li>1: Relu;
+     *      <li>3: Relu6;
+     *      <li>4: Tanh;
+     *      <li>6: Sigmoid.
+     *      </ul>
+     * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such
+     *      that values are bound within [-cell_clip, cell_clip]. If set to 0.0
+     *      then clipping is disabled.
+     * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the
+     *      projection layer, such that values are bound within
+     *      [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
+     * * 23:Time-major if true, batch-major if false.
+     * * 24:The input layer normalization weights. Optional.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at input gate.
+     * * 25:The forget layer normalization weights. Optional.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at forget gate.
+     * * 26:The cell layer normalization weights. Optional.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at cell gate.
+     * * 27:The output layer normalization weights. Optional.
+     *      A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+     *      to activation at output gate.
+     *
+     * Outputs:
+     * * 0: The output (\f$o_t\f$).
+     *      A 3-D tensor of shape:
+     *        If time-major: [max_time, batch_size, output_size]
+     *        If batch-major: [batch_size, max_time, output_size]
+     */
+    UNIDIRECTIONAL_SEQUENCE_LSTM = @1.2::OperationType:UNIDIRECTIONAL_SEQUENCE_LSTM,
+
+    /**
+     * A recurrent neural network layer that applies a basic RNN cell to a
+     * sequence of inputs.
+     *
+     * This layer unrolls the input along the sequence dimension, and implements
+     * the following operation
+     * for each element in the sequence s = 1...sequence_length:
+     *   outputs[s] = state = activation(inputs[s] * input_weights’ + state *
+     *   recurrent_weights’ + bias)
+     *
+     * Where:
+     * * “input_weights” is a weight matrix that multiplies the inputs;
+     * * “recurrent_weights” is a weight matrix that multiplies the current
+     *    “state” which itself is the output from the previous time step
+     *    computation;
+     * * “bias” is a bias vector (added to each output vector in the batch);
+     * * “activation” is the function passed as the “fused_activation_function”
+     *   argument (if not “NONE”).
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     *
+     * The input tensors must all be the same type.
+     *
+     * Inputs:
+     * * 0: input.
+     *      A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+     *      it is set to 1, then the input has a shape [maxTime, batchSize,
+     *      inputSize], otherwise the input has a shape [batchSize, maxTime,
+     *      inputSize].
+     * * 1: weights.
+     *      A 2-D tensor of shape [numUnits, inputSize].
+     * * 2: recurrent_weights.
+     *      A 2-D tensor of shape [numUnits, numUnits].
+     * * 3: bias.
+     *      A 1-D tensor of shape [numUnits].
+     * * 4: hidden state
+     *      A 2-D tensor of shape [batchSize, numUnits]. Specifies a hidden
+     *      state input for the first time step of the computation.
+     * * 5: fusedActivationFunction.
+     *      A {@link FusedActivationFunc} value indicating the activation function. If
+     *      “NONE” is specified then it results in a linear activation.
+     * * 6: timeMajor
+     *      An {@link OperandType::INT32} scalar specifying the shape format
+     *      of input and output tensors. Must be set to either 0 or 1.
+     * Outputs:
+     * * 0: output.
+     *      A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+     *      it is set to 1, then the output has a shape [maxTime, batchSize,
+     *      numUnits], otherwise the output has a shape [batchSize, maxTime,
+     *      numUnits].
+     */
+    UNIDIRECTIONAL_SEQUENCE_RNN = @1.2::OperationType:UNIDIRECTIONAL_SEQUENCE_RNN,
+
+    /**
+     * Resizes images to given size using the nearest neighbor interpretation.
+     *
+     * Resized images must be distorted if their output aspect ratio is not the
+     * same as input aspect ratio. The corner pixels of output may not be the
+     * same as corner pixels of input.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
+     * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+     * With the default data layout NHWC, the data is stored in the order of:
+     * [batch, height, width, channels]. Alternatively, the data layout could
+     * be NCHW, the data storage order of: [batch, channels, height, width].
+     *
+     * Both resizing by shape and resizing by scale are supported.
+     *
+     * Inputs (resizing by shape):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input. Zero batches is supported for this tensor.
+     * * 1: An {@link OperandType::INT32} scalar, specifying the output
+     *      width of the output tensor.
+     * * 2: An {@link OperandType::INT32} scalar, specifying the output
+     *      height of the output tensor.
+     * * 3: An {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *
+     * Inputs (resizing by scale):
+     * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+     *      the input. Zero batches is supported for this tensor.
+     * * 1: A scalar, specifying width_scale, the scaling factor of the width
+     *      dimension from the input tensor to the output tensor. The output
+     *      width is calculated as new_width = floor(width * width_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 2: A scalar, specifying height_scale, the scaling factor of the height
+     *      dimension from the input tensor to the output tensor. The output
+     *      height is calculated as new_height = floor(height * height_scale).
+     *      The scalar must be of {@link OperandType::FLOAT16} if input0 is
+     *      of {@link OperandType::TENSOR_FLOAT16} and of
+     *      {@link OperandType::FLOAT32} otherwise.
+     * * 3: An {@link OperandType::BOOL} scalar, default to false.
+     *      Set to true to specify NCHW data layout for input0 and output0.
+     *
+     * Outputs:
+     * * 0: The output 4-D tensor, of shape
+     *      [batches, new_height, new_width, depth].
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      the scale and zeroPoint must be the same as input0.
+     */
+    RESIZE_NEAREST_NEIGHBOR = @1.2::OperationType:RESIZE_NEAREST_NEIGHBOR,
+
+    /**
+     * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
+     * OEM operation and data types.
+     *
+     * This operation is OEM specific. It should only be used for OEM
+     * applications.
+     */
+    OEM_OPERATION = @1.2::OperationType:OEM_OPERATION,
+    /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF
+     * OperationTypeRange::FUNDAMENTAL_MAX.
+     */
+    /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF
+     * OperationTypeRange::OEM_MAX.
+     */
+};
+
+/**
+ * The range of values in the OperationType enum.
+ */
+enum OperationTypeRange : uint32_t {
+    BASE_MIN        = 0,
+    FUNDAMENTAL_MIN = 0,
+    FUNDAMENTAL_MAX = 94,
+    OEM_MIN         = 10000,
+    OEM_MAX         = 10000,
+    BASE_MAX        = 0xFFFF,
+};
+
 
 /**
  * The capabilities of a driver.
@@ -109,6 +4613,32 @@
 };
 
 /**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+    /**
+     * The operation type.
+     *
+     * Besides the values listed in {@link OperationType}, any value above
+     * {@link OperationTypeRange::BASE_MAX} is possible and should be interpreted
+     * as an extension type according to {@link Model::extensionNameToPrefix}.
+     */
+    OperationType type;
+
+    /**
+     * Describes the table that contains the indexes of the inputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> inputs;
+
+    /**
+     * Describes the table that contains the indexes of the outputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> outputs;
+};
+
+/**
  * Describes one operand of the model's graph.
  */
 struct Operand {
@@ -233,28 +4763,6 @@
 };
 
 /**
- * Describes one operation of the model's graph.
- */
-struct Operation {
-    /**
-     * The operation type.
-     */
-    OperationType type;
-
-    /**
-     * Describes the table that contains the indexes of the inputs of the
-     * operation. The offset is the index in the operandIndexes table.
-     */
-    vec<uint32_t> inputs;
-
-    /**
-     * Describes the table that contains the indexes of the outputs of the
-     * operation. The offset is the index in the operandIndexes table.
-     */
-    vec<uint32_t> outputs;
-};
-
-/**
  * A Neural Network Model.
  *
  * This includes not only the execution graph, but also constant data such as
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
index d41cfd2..e06f5d6 100644
--- a/neuralnetworks/1.3/types.t
+++ b/neuralnetworks/1.3/types.t
@@ -44,6 +44,47 @@
     BASE_MAX        = 0xFFFF,
 };
 
+/**
+ * Operation types.
+ *
+ * The type of an operation in a model.
+ */
+enum OperationType : int32_t {
+
+%insert Operation_1.0
+
+%insert Operation_1.1
+
+%insert Operation_1.2
+
+    /**
+     * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
+     * OEM operation and data types.
+     *
+     * This operation is OEM specific. It should only be used for OEM
+     * applications.
+     */
+    OEM_OPERATION = @1.2::OperationType:OEM_OPERATION,
+    /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF
+     * OperationTypeRange::FUNDAMENTAL_MAX.
+     */
+    /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF
+     * OperationTypeRange::OEM_MAX.
+     */
+};
+
+/**
+ * The range of values in the OperationType enum.
+ */
+enum OperationTypeRange : uint32_t {
+    BASE_MIN        = 0,
+    FUNDAMENTAL_MIN = 0,
+%insert Operation_1.3_MAX
+    OEM_MIN         = 10000,
+    OEM_MAX         = 10000,
+    BASE_MAX        = 0xFFFF,
+};
+
 
 /**
  * The capabilities of a driver.
@@ -80,6 +121,32 @@
 };
 
 /**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+    /**
+     * The operation type.
+     *
+     * Besides the values listed in {@link OperationType}, any value above
+     * {@link OperationTypeRange::BASE_MAX} is possible and should be interpreted
+     * as an extension type according to {@link Model::extensionNameToPrefix}.
+     */
+    OperationType type;
+
+    /**
+     * Describes the table that contains the indexes of the inputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> inputs;
+
+    /**
+     * Describes the table that contains the indexes of the outputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> outputs;
+};
+
+/**
  * Describes one operand of the model's graph.
  */
 struct Operand {
@@ -204,28 +271,6 @@
 };
 
 /**
- * Describes one operation of the model's graph.
- */
-struct Operation {
-    /**
-     * The operation type.
-     */
-    OperationType type;
-
-    /**
-     * Describes the table that contains the indexes of the inputs of the
-     * operation. The offset is the index in the operandIndexes table.
-     */
-    vec<uint32_t> inputs;
-
-    /**
-     * Describes the table that contains the indexes of the outputs of the
-     * operation. The offset is the index in the operandIndexes table.
-     */
-    vec<uint32_t> outputs;
-};
-
-/**
  * A Neural Network Model.
  *
  * This includes not only the execution graph, but also constant data such as
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index d8a7534..60992d5 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -456,8 +456,7 @@
     }
 
     // Execute and verify results.
-    EvaluatePreparedModel(preparedModel, testModel,
-                          /*testDynamicOutputShape=*/false);
+    EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
 }
 
 TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
@@ -519,8 +518,7 @@
     }
 
     // Execute and verify results.
-    EvaluatePreparedModel(preparedModel, testModel,
-                          /*testDynamicOutputShape=*/false);
+    EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
 }
 
 TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) {
@@ -541,8 +539,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -566,8 +563,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -590,8 +586,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -615,8 +610,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -727,8 +721,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -752,8 +745,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -776,8 +768,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -801,8 +792,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -914,8 +904,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -937,8 +926,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -1082,8 +1070,7 @@
                 ASSERT_EQ(preparedModel, nullptr);
             } else {
                 ASSERT_NE(preparedModel, nullptr);
-                EvaluatePreparedModel(preparedModel, testModelAdd,
-                                      /*testDynamicOutputShape=*/false);
+                EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL);
             }
         }
     }
@@ -1144,8 +1131,7 @@
                 ASSERT_EQ(preparedModel, nullptr);
             } else {
                 ASSERT_NE(preparedModel, nullptr);
-                EvaluatePreparedModel(preparedModel, testModelAdd,
-                                      /*testDynamicOutputShape=*/false);
+                EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL);
             }
         }
     }
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 325d641..3e947f5 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -63,15 +63,41 @@
 using V1_1::ExecutionPreference;
 using V1_2::Constant;
 using V1_2::MeasureTiming;
-using V1_2::OperationType;
 using V1_2::OutputShape;
 using V1_2::SymmPerChannelQuantParams;
 using V1_2::Timing;
 using V1_2::implementation::ExecutionCallback;
 using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
 
+namespace {
+
+enum class Executor { ASYNC, SYNC, BURST };
+
 enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
 
+struct TestConfig {
+    Executor executor;
+    MeasureTiming measureTiming;
+    OutputType outputType;
+    // `reportSkipping` indicates if a test should print an info message in case
+    // it is skipped. The field is set to true by default and is set to false in
+    // quantization coupling tests to suppress skipping a test
+    bool reportSkipping;
+    TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType)
+        : executor(executor),
+          measureTiming(measureTiming),
+          outputType(outputType),
+          reportSkipping(true) {}
+    TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType,
+               bool reportSkipping)
+        : executor(executor),
+          measureTiming(measureTiming),
+          outputType(outputType),
+          reportSkipping(reportSkipping) {}
+};
+
+}  // namespace
+
 Model createModel(const TestModel& testModel) {
     // Model operands.
     hidl_vec<Operand> operands(testModel.operands.size());
@@ -206,31 +232,34 @@
     return android::nn::ExecutionBurstController::create(preparedModel,
                                                          std::chrono::microseconds{0});
 }
-enum class Executor { ASYNC, SYNC, BURST };
 
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
-                           Executor executor, MeasureTiming measure, OutputType outputType) {
+                           const TestConfig& testConfig, bool* skipped = nullptr) {
+    if (skipped != nullptr) {
+        *skipped = false;
+    }
     // If output0 does not have size larger than one byte, we can not test with insufficient buffer.
-    if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) {
+    if (testConfig.outputType == OutputType::INSUFFICIENT &&
+        !isOutputSizeGreaterThanOne(testModel, 0)) {
         return;
     }
 
     Request request = createRequest(testModel);
-    if (outputType == OutputType::INSUFFICIENT) {
+    if (testConfig.outputType == OutputType::INSUFFICIENT) {
         makeOutputInsufficientSize(/*outputIndex=*/0, &request);
     }
 
     ErrorStatus executionStatus;
     hidl_vec<OutputShape> outputShapes;
     Timing timing;
-    switch (executor) {
+    switch (testConfig.executor) {
         case Executor::ASYNC: {
             SCOPED_TRACE("asynchronous");
 
             // launch execution
             sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-            Return<ErrorStatus> executionLaunchStatus =
-                    ExecutePreparedModel(preparedModel, request, measure, executionCallback);
+            Return<ErrorStatus> executionLaunchStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, executionCallback);
             ASSERT_TRUE(executionLaunchStatus.isOk());
             EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
 
@@ -246,8 +275,8 @@
             SCOPED_TRACE("synchronous");
 
             // execute
-            Return<ErrorStatus> executionReturnStatus =
-                    ExecutePreparedModel(preparedModel, request, measure, &outputShapes, &timing);
+            Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, &outputShapes, &timing);
             ASSERT_TRUE(executionReturnStatus.isOk());
             executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
 
@@ -270,15 +299,21 @@
             // execute burst
             int n;
             std::tie(n, outputShapes, timing, std::ignore) =
-                    controller->compute(request, measure, keys);
+                    controller->compute(request, testConfig.measureTiming, keys);
             executionStatus = nn::convertResultCodeToErrorStatus(n);
 
             break;
         }
     }
 
-    if (outputType != OutputType::FULLY_SPECIFIED &&
+    if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
         executionStatus == ErrorStatus::GENERAL_FAILURE) {
+        if (skipped != nullptr) {
+            *skipped = true;
+        }
+        if (!testConfig.reportSkipping) {
+            return;
+        }
         LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
                      "execute model that it does not support.";
         std::cout << "[          ]   Early termination of test because vendor service cannot "
@@ -286,7 +321,7 @@
                   << std::endl;
         GTEST_SKIP();
     }
-    if (measure == MeasureTiming::NO) {
+    if (testConfig.measureTiming == MeasureTiming::NO) {
         EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
         EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
     } else {
@@ -295,7 +330,7 @@
         }
     }
 
-    switch (outputType) {
+    switch (testConfig.outputType) {
         case OutputType::FULLY_SPECIFIED:
             // If the model output operands are fully specified, outputShapes must be either
             // either empty, or have the same number of elements as the number of outputs.
@@ -332,59 +367,117 @@
 }
 
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
-                           bool testDynamicOutputShape) {
-    if (testDynamicOutputShape) {
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
-    } else {
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
+                           TestKind testKind) {
+    std::initializer_list<OutputType> outputTypesList;
+    std::initializer_list<MeasureTiming> measureTimingList;
+    std::initializer_list<Executor> executorList;
+
+    switch (testKind) {
+        case TestKind::GENERAL: {
+            outputTypesList = {OutputType::FULLY_SPECIFIED};
+            measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+            executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+        } break;
+        case TestKind::DYNAMIC_SHAPE: {
+            outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
+            measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+            executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+        } break;
+        case TestKind::QUANTIZATION_COUPLING: {
+            LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel";
+            return;
+        } break;
+    }
+
+    for (const OutputType outputType : outputTypesList) {
+        for (const MeasureTiming measureTiming : measureTimingList) {
+            for (const Executor executor : executorList) {
+                const TestConfig testConfig(executor, measureTiming, outputType);
+                EvaluatePreparedModel(preparedModel, testModel, testConfig);
+            }
+        }
     }
 }
 
-void Execute(const sp<IDevice>& device, const TestModel& testModel, bool testDynamicOutputShape) {
+void EvaluatePreparedCoupledModels(const sp<IPreparedModel>& preparedModel,
+                                   const TestModel& testModel,
+                                   const sp<IPreparedModel>& preparedCoupledModel,
+                                   const TestModel& coupledModel) {
+    std::initializer_list<OutputType> outputTypesList = {OutputType::FULLY_SPECIFIED};
+    std::initializer_list<MeasureTiming> measureTimingList = {MeasureTiming::NO,
+                                                              MeasureTiming::YES};
+    std::initializer_list<Executor> executorList = {Executor::ASYNC, Executor::SYNC,
+                                                    Executor::BURST};
+
+    for (const OutputType outputType : outputTypesList) {
+        for (const MeasureTiming measureTiming : measureTimingList) {
+            for (const Executor executor : executorList) {
+                const TestConfig testConfig(executor, measureTiming, outputType,
+                                            /*reportSkipping=*/false);
+                bool baseSkipped = false;
+                EvaluatePreparedModel(preparedModel, testModel, testConfig, &baseSkipped);
+                bool coupledSkipped = false;
+                EvaluatePreparedModel(preparedCoupledModel, coupledModel, testConfig,
+                                      &coupledSkipped);
+                ASSERT_EQ(baseSkipped, coupledSkipped);
+                if (baseSkipped) {
+                    LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                                 "execute model that it does not support.";
+                    std::cout << "[          ]   Early termination of test because vendor service "
+                                 "cannot "
+                                 "execute model that it does not support."
+                              << std::endl;
+                    GTEST_SKIP();
+                }
+            }
+        }
+    }
+}
+
+void Execute(const sp<IDevice>& device, const TestModel& testModel, TestKind testKind) {
     Model model = createModel(testModel);
-    if (testDynamicOutputShape) {
+    if (testKind == TestKind::DYNAMIC_SHAPE) {
         makeOutputDimensionsUnspecified(&model);
     }
 
     sp<IPreparedModel> preparedModel;
-    createPreparedModel(device, model, &preparedModel);
-    if (preparedModel == nullptr) return;
-
-    EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape);
+    switch (testKind) {
+        case TestKind::GENERAL: {
+            createPreparedModel(device, model, &preparedModel);
+            if (preparedModel == nullptr) return;
+            EvaluatePreparedModel(preparedModel, testModel, TestKind::GENERAL);
+        } break;
+        case TestKind::DYNAMIC_SHAPE: {
+            createPreparedModel(device, model, &preparedModel);
+            if (preparedModel == nullptr) return;
+            EvaluatePreparedModel(preparedModel, testModel, TestKind::DYNAMIC_SHAPE);
+        } break;
+        case TestKind::QUANTIZATION_COUPLING: {
+            ASSERT_TRUE(testModel.hasQuant8AsymmOperands());
+            createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ false);
+            TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel);
+            sp<IPreparedModel> preparedCoupledModel;
+            createPreparedModel(device, createModel(signedQuantizedModel), &preparedCoupledModel,
+                                /*reportSkipping*/ false);
+            // If we couldn't prepare a model with unsigned quantization, we must
+            // fail to prepare a model with signed quantization as well.
+            if (preparedModel == nullptr) {
+                ASSERT_EQ(preparedCoupledModel, nullptr);
+                // If we failed to prepare both of the models, we can safely skip
+                // the test.
+                LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                             "prepare model that it does not support.";
+                std::cout
+                        << "[          ]   Early termination of test because vendor service cannot "
+                           "prepare model that it does not support."
+                        << std::endl;
+                GTEST_SKIP();
+            }
+            ASSERT_NE(preparedCoupledModel, nullptr);
+            EvaluatePreparedCoupledModels(preparedModel, testModel, preparedCoupledModel,
+                                          signedQuantizedModel);
+        } break;
+    }
 }
 
 void GeneratedTestBase::SetUp() {
@@ -407,12 +500,19 @@
 // Tag for the dynamic output shape tests
 class DynamicOutputShapeTest : public GeneratedTest {};
 
+// Tag for the dynamic output shape tests
+class DISABLED_QuantizationCouplingTest : public GeneratedTest {};
+
 TEST_P(GeneratedTest, Test) {
-    Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/false);
+    Execute(kDevice, kTestModel, /*testKind=*/TestKind::GENERAL);
 }
 
 TEST_P(DynamicOutputShapeTest, Test) {
-    Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/true);
+    Execute(kDevice, kTestModel, /*testKind=*/TestKind::DYNAMIC_SHAPE);
+}
+
+TEST_P(DISABLED_QuantizationCouplingTest, Test) {
+    Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING);
 }
 
 INSTANTIATE_GENERATED_TEST(GeneratedTest,
@@ -421,4 +521,8 @@
 INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest,
                            [](const TestModel& testModel) { return !testModel.expectFailure; });
 
+INSTANTIATE_GENERATED_TEST(DISABLED_QuantizationCouplingTest, [](const TestModel& testModel) {
+    return testModel.hasQuant8AsymmOperands() && testModel.operations.size() == 1;
+});
+
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
index 45cff5b..ad6323f 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
@@ -57,8 +57,19 @@
 
 void PrepareModel(const sp<IDevice>& device, const Model& model, sp<IPreparedModel>* preparedModel);
 
+enum class TestKind {
+    // Runs a test model and compares the results to a golden data
+    GENERAL,
+    // Same as GENERAL but sets dimensions for the output tensors to zeros
+    DYNAMIC_SHAPE,
+    // Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result
+    // (OK/SKIPPED/FAILED) as the model with all such tensors converted to
+    // TENSOR_QUANT8_ASYMM_SIGNED.
+    QUANTIZATION_COUPLING
+};
+
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel,
-                           const test_helper::TestModel& testModel, bool testDynamicOutputShape);
+                           const test_helper::TestModel& testModel, TestKind testKind);
 
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
 
diff --git a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
index 7361078..a7569e6 100644
--- a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
+++ b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
@@ -25,8 +25,6 @@
 #define CHECK_TEST_ENUM(EnumType, enumValue) \
     static_assert(static_cast<EnumType>(Test##EnumType::enumValue) == EnumType::enumValue)
 
-using V1_2::OperationType;
-
 CHECK_TEST_ENUM(OperandType, FLOAT32);
 CHECK_TEST_ENUM(OperandType, INT32);
 CHECK_TEST_ENUM(OperandType, UINT32);
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 1ff02dc..46bbd3f 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -27,7 +27,6 @@
 using V1_0::ErrorStatus;
 using V1_0::OperandLifeTime;
 using V1_1::ExecutionPreference;
-using V1_2::OperationType;
 using V1_2::OperationTypeRange;
 using V1_2::SymmPerChannelQuantParams;
 using HidlToken =
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
index 625913d..92d8fa7 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -37,7 +37,7 @@
 
 // internal helper function
 void createPreparedModel(const sp<IDevice>& device, const Model& model,
-                         sp<IPreparedModel>* preparedModel) {
+                         sp<IPreparedModel>* preparedModel, bool reportSkipping) {
     ASSERT_NE(nullptr, preparedModel);
     *preparedModel = nullptr;
 
@@ -74,6 +74,9 @@
     // can continue.
     if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
         ASSERT_EQ(nullptr, preparedModel->get());
+        if (!reportSkipping) {
+            return;
+        }
         LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare "
                      "model that it does not support.";
         std::cout << "[          ]   Early termination of test because vendor service cannot "
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
index 8cb42d4..4e51052 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
@@ -47,7 +47,7 @@
 // Create an IPreparedModel object. If the model cannot be prepared,
 // "preparedModel" will be nullptr instead.
 void createPreparedModel(const sp<IDevice>& device, const Model& model,
-                         sp<IPreparedModel>* preparedModel);
+                         sp<IPreparedModel>* preparedModel, bool reportSkipping = true);
 
 // Utility function to get PreparedModel from callback and downcast to V1_2.
 sp<IPreparedModel> getPreparedModel_1_3(const sp<implementation::PreparedModelCallback>& callback);
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index de20dd0..74ec56d 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -17,6 +17,8 @@
 package android.hardware.radio@1.5;
 
 import @1.4::IRadio;
+import @1.5::AccessNetwork;
+import @1.5::SignalThresholdInfo;
 
 /**
  * This interface is used by telephony and telecom to talk to cellular radio.
@@ -27,4 +29,30 @@
  * setResponseFunctions must work with @1.5::IRadioResponse and @1.5::IRadioIndication.
  */
 interface IRadio extends @1.4::IRadio {
+
+    /**
+     * Sets the signal strength reporting criteria.
+     *
+     * The resulting reporting rules are the AND of all the supplied criteria. For each RAN
+     * The hysteresisDb and thresholds apply to only the following measured quantities:
+     * -GERAN    - RSSI
+     * -CDMA2000 - RSSI
+     * -UTRAN    - RSCP
+     * -EUTRAN   - RSRP/RSRQ/RSSNR
+     * -NGRAN    - SSRSRP/SSRSRQ/SSSINR
+     *
+     * Note: Reporting criteria must be individually set for each RAN. For any unset reporting
+     * criteria, the value is implementation-defined.
+     *
+     * Response callback is
+     * IRadioResponse.setSignalStrengthReportingCriteriaResponse_1_5()
+     *
+     * @param serial Serial number of request.
+     * @param signalThresholdInfo Signal threshold info including the threshold values,
+     *                            hysteresisDb, and hysteresisMs. See @1.5::SignalThresholdInfo
+     *                            for details.
+     * @param accessNetwork The type of network for which to apply these thresholds.
+     */
+    oneway setSignalStrengthReportingCriteria_1_5(int32_t serial,
+            SignalThresholdInfo signalThresholdInfo, AccessNetwork accessNetwork);
 };
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index d4c4f76..91dc1e0 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -23,4 +23,13 @@
  * Interface declaring response functions to solicited radio requests.
  */
 interface IRadioResponse extends @1.4::IRadioResponse {
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:RADIO_NOT_AVAILABLE
+     */
+    oneway setSignalStrengthReportingCriteriaResponse_1_5(RadioResponseInfo info);
 };
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index a639a8d..2441b65 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -15,3 +15,102 @@
  */
 
 package android.hardware.radio@1.5;
+
+import @1.4::AccessNetwork;
+
+/**
+ * Defining signal strength type.
+ */
+enum SignalMeasurementType : int32_t {
+    /**
+     * Received Signal Strength Indication.
+     * Range: -113 dBm and -51 dBm
+     * Used RAN: GERAN, CDMA2000
+     * Reference: 3GPP TS 27.007 section 8.5.
+     */
+    RSSI = 1,
+    /**
+     * Received Signal Code Power.
+     * Range: -120 dBm to -25 dBm;
+     * Used RAN: UTRAN
+     * Reference: 3GPP TS 25.123, section 9.1.1.1
+     */
+    RSCP = 2,
+    /**
+     * Reference Signal Received Power.
+     * Range: -140 dBm to -44 dBm;
+     * Used RAN: EUTRAN
+     * Reference: 3GPP TS 36.133 9.1.4
+     */
+    RSRP = 3,
+    /**
+     * Reference Signal Received Quality
+     * Range: -20 dB to -3 dB;
+     * Used RAN: EUTRAN
+     * Reference: 3GPP TS 36.133 9.1.7
+     */
+    RSRQ = 4,
+    /**
+     * Reference Signal Signal to Noise Ratio
+     * Range: -20 dB to 30 dB;
+     * Used RAN: EUTRAN
+     * Note: this field is optional; how to support it can be decided by the
+     * corresponding vendor. Though the response code is not enforced,
+     * vendor's implementation must ensure this interface not crashing.
+     */
+    RSSNR = 5,
+    /**
+     * 5G SS reference signal received power.
+     * Range: -140 dBm to -44 dBm.
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215.
+     */
+    SSRSRP = 6,
+    /**
+     * 5G SS reference signal received quality.
+     * Range: -20 dB to -3 dB.
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215.
+     */
+    SSRSRQ = 7,
+    /**
+     * 5G SS signal-to-noise and interference ratio.
+     * Range: -23 dB to 40 dB
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
+     */
+    SSSINR = 8,
+};
+
+/**
+ * Contains the threshold values of each signal measurement type.
+ */
+struct SignalThresholdInfo {
+    /** Signal Measurement Type */
+    SignalMeasurementType signalMeasurement;
+
+    /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis */
+    int32_t hysteresisMs;
+
+    /**
+     * An interval in dB defining the required magnitude change between reports.
+     * hysteresisDb must be smaller than the smallest threshold delta.
+     * An interval value of 0 disables hysteresis.
+     */
+    int32_t hysteresisDb;
+
+    /**
+     * List of threshold values.
+     * Range and unit must reference specific @1.5::SignalMeasurementType.
+     * The threshold values for which to apply criteria.
+     * A vector size of 0 disables the use of thresholds for reporting.
+     */
+    vec<int32_t> thresholds;
+};
+
+enum AccessNetwork : @1.4::AccessNetwork {
+    /**
+     *  Next-Generation Radio Access Network (NGRAN)
+     */
+    NGRAN = 6,
+};
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index b86fa5f..d173411 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -17,3 +17,262 @@
 #include <radio_hidl_hal_utils_v1_5.h>
 
 #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() with invalid hysteresisDb
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_invalidHysteresisDb) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 10;  // hysteresisDb too large given threshold list deltas
+    signalThresholdInfo.thresholds = {-109, -103, -97, -89};
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_invalidHysteresisDb, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() with empty thresholds
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_EmptyThresholds) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI;
+    signalThresholdInfo.hysteresisMs = 0;
+    signalThresholdInfo.hysteresisDb = 0;
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_EmptyParams, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for GERAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Geran) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-109, -103, -97, -89};
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_Geran, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for UTRAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Utran) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSCP;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-110, -97, -73, -49, -25};
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::UTRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_Utran, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRP) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSRP;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-128, -108, -88, -68};
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_Eutran, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRQ) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSRQ;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-27, -20, -13, -6};
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_Eutran, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSSNR) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSNR;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-10, 0, 10, 20};
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for CDMA2000
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Cdma2000) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-105, -90, -75, -65};
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::CDMA2000);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_Cdma2000, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSRSRP
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::SSRSRP;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 0;
+    signalThresholdInfo.thresholds = {-105, -90, -75, -65};
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSRSRQ
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::SSRSRQ;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 0;
+    signalThresholdInfo.thresholds = {-15, -10, -5, -4};
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSSINR
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) {
+    serial = GetRandomSerialNumber();
+
+    ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalMeasurementType::SSSINR;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 0;
+    signalThresholdInfo.thresholds = {-10, 3, 16, 18};
+
+    Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+            serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::NONE}));
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index 799702b..683fdfc 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -521,6 +521,9 @@
     Return<void> getAllowedCarriersResponse_1_4(const RadioResponseInfo& info,
                                                 const CarrierRestrictionsWithPriority& carriers,
                                                 SimLockMultiSimPolicy multiSimPolicy);
+
+    /* 1.5 Api */
+    Return<void> setSignalStrengthReportingCriteriaResponse_1_5(const RadioResponseInfo& info);
 };
 
 /* Callback class for radio indication */
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index 1e5cc47..29a9250 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -885,3 +885,11 @@
     parent_v1_5.notify(info.serial);
     return Void();
 }
+
+/* 1.5 Apis */
+Return<void> RadioResponse_v1_5::setSignalStrengthReportingCriteriaResponse_1_5(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
\ No newline at end of file
diff --git a/radio/config/1.0/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.0/vts/functional/radio_config_hidl_hal_utils.h
index 6bc1b65..2722afe 100644
--- a/radio/config/1.0/vts/functional/radio_config_hidl_hal_utils.h
+++ b/radio/config/1.0/vts/functional/radio_config_hidl_hal_utils.h
@@ -27,6 +27,7 @@
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
+#include <log/log.h>
 
 #include "vts_test_util.h"
 
diff --git a/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h
index e9951dc..4cdeb06 100644
--- a/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h
+++ b/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h
@@ -26,6 +26,7 @@
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
+#include <log/log.h>
 
 #include "vts_test_util.h"
 
diff --git a/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h
index e9cbcbd..ba3f02e 100644
--- a/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h
+++ b/radio/config/1.2/vts/functional/radio_config_hidl_hal_utils.h
@@ -28,6 +28,7 @@
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
+#include <log/log.h>
 
 #include "vts_test_util.h"
 
@@ -98,20 +99,6 @@
             const ::android::hardware::hidl_vec<SimSlotStatus>& slotStatus);
 };
 
-// Test environment for Radio HIDL HAL.
-class RadioConfigHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-  public:
-    // get the test environment singleton
-    static RadioConfigHidlEnvironment* Instance() {
-        static RadioConfigHidlEnvironment* instance = new RadioConfigHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override { registerTestService<IRadioConfig>(); }
-
-  private:
-    RadioConfigHidlEnvironment() {}
-};
-
 // The main test class for Radio config HIDL.
 class RadioConfigHidlTest : public ::testing::TestWithParam<std::string> {
   protected:
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
index a771100..1acc8e6 100644
--- a/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
@@ -5,7 +5,7 @@
         <version>2.0</version>
         <interface>
             <name>ISensors</name>
-            <instance>multihal</instance>
+            <instance>default</instance>
         </interface>
     </hal>
 </manifest>
diff --git a/soundtrigger/2.0/vts/functional/Android.bp b/soundtrigger/2.0/vts/functional/Android.bp
index f6207c4..13dcdec 100644
--- a/soundtrigger/2.0/vts/functional/Android.bp
+++ b/soundtrigger/2.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalSoundtriggerV2_0TargetTest.cpp"],
     static_libs: ["android.hardware.soundtrigger@2.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
index 59ac13e..d7a7d08 100644
--- a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
+++ b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
@@ -23,15 +23,15 @@
 
 #include <android/log.h>
 #include <cutils/native_handle.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 #include <android/hardware/audio/common/2.0/types.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.0/types.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 #define SHORT_TIMEOUT_PERIOD (1)
 
 using ::android::hardware::audio::common::V2_0::AudioDevice;
@@ -86,27 +86,11 @@
   int mCount;
 };
 
-// Test environment for SoundTrigger HIDL HAL.
-class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static SoundTriggerHidlEnvironment* Instance() {
-        static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
-
-   private:
-    SoundTriggerHidlEnvironment() {}
-};
-
 // The main test class for Sound Trigger HIDL HAL.
-class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SoundTriggerHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-      mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
-          SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
+      mSoundTriggerHal = ISoundTriggerHw::getService(GetParam());
       ASSERT_NE(nullptr, mSoundTriggerHal.get());
       mCallback = new SoundTriggerHwCallback(*this);
       ASSERT_NE(nullptr, mCallback.get());
@@ -167,7 +151,7 @@
  *  - the implementation supports at least one sound model and one key phrase
  *  - the implementation supports at least VOICE_TRIGGER recognition mode
  */
-TEST_F(SoundTriggerHidlTest, GetProperties) {
+TEST_P(SoundTriggerHidlTest, GetProperties) {
   ISoundTriggerHw::Properties halProperties;
   Return<void> hidlReturn;
   int ret = -ENODEV;
@@ -194,7 +178,7 @@
  * There is no way to verify that implementation actually can load a sound model because each
  * sound model is vendor specific.
  */
-TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) {
+TEST_P(SoundTriggerHidlTest, LoadInvalidModelFail) {
   Return<void> hidlReturn;
   int ret = -ENODEV;
   ISoundTriggerHw::PhraseSoundModel model;
@@ -220,7 +204,7 @@
  * Verifies that:
  *  - the implementation returns error when passed a sound model with random data.
  */
-TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
+TEST_P(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
   int ret = -ENODEV;
   ISoundTriggerHw::SoundModel model;
   SoundModelHandle handle = 0;
@@ -251,7 +235,7 @@
  *  - the implementation returns an error when called without a valid loaded sound model
  *
  */
-TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) {
+TEST_P(SoundTriggerHidlTest, UnloadModelNoModelFail) {
   Return<int32_t> hidlReturn(0);
   SoundModelHandle halHandle = 0;
 
@@ -271,7 +255,7 @@
  * There is no way to verify that implementation actually starts recognition because no model can
  * be loaded.
  */
-TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
+TEST_P(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle handle = 0;
     PhraseRecognitionExtra phrase;
@@ -299,7 +283,7 @@
  *  - the implementation returns an error when called without an active recognition running
  *
  */
-TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
+TEST_P(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle handle = 0;
 
@@ -316,7 +300,7 @@
  *  - the implementation implements this optional method or indicates it is not support by
  *  returning -ENOSYS
  */
-TEST_F(SoundTriggerHidlTest, stopAllRecognitions) {
+TEST_P(SoundTriggerHidlTest, stopAllRecognitions) {
     Return<int32_t> hidlReturn(0);
 
     hidlReturn = mSoundTriggerHal->stopAllRecognitions();
@@ -325,11 +309,7 @@
     EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, SoundTriggerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/soundtrigger/2.1/vts/functional/Android.bp b/soundtrigger/2.1/vts/functional/Android.bp
index f1eb35d..7830fe2 100644
--- a/soundtrigger/2.1/vts/functional/Android.bp
+++ b/soundtrigger/2.1/vts/functional/Android.bp
@@ -25,5 +25,5 @@
                  "android.hardware.soundtrigger@2.1",
                  "libhidlmemory"
                  ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
index 0a2eeac..7f06ed9 100644
--- a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
+++ b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
@@ -23,6 +23,9 @@
 
 #include <android/log.h>
 #include <cutils/native_handle.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 #include <android/hardware/audio/common/2.0/types.h>
@@ -32,9 +35,6 @@
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <hidlmemory/mapping.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 #define SHORT_TIMEOUT_PERIOD (1)
 
 using ::android::sp;
@@ -94,27 +94,11 @@
     int mCount;
 };
 
-// Test environment for SoundTrigger HIDL HAL.
-class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static SoundTriggerHidlEnvironment* Instance() {
-        static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
-
-   private:
-    SoundTriggerHidlEnvironment() {}
-};
-
 // The main test class for Sound Trigger HIDL HAL.
-class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SoundTriggerHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
-            SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
+        mSoundTriggerHal = ISoundTriggerHw::getService(GetParam());
         ASSERT_NE(nullptr, mSoundTriggerHal.get());
         mCallback = new SoundTriggerHwCallback(*this);
         ASSERT_NE(nullptr, mCallback.get());
@@ -196,7 +180,7 @@
  *  - the implementation supports at least one sound model and one key phrase
  *  - the implementation supports at least VOICE_TRIGGER recognition mode
  */
-TEST_F(SoundTriggerHidlTest, GetProperties) {
+TEST_P(SoundTriggerHidlTest, GetProperties) {
     ISoundTriggerHw::Properties halProperties;
     Return<void> hidlReturn;
     int ret = -ENODEV;
@@ -223,7 +207,7 @@
  * There is no way to verify that implementation actually can load a sound model because each
  * sound model is vendor specific.
  */
-TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) {
+TEST_P(SoundTriggerHidlTest, LoadInvalidModelFail) {
     Return<void> hidlReturn;
     int ret = -ENODEV;
     V2_0_ISoundTriggerHw::PhraseSoundModel model;
@@ -252,7 +236,7 @@
  * There is no way to verify that implementation actually can load a sound model because each
  * sound model is vendor specific.
  */
-TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail_2_1) {
+TEST_P(SoundTriggerHidlTest, LoadInvalidModelFail_2_1) {
     Return<void> hidlReturn;
     int ret = -ENODEV;
     ISoundTriggerHw::PhraseSoundModel model;
@@ -277,7 +261,7 @@
  * Verifies that:
  *  - the implementation returns an error when passed an empty sound model
  */
-TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail) {
+TEST_P(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail) {
     int ret = -ENODEV;
     V2_0_ISoundTriggerHw::SoundModel model;
     SoundModelHandle handle = 0;
@@ -301,7 +285,7 @@
  * Verifies that:
  *  - the implementation returns error when passed a sound model with random data.
  */
-TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
+TEST_P(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
     int ret = -ENODEV;
     V2_0_ISoundTriggerHw::SoundModel model;
     SoundModelHandle handle = 0;
@@ -329,7 +313,7 @@
  * Verifies that:
  *  - the implementation returns error when passed a sound model with random data.
  */
-TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail_2_1) {
+TEST_P(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail_2_1) {
     int ret = -ENODEV;
     ISoundTriggerHw::SoundModel model;
     SoundModelHandle handle = 0;
@@ -353,7 +337,7 @@
  * Verifies that:
  *  - the implementation returns error when passed a sound model with random data.
  */
-TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail_2_1) {
+TEST_P(SoundTriggerHidlTest, LoadGenericSoundModelFail_2_1) {
     int ret = -ENODEV;
     ISoundTriggerHw::SoundModel model;
     SoundModelHandle handle = 0;
@@ -394,7 +378,7 @@
  *  - the implementation returns an error when called without a valid loaded sound model
  *
  */
-TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) {
+TEST_P(SoundTriggerHidlTest, UnloadModelNoModelFail) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle halHandle = 0;
 
@@ -414,7 +398,7 @@
  * There is no way to verify that implementation actually starts recognition because no model can
  * be loaded.
  */
-TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
+TEST_P(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle handle = 0;
     PhraseRecognitionExtra phrase;
@@ -444,7 +428,7 @@
  * There is no way to verify that implementation actually starts recognition because no model can
  * be loaded.
  */
-TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail_2_1) {
+TEST_P(SoundTriggerHidlTest, StartRecognitionNoModelFail_2_1) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle handle = 0;
     PhraseRecognitionExtra phrase;
@@ -472,7 +456,7 @@
  *  - the implementation returns an error when called without an active recognition running
  *
  */
-TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
+TEST_P(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
     Return<int32_t> hidlReturn(0);
     SoundModelHandle handle = 0;
 
@@ -489,7 +473,7 @@
  *  - the implementation implements this optional method or indicates it is not supported by
  *  returning -ENOSYS
  */
-TEST_F(SoundTriggerHidlTest, stopAllRecognitions) {
+TEST_P(SoundTriggerHidlTest, stopAllRecognitions) {
     Return<int32_t> hidlReturn(0);
 
     hidlReturn = mSoundTriggerHal->stopAllRecognitions();
@@ -498,11 +482,7 @@
     EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, SoundTriggerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/soundtrigger/2.2/vts/functional/Android.bp b/soundtrigger/2.2/vts/functional/Android.bp
index 08ccd7b..b5d241d 100644
--- a/soundtrigger/2.2/vts/functional/Android.bp
+++ b/soundtrigger/2.2/vts/functional/Android.bp
@@ -23,5 +23,5 @@
         "android.hardware.soundtrigger@2.1",
         "android.hardware.soundtrigger@2.2",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp b/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp
index 0f37816..1cce5a1 100644
--- a/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp
+++ b/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp
@@ -23,42 +23,26 @@
 
 #include <android/log.h>
 #include <cutils/native_handle.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 #include <android/hardware/audio/common/2.0/types.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 using ::android::sp;
 using ::android::hardware::Return;
 using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
 using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
 using ::android::hardware::soundtrigger::V2_2::ISoundTriggerHw;
 
-// Test environment for SoundTrigger HIDL HAL.
-class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static SoundTriggerHidlEnvironment* Instance() {
-        static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
-        return instance;
-    }
-
-    void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
-
-   private:
-    SoundTriggerHidlEnvironment() {}
-};
-
 // The main test class for Sound Trigger HIDL HAL.
-class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SoundTriggerHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     void SetUp() override {
-        mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
-            SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
+        mSoundTriggerHal = ISoundTriggerHw::getService(GetParam());
         ASSERT_NE(nullptr, mSoundTriggerHal.get());
     }
 
@@ -77,18 +61,13 @@
  *  - the implementation returns -ENOSYS with invalid model handle
  *
  */
-TEST_F(SoundTriggerHidlTest, GetModelStateInvalidModel) {
+TEST_P(SoundTriggerHidlTest, GetModelStateInvalidModel) {
     SoundModelHandle handle = 0;
     Return<int32_t> hidlReturn = mSoundTriggerHal->getModelState(handle);
     EXPECT_TRUE(hidlReturn.isOk());
     EXPECT_EQ(-ENOSYS, hidlReturn);
 }
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, SoundTriggerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp
new file mode 100644
index 0000000..ef9b39b
--- /dev/null
+++ b/tests/extension/vibrator/aidl/Android.bp
@@ -0,0 +1,29 @@
+aidl_interface {
+    // This is an example test interface showing how to add functionality
+    // with setExtension/getExtension
+    name: "test-vintf-vibrator-ext",
+    vendor_available: true,
+    srcs: [
+        // Using android.hardware as the package because this is in
+        // hardware/interfaces. For custom interfaces, normally you
+        // would use a different package.
+        "android/hardware/tests/extension/vibrator/Directionality.aidl",
+        "android/hardware/tests/extension/vibrator/ICustomVibrator.aidl",
+        "android/hardware/tests/extension/vibrator/VendorEffect.aidl",
+    ],
+
+    // This is agreeing to keep the interface stable.
+    stability: "vintf",
+
+    // This happens to use types from a core interface, so we import it, but
+    // this won't always be needed.
+    imports: [
+        "vintf-vibrator",
+    ],
+
+    backend: {
+        java: {
+            enabled: false,
+        },
+    },
+}
diff --git a/vibrator/1.4/types.hal b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/Directionality.aidl
similarity index 60%
copy from vibrator/1.4/types.hal
copy to tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/Directionality.aidl
index acc49b1..72bfd66 100644
--- a/vibrator/1.4/types.hal
+++ b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/Directionality.aidl
@@ -13,10 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.hardware.tests.extension.vibrator;
 
-package android.hardware.vibrator@1.4;
-
-enum Capabilities : uint32_t {
-    ON_COMPLETION_CALLBACK = 1 << 0,
-    PERFORM_COMPLETION_CALLBACK = 1 << 1,
-};
+/**
+ * Can add custom enums. If these need to be extended further, new values can
+ * simply be added.
+ */
+@Backing(type="int")
+@VintfStability
+enum Directionality {
+    NONE,
+    /** vibrations should be transverse wrt primary screen */
+    TRANSVERSE,
+    /** vibrations should be longitudinal wrt primary screen */
+    LONGITUDINAL,
+}
diff --git a/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl
new file mode 100644
index 0000000..0b21f46
--- /dev/null
+++ b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/ICustomVibrator.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.tests.extension.vibrator;
+
+// it's fine to use types from other interfaces
+import android.hardware.vibrator.IVibratorCallback;
+import android.hardware.tests.extension.vibrator.Directionality;
+import android.hardware.tests.extension.vibrator.VendorEffect;
+
+/**
+ * This is an example of an AIDL interface extension. Notice that it does not
+ * inherit from any other extension. Instead, it will be tagged onto that
+ * extension at runtime.
+ */
+@VintfStability
+interface ICustomVibrator {
+    /**
+     * Avoid conflicting with vendor properties. Giving this as an example
+     * because the core vibrator interface uses capabilities. In reality,
+     * since this is only one capability, it's probably not needed to construct
+     * a bitfield.
+     *
+     * This is for longitudinal/transverse waves, see setDirectionality.
+     */
+    const int CAP_VENDOR_DIRECTIONALITY = 1 << 0;
+
+    /**
+     * Any new methods can be added, this returns CAP_VENDOR_*.
+     */
+    int getVendorCapabilities();
+
+    /**
+     * Arbitrary new functionality can be added.
+     */
+    void setDirectionality(Directionality directionality);
+
+    /**
+     * Perform a custom vendor effect. Note, this is a separate effect enum to
+     * avoid conflicting with core types.
+     */
+    int perform(VendorEffect effect, IVibratorCallback callback);
+}
diff --git a/vibrator/1.4/types.hal b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/VendorEffect.aidl
similarity index 74%
rename from vibrator/1.4/types.hal
rename to tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/VendorEffect.aidl
index acc49b1..968532c 100644
--- a/vibrator/1.4/types.hal
+++ b/tests/extension/vibrator/aidl/android/hardware/tests/extension/vibrator/VendorEffect.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.hardware.tests.extension.vibrator;
 
-package android.hardware.vibrator@1.4;
-
-enum Capabilities : uint32_t {
-    ON_COMPLETION_CALLBACK = 1 << 0,
-    PERFORM_COMPLETION_CALLBACK = 1 << 1,
-};
+/**
+ * Extending enum separately to avoid conflicts w/ upstream.
+ */
+@Backing(type="int")
+@VintfStability
+enum VendorEffect {
+    CRACKLE,
+    WIGGLE,
+}
diff --git a/tests/extension/vibrator/aidl/client/Android.bp b/tests/extension/vibrator/aidl/client/Android.bp
new file mode 100644
index 0000000..f7b71f7
--- /dev/null
+++ b/tests/extension/vibrator/aidl/client/Android.bp
@@ -0,0 +1,26 @@
+
+// This example client is written as a test, but it is executing from a system
+// context. All this code would look the same if it was running in system
+// server for example.
+
+cc_test {
+    name: "test-vintf-vibrator-ext-client",
+    srcs: [
+         // system code has the option to use the unstable C++ libbinder API
+         // or the NDK one. For maximum code portability, using the ndk client
+         // makes the most sense, but both are provided here as an example.
+         "test-cpp-client.cpp",
+         "test-ndk-client.cpp",
+    ],
+    shared_libs: [
+         "libbinder",
+         "libutils",
+         "vintf-vibrator-cpp",
+         "test-vintf-vibrator-ext-cpp",
+
+         "libbinder_ndk",
+         "vintf-vibrator-ndk_platform",
+         "test-vintf-vibrator-ext-ndk_platform",
+    ],
+}
+
diff --git a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp b/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
new file mode 100644
index 0000000..f6f5537
--- /dev/null
+++ b/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/tests/extension/vibrator/ICustomVibrator.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+#include <gtest/gtest.h>
+
+using android::IBinder;
+using android::IInterface;
+using android::interface_cast;
+using android::OK;
+using android::sp;
+using android::waitForVintfService;
+using android::hardware::tests::extension::vibrator::Directionality;
+using android::hardware::tests::extension::vibrator::ICustomVibrator;
+using android::hardware::vibrator::IVibrator;
+
+TEST(Cpp, CallRootMethod) {
+    sp<IVibrator> vib = waitForVintfService<IVibrator>();
+    ASSERT_NE(nullptr, vib.get());
+    ASSERT_TRUE(vib->off().isOk());
+}
+
+TEST(Cpp, CallExtMethod) {
+    // normally you would want to cache this
+    sp<IVibrator> vib = waitForVintfService<IVibrator>();
+    ASSERT_NE(nullptr, vib.get());
+
+    // getting the extension
+    sp<IBinder> ext;
+    ASSERT_EQ(OK, IInterface::asBinder(vib)->getExtension(&ext));
+    sp<ICustomVibrator> cvib = interface_cast<ICustomVibrator>(ext);
+    ASSERT_NE(nullptr, cvib.get());
+
+    // calling extension method
+    ASSERT_TRUE(cvib->setDirectionality(Directionality::TRANSVERSE).isOk());
+}
diff --git a/tests/extension/vibrator/aidl/client/test-ndk-client.cpp b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
new file mode 100644
index 0000000..c846495
--- /dev/null
+++ b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/tests/extension/vibrator/ICustomVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <android/binder_manager.h>
+
+#include <gtest/gtest.h>
+
+using aidl::android::hardware::tests::extension::vibrator::Directionality;
+using aidl::android::hardware::tests::extension::vibrator::ICustomVibrator;
+using aidl::android::hardware::vibrator::IVibrator;
+using ndk::SpAIBinder;
+
+static const std::string kInstance = std::string() + IVibrator::descriptor + "/default";
+
+TEST(Ndk, CallRootMethod) {
+    SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+    ASSERT_NE(nullptr, vibBinder.get());
+    std::shared_ptr<IVibrator> vib = IVibrator::fromBinder(vibBinder);
+    ASSERT_NE(nullptr, vib.get());
+    ASSERT_TRUE(vib->off().isOk());
+}
+
+TEST(Ndk, CallExtMethod) {
+    // normally you would want to cache this
+    //
+    SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+    ASSERT_NE(nullptr, vibBinder.get());
+    std::shared_ptr<IVibrator> vib = IVibrator::fromBinder(vibBinder);
+    ASSERT_NE(nullptr, vib.get());
+
+    // getting the extension
+    SpAIBinder cvibBinder;
+    ASSERT_EQ(STATUS_OK, AIBinder_getExtension(vibBinder.get(), cvibBinder.getR()));
+    ASSERT_NE(nullptr, cvibBinder.get());
+    std::shared_ptr<ICustomVibrator> cvib = ICustomVibrator::fromBinder(cvibBinder);
+    ASSERT_NE(nullptr, cvib.get());
+
+    // calling extension method
+    ASSERT_TRUE(cvib->setDirectionality(Directionality::TRANSVERSE).isOk());
+}
diff --git a/tests/extension/vibrator/aidl/default/Android.bp b/tests/extension/vibrator/aidl/default/Android.bp
new file mode 100644
index 0000000..9869657
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/Android.bp
@@ -0,0 +1,25 @@
+cc_binary {
+    name: "android.hardware.tests.extension.vibrator-service.example",
+    relative_install_path: "hw",
+    // normally you implement a service directly, but we are using an implementation
+    // from a library to attach our extension to.
+    static_libs: [
+        "libvibratorexampleimpl",
+    ],
+
+    // need to add this in the manifest and to init as well to use, see
+    // android.hardware.vibrator-service.example. This binary is being tested
+    // by running it manually as root.
+
+    vendor: true,
+    srcs: [
+        "service.cpp",
+        "CustomVibrator.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "vintf-vibrator-ndk_platform",
+        "test-vintf-vibrator-ext-ndk_platform",
+    ],
+}
diff --git a/tests/extension/vibrator/aidl/default/CustomVibrator.cpp b/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
new file mode 100644
index 0000000..2f3dfcb
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CustomVibrator.h"
+
+#include <android-base/logging.h>
+#include <thread>
+
+namespace aidl::android::hardware::tests::extension::vibrator {
+
+ndk::ScopedAStatus CustomVibrator::getVendorCapabilities(int32_t* _aidl_return) {
+    *_aidl_return = ICustomVibrator::CAP_VENDOR_DIRECTIONALITY;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus CustomVibrator::setDirectionality(Directionality directionality) {
+    LOG(INFO) << "Custom vibrator set directionality";
+    // do something cool in hardware
+    (void)directionality;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus CustomVibrator::perform(VendorEffect effect,
+                                           const std::shared_ptr<IVibratorCallback>& callback,
+                                           int32_t* _aidl_return) {
+    LOG(INFO) << "Custom vibrator perform";
+
+    if (effect != VendorEffect::CRACKLE && effect != VendorEffect::WIGGLE) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    constexpr size_t kEffectMillis = 100;
+
+    if (callback != nullptr) {
+        std::thread([=] {
+            LOG(INFO) << "Starting vendor perform on another thread";
+            usleep(kEffectMillis * 1000);
+            LOG(INFO) << "Notifying vendor perform complete";
+            callback->onComplete();
+        }).detach();
+    }
+
+    *_aidl_return = kEffectMillis;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::tests::extension::vibrator
diff --git a/tests/extension/vibrator/aidl/default/CustomVibrator.h b/tests/extension/vibrator/aidl/default/CustomVibrator.h
new file mode 100644
index 0000000..6dc5743
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/CustomVibrator.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/tests/extension/vibrator/BnCustomVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorCallback.h>
+
+namespace aidl::android::hardware::tests::extension::vibrator {
+
+using aidl::android::hardware::vibrator::IVibratorCallback;
+
+class CustomVibrator : public BnCustomVibrator {
+    ndk::ScopedAStatus getVendorCapabilities(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus setDirectionality(Directionality directionality) override;
+    ndk::ScopedAStatus perform(VendorEffect effect,
+                               const std::shared_ptr<IVibratorCallback>& callback,
+                               int32_t* _aidl_return) override;
+};
+
+}  // namespace aidl::android::hardware::tests::extension::vibrator
diff --git a/tests/extension/vibrator/aidl/default/service.cpp b/tests/extension/vibrator/aidl/default/service.cpp
new file mode 100644
index 0000000..16290df
--- /dev/null
+++ b/tests/extension/vibrator/aidl/default/service.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vibrator-impl/Vibrator.h>
+#include "CustomVibrator.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::tests::extension::vibrator::CustomVibrator;
+using aidl::android::hardware::vibrator::Vibrator;
+
+int main() {
+    // these are threads in addition to the one we are joining below, so this
+    // service will have a single thread
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    // making the core service
+    std::shared_ptr<Vibrator> vib = ndk::SharedRefBase::make<Vibrator>();
+    ndk::SpAIBinder vibBinder = vib->asBinder();
+
+    // making the extension service
+    std::shared_ptr<CustomVibrator> cvib = ndk::SharedRefBase::make<CustomVibrator>();
+
+    // need to attach the extension to the same binder we will be registering
+    CHECK(STATUS_OK == AIBinder_setExtension(vibBinder.get(), cvib->asBinder().get()));
+
+    const std::string instance = std::string() + Vibrator::descriptor + "/default";
+    CHECK(STATUS_OK == AServiceManager_addService(vibBinder.get(), instance.c_str()));
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/vibrator/1.4/Android.bp b/vibrator/1.4/Android.bp
deleted file mode 100644
index acfc795..0000000
--- a/vibrator/1.4/Android.bp
+++ /dev/null
@@ -1,19 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-hidl_interface {
-    name: "android.hardware.vibrator@1.4",
-    root: "android.hardware",
-    srcs: [
-        "types.hal",
-        "IVibrator.hal",
-        "IVibratorCallback.hal",
-    ],
-    interfaces: [
-        "android.hardware.vibrator@1.0",
-        "android.hardware.vibrator@1.1",
-        "android.hardware.vibrator@1.2",
-        "android.hardware.vibrator@1.3",
-        "android.hidl.base@1.0",
-    ],
-    gen_java: true,
-}
diff --git a/vibrator/1.4/IVibrator.hal b/vibrator/1.4/IVibrator.hal
deleted file mode 100644
index 913abe3..0000000
--- a/vibrator/1.4/IVibrator.hal
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.vibrator@1.4;
-
-import @1.0::EffectStrength;
-import @1.3::Effect;
-import @1.0::Status;
-import @1.3::IVibrator;
-import IVibratorCallback;
-
-interface IVibrator extends @1.3::IVibrator {
-    /**
-     * Determine capabilities of the vibrator HAL.
-     */
-    getCapabilities() generates (bitfield<Capabilities> capabilities);
-
-    /**
-     * Turn on vibrator
-     *
-     * This function must only be called after the previous timeout has expired or
-     * was canceled (through off()).
-     * @param timeoutMs number of milliseconds to vibrate.
-     * @param callback A callback used to inform Frameworks of state change, if supported.
-     * @return vibratorOnRet whether vibrator command was successful or not.
-     */
-    on_1_4(uint32_t timeoutMs, IVibratorCallback callback) generates (Status vibratorOnRet);
-
-    /**
-     * Fire off a predefined haptic event.
-     *
-     * @param effect The type of haptic event to trigger.
-     * @param strength The intensity of haptic event to trigger.
-     * @param callback A callback used to inform Frameworks of state change, if supported.
-     * @return status Whether the effect was successfully performed or not. Must
-     *     return Status::UNSUPPORTED_OPERATION if the effect is not supported.
-     * @return lengthMs The length of time the event is expected to take in
-     *     milliseconds. This doesn't need to be perfectly accurate, but should be a reasonable
-     *     approximation. Should be a positive, non-zero value if the returned status is Status::OK,
-     *     and set to 0 otherwise.
-     */
-    perform_1_4(Effect effect, EffectStrength strength, IVibratorCallback callback)
-        generates (Status status, uint32_t lengthMs);
-};
diff --git a/vibrator/1.4/IVibratorCallback.hal b/vibrator/1.4/IVibratorCallback.hal
deleted file mode 100644
index 76281bc..0000000
--- a/vibrator/1.4/IVibratorCallback.hal
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.vibrator@1.4;
-
-interface IVibratorCallback {
-    oneway onComplete();
-};
diff --git a/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp b/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp
deleted file mode 100644
index 1b6abe9..0000000
--- a/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "vibrator_hidl_hal_test"
-
-#include <android-base/logging.h>
-#include <android/hardware/vibrator/1.0/types.h>
-#include <android/hardware/vibrator/1.4/IVibrator.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
-
-#include <getopt.h>
-#include <unistd.h>
-
-#include <future>
-
-using ::android::sp;
-using ::android::hardware::hidl_bitfield;
-using ::android::hardware::hidl_enum_range;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::vibrator::V1_0::EffectStrength;
-using ::android::hardware::vibrator::V1_0::Status;
-using ::android::hardware::vibrator::V1_3::Effect;
-using ::android::hardware::vibrator::V1_4::Capabilities;
-using ::android::hardware::vibrator::V1_4::IVibrator;
-using ::android::hardware::vibrator::V1_4::IVibratorCallback;
-
-static uint32_t sCompletionLimitMs = UINT32_MAX;
-
-#define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk())
-
-class CompletionCallback : public IVibratorCallback {
-  public:
-    CompletionCallback(std::function<void()> callback) : mCallback(callback) {}
-    Return<void> onComplete() override {
-        mCallback();
-        return Void();
-    }
-
-  private:
-    std::function<void()> mCallback;
-};
-
-class VibratorHidlTest_1_4 : public testing::TestWithParam<std::string> {
-  public:
-    virtual void SetUp() override {
-        vibrator = IVibrator::getService(GetParam());
-        ASSERT_NE(vibrator, nullptr);
-        capabilities = vibrator->getCapabilities();
-    }
-
-    virtual void TearDown() override {}
-
-    sp<IVibrator> vibrator;
-    hidl_bitfield<Capabilities> capabilities;
-};
-
-TEST_P(VibratorHidlTest_1_4, OnWithCallback) {
-    if (capabilities & Capabilities::ON_COMPLETION_CALLBACK) {
-        std::promise<void> completionPromise;
-        std::future<void> completionFuture{completionPromise.get_future()};
-        sp<CompletionCallback> callback =
-                new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
-        uint32_t duration = 250;
-        std::chrono::milliseconds timeout{duration * 2};
-        EXPECT_EQ(Status::OK, vibrator->on_1_4(duration, callback));
-        EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
-        vibrator->off();
-    }
-}
-
-static void validatePerformEffectUnsupportedOperation(Status status, uint32_t lengthMs) {
-    ASSERT_EQ(Status::UNSUPPORTED_OPERATION, status);
-    ASSERT_EQ(static_cast<uint32_t>(0), lengthMs)
-            << "Effects that return UNSUPPORTED_OPERATION must have a duration of zero";
-}
-
-static void validatePerformEffect(Status status, uint32_t lengthMs) {
-    ASSERT_TRUE(status == Status::OK || status == Status::UNSUPPORTED_OPERATION);
-    if (status == Status::OK) {
-        ASSERT_LT(static_cast<uint32_t>(0), lengthMs)
-                << "Effects that return OK must return a positive duration";
-    } else {
-        validatePerformEffectUnsupportedOperation(status, lengthMs);
-    }
-}
-
-/*
- * Test to make sure effects within the valid range return are either supported and return OK with
- * a valid duration, or are unsupported and return UNSUPPORTED_OPERATION with a duration of 0.
- */
-TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4) {
-    Status performStatus;
-    uint32_t performLength;
-    auto validateWrapper = [&](Status status, uint32_t lengthMs) {
-        performStatus = status;
-        performLength = lengthMs;
-        validatePerformEffect(status, lengthMs);
-    };
-    for (const auto& effect : hidl_enum_range<Effect>()) {
-        for (const auto& strength : hidl_enum_range<EffectStrength>()) {
-            std::promise<void> completionPromise;
-            std::future<void> completionFuture{completionPromise.get_future()};
-            sp<CompletionCallback> callback =
-                    new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
-            EXPECT_OK(vibrator->perform_1_4(effect, strength, callback, validateWrapper));
-            if (performStatus == Status::OK && performLength < sCompletionLimitMs &&
-                (capabilities & Capabilities::PERFORM_COMPLETION_CALLBACK)) {
-                std::chrono::milliseconds timeout{performLength * 2};
-                EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
-            }
-        }
-    }
-}
-
-/*
- * Test to make sure effect values above the valid range are rejected.
- */
-TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadEffects_AboveValidRange) {
-    Effect effect = *std::prev(hidl_enum_range<Effect>().end());
-    Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) + 1);
-    EXPECT_OK(vibrator->perform_1_4(badEffect, EffectStrength::LIGHT, nullptr,
-                                    validatePerformEffectUnsupportedOperation));
-}
-
-/*
- * Test to make sure effect values below the valid range are rejected.
- */
-TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadEffects_BelowValidRange) {
-    Effect effect = *hidl_enum_range<Effect>().begin();
-    Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) - 1);
-    EXPECT_OK(vibrator->perform_1_4(badEffect, EffectStrength::LIGHT, nullptr,
-                                    validatePerformEffectUnsupportedOperation));
-}
-
-/*
- * Test to make sure strength values above the valid range are rejected.
- */
-TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadStrength_AboveValidRange) {
-    EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
-    EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
-    EXPECT_OK(vibrator->perform_1_4(Effect::THUD, badStrength, nullptr,
-                                    validatePerformEffectUnsupportedOperation));
-}
-
-/*
- * Test to make sure strength values below the valid range are rejected.
- */
-TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadStrength_BelowValidRange) {
-    EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
-    EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
-    EXPECT_OK(vibrator->perform_1_4(Effect::THUD, badStrength, nullptr,
-                                    validatePerformEffectUnsupportedOperation));
-}
-
-INSTANTIATE_TEST_SUITE_P(
-        PerInstance, VibratorHidlTest_1_4,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
-        android::hardware::PrintInstanceNameToString);
-
-enum {
-    OPTION_COMPLETION_LIMIT_MS,
-};
-
-int main(int argc, char** argv) {
-    struct option options[] = {
-            {"completion-limit-ms", required_argument, 0, OPTION_COMPLETION_LIMIT_MS}, {}};
-
-    printf("Running main() from %s\n", __FILE__);
-    testing::InitGoogleTest(&argc, argv);
-
-    while (true) {
-        int opt = getopt_long(argc, argv, "", options, nullptr);
-        if (opt == -1) {
-            break;
-        }
-        switch (opt) {
-            case OPTION_COMPLETION_LIMIT_MS:
-                std::istringstream(optarg) >> sCompletionLimitMs;
-                break;
-            default:
-                printf("Unrecognized option\n");
-                return -EINVAL;
-        }
-    }
-
-    return RUN_ALL_TESTS();
-}
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index 18468ef..cd5439f 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -5,10 +5,5 @@
         "android/hardware/vibrator/*.aidl",
     ],
     stability: "vintf",
-    backend: {
-        java: {
-            enabled: false,
-        },
-    },
 }
 
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index f399887..dc8867f 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -1,3 +1,19 @@
+cc_library_static {
+    name: "libvibratorexampleimpl",
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "vintf-vibrator-ndk_platform",
+    ],
+    export_include_dirs: ["include"],
+    srcs: ["Vibrator.cpp"],
+    visibility: [
+         ":__subpackages__",
+         "//hardware/interfaces/tests/extension/vibrator:__subpackages__",
+    ],
+}
+
 cc_binary {
     name: "android.hardware.vibrator-service.example",
     relative_install_path: "hw",
@@ -9,5 +25,8 @@
         "libbinder_ndk",
         "vintf-vibrator-ndk_platform",
     ],
-    srcs: ["main.cpp", "Vibrator.cpp"],
+    static_libs: [
+        "libvibratorexampleimpl",
+    ],
+    srcs: ["main.cpp"],
 }
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 18be1a6..09cd234 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "Vibrator.h"
+#include "vibrator-impl/Vibrator.h"
 
 #include <android-base/logging.h>
 #include <thread>
diff --git a/vibrator/aidl/default/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
similarity index 100%
rename from vibrator/aidl/default/Vibrator.h
rename to vibrator/aidl/default/include/vibrator-impl/Vibrator.h
diff --git a/vibrator/aidl/default/main.cpp b/vibrator/aidl/default/main.cpp
index d1619ff..ebb0905 100644
--- a/vibrator/aidl/default/main.cpp
+++ b/vibrator/aidl/default/main.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "Vibrator.h"
+#include "vibrator-impl/Vibrator.h"
 
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 6fa6e7e..bf77503 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -30,6 +30,7 @@
     ],
     static_libs: [
         "android.hardware.wifi@1.0",
+        "libwifi-system-iface"
     ],
 }
 
@@ -49,8 +50,9 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
 // These tests are split out so that they can be conditioned on presence of the
@@ -66,8 +68,9 @@
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
         "android.hardware.wifi@1.0",
+        "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
 // These tests are split out so that they can be conditioned on presence of
@@ -83,6 +86,7 @@
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
         "android.hardware.wifi@1.0",
+        "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
index 9d25014..128dae5 100644
--- a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
+++ b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
@@ -14,34 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
 
-#include "wifi_hidl_test_utils.h"
-
-class WifiVtsHidlEnvironment_1_0 : public WifiHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiVtsHidlEnvironment_1_0* Instance() {
-        static WifiVtsHidlEnvironment_1_0* instance =
-            new WifiVtsHidlEnvironment_1_0;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<android::hardware::wifi::V1_0::IWifi>();
-    }
-
-   private:
-    WifiVtsHidlEnvironment_1_0() {}
-};
-
-WifiHidlEnvironment* gEnv = WifiVtsHidlEnvironment_1_0::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
\ No newline at end of file
diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
index c55221d..8be8a0c 100644
--- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -16,35 +16,37 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiApIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
 
+using ::android::sp;
 using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiApIface;
 using ::android::hardware::wifi::V1_0::WifiBand;
 using ::android::hardware::wifi::V1_0::WifiStatusCode;
-using ::android::sp;
 
 /**
  * Fixture to use for all AP Iface HIDL interface tests.
  */
-class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_ap_iface_ = getWifiApIface();
+        wifi_ap_iface_ = getWifiApIface(GetInstanceName());
         ASSERT_NE(nullptr, wifi_ap_iface_.get());
     }
 
-    virtual void TearDown() override {
-        stopWifi();
-    }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     sp<IWifiApIface> wifi_ap_iface_;
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -52,16 +54,15 @@
  * Ensures that an instance of the IWifiApIface proxy object is
  * successfully created.
  */
-TEST(WifiApIfaceHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiApIface().get());
-    stopWifi();
+TEST_P(WifiApIfaceHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
 
 /*
  * GetType:
  * Ensures that the correct interface type is returned for AP interface.
  */
-TEST_F(WifiApIfaceHidlTest, GetType) {
+TEST_P(WifiApIfaceHidlTest, GetType) {
     const auto& status_and_type = HIDL_INVOKE(wifi_ap_iface_, getType);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code);
     EXPECT_EQ(IfaceType::AP, status_and_type.second);
@@ -72,7 +73,7 @@
  * Ensures that a call to set the country code will return with a success
  * status code.
  */
-TEST_F(WifiApIfaceHidlTest, SetCountryCode) {
+TEST_P(WifiApIfaceHidlTest, SetCountryCode) {
     const android::hardware::hidl_array<int8_t, 2> kCountryCode{
         std::array<int8_t, 2>{{0x55, 0x53}}};
     EXPECT_EQ(WifiStatusCode::SUCCESS,
@@ -83,9 +84,15 @@
  * GetValidFrequenciesForBand:
  * Ensures that we can retrieve valid frequencies for 2.4 GHz band.
  */
-TEST_F(WifiApIfaceHidlTest, GetValidFrequenciesForBand) {
+TEST_P(WifiApIfaceHidlTest, GetValidFrequenciesForBand) {
     const auto& status_and_freqs = HIDL_INVOKE(
         wifi_ap_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code);
     EXPECT_GT(status_and_freqs.second.size(), 0u);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiApIfaceHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
index 232ffdd..33817d5 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
@@ -16,9 +16,11 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -26,6 +28,7 @@
 using ::android::sp;
 using ::android::hardware::wifi::V1_0::ChipModeId;
 using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiApIface;
 using ::android::hardware::wifi::V1_0::IWifiChip;
 using ::android::hardware::wifi::V1_0::IWifiIface;
@@ -35,14 +38,14 @@
 /**
  * Fixture for IWifiChip tests that are conditioned on SoftAP support.
  */
-class WifiChipHidlApTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlApTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_chip_ = getWifiChip();
+        wifi_chip_ = getWifiChip(GetInstanceName());
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     // Helper function to configure the Chip in one of the supported modes.
@@ -72,6 +75,9 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -79,7 +85,7 @@
  * Configures the chip in AP mode and ensures that at least 1 iface creation
  * succeeds.
  */
-TEST_F(WifiChipHidlApTest, CreateApIface) {
+TEST_P(WifiChipHidlApTest, CreateApIface) {
     configureChipForIfaceType(IfaceType::AP, true);
 
     sp<IWifiApIface> iface;
@@ -93,7 +99,7 @@
  * before creating the iface. Then, create the iface and ensure that
  * iface name is returned via the list.
  */
-TEST_F(WifiChipHidlApTest, GetApIfaceNames) {
+TEST_P(WifiChipHidlApTest, GetApIfaceNames) {
     configureChipForIfaceType(IfaceType::AP, true);
 
     const auto& status_and_iface_names1 =
@@ -125,7 +131,7 @@
  * the iface object using the correct name and ensure any other name
  * doesn't retrieve an iface object.
  */
-TEST_F(WifiChipHidlApTest, GetApIface) {
+TEST_P(WifiChipHidlApTest, GetApIface) {
     configureChipForIfaceType(IfaceType::AP, true);
 
     sp<IWifiApIface> ap_iface;
@@ -151,7 +157,7 @@
  * the iface object using the correct name and ensure any other name
  * doesn't remove the iface.
  */
-TEST_F(WifiChipHidlApTest, RemoveApIface) {
+TEST_P(WifiChipHidlApTest, RemoveApIface) {
     configureChipForIfaceType(IfaceType::AP, true);
 
     sp<IWifiApIface> ap_iface;
@@ -166,3 +172,9 @@
     // No such iface exists now. So, this should return failure.
     EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name));
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlApTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
index 595f23a..95f223d 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
@@ -16,9 +16,11 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -26,6 +28,7 @@
 using ::android::sp;
 using ::android::hardware::wifi::V1_0::ChipModeId;
 using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiChip;
 using ::android::hardware::wifi::V1_0::IWifiIface;
 using ::android::hardware::wifi::V1_0::IWifiNanIface;
@@ -35,14 +38,14 @@
 /**
  * Fixture for IWifiChip tests that are conditioned on NAN support.
  */
-class WifiChipHidlNanTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlNanTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_chip_ = getWifiChip();
+        wifi_chip_ = getWifiChip(GetInstanceName());
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     // Helper function to configure the Chip in one of the supported modes.
@@ -72,6 +75,9 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -79,7 +85,7 @@
  * Configures the chip in NAN mode and ensures that at least 1 iface creation
  * succeeds.
  */
-TEST_F(WifiChipHidlNanTest, CreateNanIface) {
+TEST_P(WifiChipHidlNanTest, CreateNanIface) {
     configureChipForIfaceType(IfaceType::NAN, true);
 
     sp<IWifiNanIface> iface;
@@ -93,7 +99,7 @@
  * before creating the iface. Then, create the iface and ensure that
  * iface name is returned via the list.
  */
-TEST_F(WifiChipHidlNanTest, GetNanIfaceNames) {
+TEST_P(WifiChipHidlNanTest, GetNanIfaceNames) {
     configureChipForIfaceType(IfaceType::NAN, true);
 
     const auto& status_and_iface_names1 =
@@ -125,7 +131,7 @@
  * the iface object using the correct name and ensure any other name
  * doesn't retrieve an iface object.
  */
-TEST_F(WifiChipHidlNanTest, GetNanIface) {
+TEST_P(WifiChipHidlNanTest, GetNanIface) {
     configureChipForIfaceType(IfaceType::NAN, true);
 
     sp<IWifiNanIface> nan_iface;
@@ -151,7 +157,7 @@
  * the iface object using the correct name and ensure any other name
  * doesn't remove the iface.
  */
-TEST_F(WifiChipHidlNanTest, RemoveNanIface) {
+TEST_P(WifiChipHidlNanTest, RemoveNanIface) {
     configureChipForIfaceType(IfaceType::NAN, true);
 
     sp<IWifiNanIface> nan_iface;
@@ -167,3 +173,9 @@
     // No such iface exists now. So, this should return failure.
     EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name));
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlNanTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
index 2601b78..ec96fcf 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -16,10 +16,12 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiChip.h>
 #include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -27,19 +29,20 @@
 using ::android::sp;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
-using ::android::hardware::wifi::V1_0::IfaceType;
 using ::android::hardware::wifi::V1_0::ChipId;
 using ::android::hardware::wifi::V1_0::ChipModeId;
-using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus;
-using ::android::hardware::wifi::V1_0::WifiDebugRingBufferVerboseLevel;
-using ::android::hardware::wifi::V1_0::WifiDebugHostWakeReasonStats;
-using ::android::hardware::wifi::V1_0::WifiStatus;
-using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiChip;
 using ::android::hardware::wifi::V1_0::IWifiIface;
 using ::android::hardware::wifi::V1_0::IWifiP2pIface;
 using ::android::hardware::wifi::V1_0::IWifiRttController;
 using ::android::hardware::wifi::V1_0::IWifiStaIface;
+using ::android::hardware::wifi::V1_0::WifiDebugHostWakeReasonStats;
+using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus;
+using ::android::hardware::wifi::V1_0::WifiDebugRingBufferVerboseLevel;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
 
 extern WifiHidlEnvironment* gEnv;
 
@@ -67,14 +70,14 @@
  * Tests that require SoftAP or NAN support should go into WifiChipHidlApTest or
  * WifiChipHidlNanTest respectively.
  */
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_chip_ = getWifiChip();
+        wifi_chip_ = getWifiChip(GetInstanceName());
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     // Helper function to configure the Chip in one of the supported modes.
@@ -136,6 +139,9 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -143,15 +149,14 @@
  * Ensures that an instance of the IWifiChip proxy object is
  * successfully created.
  */
-TEST(WifiChipHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiChip().get());
-    stopWifi();
+TEST_P(WifiChipHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
 
 /*
  * GetId:
  */
-TEST_F(WifiChipHidlTest, GetId) {
+TEST_P(WifiChipHidlTest, GetId) {
     EXPECT_EQ(WifiStatusCode::SUCCESS,
               HIDL_INVOKE(wifi_chip_, getId).first.code);
 }
@@ -159,7 +164,7 @@
 /*
  * GetAvailableMode:
  */
-TEST_F(WifiChipHidlTest, GetAvailableModes) {
+TEST_P(WifiChipHidlTest, GetAvailableModes) {
     const auto& status_and_modes = HIDL_INVOKE(wifi_chip_, getAvailableModes);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_modes.first.code);
     EXPECT_LT(0u, status_and_modes.second.size());
@@ -168,17 +173,17 @@
 /*
  * ConfigureChip:
  */
-TEST_F(WifiChipHidlTest, ConfigureChip) {
+TEST_P(WifiChipHidlTest, ConfigureChip) {
     const auto& status_and_modes = HIDL_INVOKE(wifi_chip_, getAvailableModes);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_modes.first.code);
     EXPECT_LT(0u, status_and_modes.second.size());
     for (const auto& mode : status_and_modes.second) {
         // configureChip() requires to be called with a fresh IWifiChip object.
-        wifi_chip_ = getWifiChip();
+        wifi_chip_ = getWifiChip(GetInstanceName());
         ASSERT_NE(nullptr, wifi_chip_.get());
         EXPECT_EQ(WifiStatusCode::SUCCESS,
                   HIDL_INVOKE(wifi_chip_, configureChip, mode.id).code);
-        stopWifi();
+        stopWifi(GetInstanceName());
         // Sleep for 5 milliseconds between each wifi state toggle.
         usleep(5000);
     }
@@ -187,7 +192,7 @@
 /*
  * GetCapabilities:
  */
-TEST_F(WifiChipHidlTest, GetCapabilities) {
+TEST_P(WifiChipHidlTest, GetCapabilities) {
     configureChipForIfaceType(IfaceType::STA, true);
     const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities);
     if (status_and_caps.first.code != WifiStatusCode::SUCCESS) {
@@ -200,7 +205,7 @@
 /*
  * GetMode:
  */
-TEST_F(WifiChipHidlTest, GetMode) {
+TEST_P(WifiChipHidlTest, GetMode) {
     ChipModeId chip_mode_id = configureChipForIfaceType(IfaceType::STA, true);
     const auto& status_and_mode = HIDL_INVOKE(wifi_chip_, getMode);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mode.first.code);
@@ -210,7 +215,7 @@
 /*
  * RequestChipDebugInfo:
  */
-TEST_F(WifiChipHidlTest, RequestChipDebugInfo) {
+TEST_P(WifiChipHidlTest, RequestChipDebugInfo) {
     configureChipForIfaceType(IfaceType::STA, true);
     const auto& status_and_chip_info =
         HIDL_INVOKE(wifi_chip_, requestChipDebugInfo);
@@ -222,7 +227,7 @@
 /*
  * RequestFirmwareDebugDump
  */
-TEST_F(WifiChipHidlTest, RequestFirmwareDebugDump) {
+TEST_P(WifiChipHidlTest, RequestFirmwareDebugDump) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status_and_firmware_dump =
         HIDL_INVOKE(wifi_chip_, requestFirmwareDebugDump);
@@ -237,7 +242,7 @@
 /*
  * RequestDriverDebugDump
  */
-TEST_F(WifiChipHidlTest, RequestDriverDebugDump) {
+TEST_P(WifiChipHidlTest, RequestDriverDebugDump) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status_and_driver_dump =
         HIDL_INVOKE(wifi_chip_, requestDriverDebugDump);
@@ -254,7 +259,7 @@
 /*
  * GetDebugRingBuffersStatus
  */
-TEST_F(WifiChipHidlTest, GetDebugRingBuffersStatus) {
+TEST_P(WifiChipHidlTest, GetDebugRingBuffersStatus) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status_and_ring_buffer_status =
         HIDL_INVOKE(wifi_chip_, getDebugRingBuffersStatus);
@@ -273,7 +278,7 @@
 /*
  * StartLoggingToDebugRingBuffer
  */
-TEST_F(WifiChipHidlTest, StartLoggingToDebugRingBuffer) {
+TEST_P(WifiChipHidlTest, StartLoggingToDebugRingBuffer) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     std::string ring_name;
     const auto& status_and_ring_buffer_status =
@@ -301,7 +306,7 @@
 /*
  * ForceDumpToDebugRingBuffer
  */
-TEST_F(WifiChipHidlTest, ForceDumpToDebugRingBuffer) {
+TEST_P(WifiChipHidlTest, ForceDumpToDebugRingBuffer) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     std::string ring_name;
     const auto& status_and_ring_buffer_status =
@@ -327,7 +332,7 @@
 /*
  * GetDebugHostWakeReasonStats
  */
-TEST_F(WifiChipHidlTest, GetDebugHostWakeReasonStats) {
+TEST_P(WifiChipHidlTest, GetDebugHostWakeReasonStats) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status_and_debug_wake_reason =
         HIDL_INVOKE(wifi_chip_, getDebugHostWakeReasonStats);
@@ -345,7 +350,7 @@
  * Configures the chip in P2P mode and ensures that at least 1 iface creation
  * succeeds.
  */
-TEST_F(WifiChipHidlTest, CreateP2pIface) {
+TEST_P(WifiChipHidlTest, CreateP2pIface) {
     configureChipForIfaceType(IfaceType::P2P, true);
 
     sp<IWifiP2pIface> iface;
@@ -359,7 +364,7 @@
  * before creating the iface. Then, create the iface and ensure that
  * iface name is returned via the list.
  */
-TEST_F(WifiChipHidlTest, GetP2pIfaceNames) {
+TEST_P(WifiChipHidlTest, GetP2pIfaceNames) {
     configureChipForIfaceType(IfaceType::P2P, true);
 
     const auto& status_and_iface_names1 =
@@ -391,7 +396,7 @@
  * the iface object using the correct name and ensure any other name
  * doesn't retrieve an iface object.
  */
-TEST_F(WifiChipHidlTest, GetP2pIface) {
+TEST_P(WifiChipHidlTest, GetP2pIface) {
     configureChipForIfaceType(IfaceType::P2P, true);
 
     sp<IWifiP2pIface> p2p_iface;
@@ -417,7 +422,7 @@
  * the iface object using the correct name and ensure any other name
  * doesn't remove the iface.
  */
-TEST_F(WifiChipHidlTest, RemoveP2pIface) {
+TEST_P(WifiChipHidlTest, RemoveP2pIface) {
     configureChipForIfaceType(IfaceType::P2P, true);
 
     sp<IWifiP2pIface> p2p_iface;
@@ -438,7 +443,7 @@
  * Configures the chip in STA mode and ensures that at least 1 iface creation
  * succeeds.
  */
-TEST_F(WifiChipHidlTest, CreateStaIface) {
+TEST_P(WifiChipHidlTest, CreateStaIface) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     sp<IWifiStaIface> iface;
@@ -452,7 +457,7 @@
  * before creating the iface. Then, create the iface and ensure that
  * iface name is returned via the list.
  */
-TEST_F(WifiChipHidlTest, GetStaIfaceNames) {
+TEST_P(WifiChipHidlTest, GetStaIfaceNames) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     const auto& status_and_iface_names1 =
@@ -484,7 +489,7 @@
  * the iface object using the correct name and ensure any other name
  * doesn't retrieve an iface object.
  */
-TEST_F(WifiChipHidlTest, GetStaIface) {
+TEST_P(WifiChipHidlTest, GetStaIface) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     sp<IWifiStaIface> sta_iface;
@@ -510,7 +515,7 @@
  * the iface object using the correct name and ensure any other name
  * doesn't remove the iface.
  */
-TEST_F(WifiChipHidlTest, RemoveStaIface) {
+TEST_P(WifiChipHidlTest, RemoveStaIface) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     sp<IWifiStaIface> sta_iface;
@@ -529,7 +534,7 @@
 /*
  * CreateRttController
  */
-TEST_F(WifiChipHidlTest, CreateRttController) {
+TEST_P(WifiChipHidlTest, CreateRttController) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     sp<IWifiStaIface> iface;
@@ -541,3 +546,9 @@
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_rtt_controller.first.code);
     EXPECT_NE(nullptr, status_and_rtt_controller.second.get());
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
index b8e501c..512701a 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
@@ -18,7 +18,9 @@
 
 #include <android/hardware/wifi/1.0/IWifi.h>
 
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_test_utils.h"
 
@@ -28,13 +30,14 @@
 /**
  * Fixture to use for all root Wifi HIDL interface tests.
  */
-class WifiHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {}
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -42,7 +45,12 @@
  * Ensures that an instance of the IWifi proxy object is
  * successfully created.
  */
-TEST(WifiHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifi().get());
-    stopWifi();
+TEST_P(WifiHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index f89f7b4..d584d4b 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -18,12 +18,15 @@
 
 #include <VtsHalHidlTargetTestBase.h>
 
+#include <wifi_system/interface_tool.h>
+
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
 
 using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiApIface;
 using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::V1_0::IWifiIface;
 using ::android::hardware::wifi::V1_0::IWifiNanIface;
 using ::android::hardware::wifi::V1_0::IWifiP2pIface;
 using ::android::hardware::wifi::V1_0::IWifiRttController;
@@ -36,6 +39,7 @@
 using ::android::sp;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
+using ::android::wifi_system::InterfaceTool;
 
 extern WifiHidlEnvironment* gEnv;
 
@@ -131,6 +135,16 @@
     return status_and_chip.second;
 }
 
+void setIfaceUp(const sp<IWifiIface>& iface) {
+    // Set the iface up before retrurning the object.
+    const auto& status_and_name = HIDL_INVOKE(iface, getName);
+    if (status_and_name.first.code == WifiStatusCode::SUCCESS) {
+        const auto& iface_name = status_and_name.second;
+        InterfaceTool iface_tool;
+        iface_tool.SetUpState(iface_name.c_str(), true);
+    }
+}
+
 sp<IWifiApIface> getWifiApIface(const std::string& instance_name) {
     sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
     if (!wifi_chip.get()) {
@@ -143,6 +157,7 @@
     if (status_and_iface.first.code != WifiStatusCode::SUCCESS) {
         return nullptr;
     }
+    setIfaceUp(status_and_iface.second);
     return status_and_iface.second;
 }
 
@@ -158,6 +173,7 @@
     if (status_and_iface.first.code != WifiStatusCode::SUCCESS) {
         return nullptr;
     }
+    setIfaceUp(status_and_iface.second);
     return status_and_iface.second;
 }
 
@@ -173,6 +189,7 @@
     if (status_and_iface.first.code != WifiStatusCode::SUCCESS) {
         return nullptr;
     }
+    setIfaceUp(status_and_iface.second);
     return status_and_iface.second;
 }
 
@@ -188,6 +205,7 @@
     if (status_and_iface.first.code != WifiStatusCode::SUCCESS) {
         return nullptr;
     }
+    setIfaceUp(status_and_iface.second);
     return status_and_iface.second;
 }
 
@@ -196,7 +214,7 @@
     if (!wifi_chip.get()) {
         return nullptr;
     }
-    sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface();
+    sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface(instance_name);
     if (!wifi_sta_iface.get()) {
         return nullptr;
     }
diff --git a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
index 64b4fb6..422e3f6 100644
--- a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -16,10 +16,12 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiNanIface.h>
 #include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -29,27 +31,28 @@
 
 using namespace ::android::hardware::wifi::V1_0;
 
+using ::android::sp;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::sp;
+using ::android::hardware::wifi::V1_0::IWifi;
 
 #define TIMEOUT_PERIOD 10
 
 /**
  * Fixture to use for all NAN Iface HIDL interface tests.
  */
-class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-  public:
+class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+   public:
     virtual void SetUp() override {
-      iwifiNanIface = getWifiNanIface();
-      ASSERT_NE(nullptr, iwifiNanIface.get());
-      ASSERT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, registerEventCallback,
-            new WifiNanIfaceEventCallback(*this)).code);
+        iwifiNanIface = getWifiNanIface(GetInstanceName());
+        ASSERT_NE(nullptr, iwifiNanIface.get());
+        ASSERT_EQ(WifiStatusCode::SUCCESS,
+                  HIDL_INVOKE(iwifiNanIface, registerEventCallback,
+                              new WifiNanIfaceEventCallback(*this))
+                      .code);
     }
 
-    virtual void TearDown() override {
-      stopWifi();
-    }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
     /* Used as a mechanism to inform the test about data/event callback */
     inline void notify() {
@@ -438,6 +441,8 @@
       NanFollowupReceivedInd nanFollowupReceivedInd;
       NanDataPathRequestInd nanDataPathRequestInd;
       NanDataPathConfirmInd nanDataPathConfirmInd;
+
+      std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -445,9 +450,8 @@
  * Ensures that an instance of the IWifiNanIface proxy object is
  * successfully created.
  */
-TEST(WifiNanIfaceHidlTestNoFixture, Create) {
-  ASSERT_NE(nullptr, getWifiNanIface().get());
-  stopWifi();
+TEST_P(WifiNanIfaceHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
 
 /*
@@ -455,41 +459,51 @@
  * Ensure that API calls fail with ERROR_WIFI_IFACE_INVALID when using an interface once wifi
  * is disabled.
  */
-TEST(WifiNanIfaceHidlTestNoFixture, FailOnIfaceInvalid) {
-  android::sp<IWifiNanIface> iwifiNanIface = getWifiNanIface();
-  ASSERT_NE(nullptr, iwifiNanIface.get());
-  stopWifi();
-  sleep(5); // make sure that all chips/interfaces are invalidated
-  ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-          HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code);
+TEST_P(WifiNanIfaceHidlTest, FailOnIfaceInvalid) {
+    stopWifi(GetInstanceName());
+    android::sp<IWifiNanIface> iwifiNanIface =
+        getWifiNanIface(GetInstanceName());
+    ASSERT_NE(nullptr, iwifiNanIface.get());
+    stopWifi(GetInstanceName());
+    sleep(5);  // make sure that all chips/interfaces are invalidated
+    ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+              HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code);
 }
 
 /*
  * getCapabilitiesRequest: validate that returns capabilities.
  */
-TEST_F(WifiNanIfaceHidlTest, getCapabilitiesRequest) {
-  uint16_t inputCmdId = 10;
-  callbackType = INVALID;
-  ASSERT_EQ(WifiStatusCode::SUCCESS,
+TEST_P(WifiNanIfaceHidlTest, getCapabilitiesRequest) {
+    uint16_t inputCmdId = 10;
+    callbackType = INVALID;
+    ASSERT_EQ(
+        WifiStatusCode::SUCCESS,
         HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, inputCmdId).code);
-  // wait for a callback
-  ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
-  ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType);
-  ASSERT_EQ(id, inputCmdId);
+    // wait for a callback
+    ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
+    ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType);
+    ASSERT_EQ(id, inputCmdId);
 
-  // check for reasonable capability values
-  EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxPublishes, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxSubscribes, (unsigned int) 0);
-  EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int) 255);
-  EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int) 255);
-  EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int) 255);
-  EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int) 255);
-  EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen, (unsigned int) 255);
-  EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxNdpSessions, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int) 0);
-  EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int) 0);
+    // check for reasonable capability values
+    EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int)0);
+    EXPECT_GT(capabilities.maxPublishes, (unsigned int)0);
+    EXPECT_GT(capabilities.maxSubscribes, (unsigned int)0);
+    EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int)255);
+    EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int)255);
+    EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int)255);
+    EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int)255);
+    EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen,
+              (unsigned int)255);
+    EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int)0);
+    EXPECT_GT(capabilities.maxNdpSessions, (unsigned int)0);
+    EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int)0);
+    EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int)0);
+    EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int)0);
+    EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int)0);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiNanIfaceHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
index 269eb6c..8f33271 100644
--- a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
@@ -16,25 +16,29 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiP2pIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_test_utils.h"
 
-using ::android::hardware::wifi::V1_0::IWifiP2pIface;
 using ::android::sp;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiP2pIface;
 
 /**
  * Fixture to use for all P2P Iface HIDL interface tests.
  */
-class WifiP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiP2pIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {}
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -42,7 +46,13 @@
  * Ensures that an instance of the IWifiP2pIface proxy object is
  * successfully created.
  */
-TEST(WifiP2pIfaceHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiP2pIface().get());
-    stopWifi();
+TEST_P(WifiP2pIfaceHidlTest, Create) {
+    stopWifi(GetInstanceName());
+    EXPECT_NE(nullptr, getWifiP2pIface(GetInstanceName()).get());
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiP2pIfaceHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
index e13086d..e1ee34f 100644
--- a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -16,25 +16,29 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiRttController.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_test_utils.h"
 
-using ::android::hardware::wifi::V1_0::IWifiRttController;
 using ::android::sp;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiRttController;
 
 /**
  * Fixture to use for all RTT controller HIDL interface tests.
  */
-class WifiRttControllerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiRttControllerHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {}
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -42,7 +46,13 @@
  * Ensures that an instance of the IWifiRttController proxy object is
  * successfully created.
  */
-TEST(WifiRttControllerHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiRttController().get());
-    stopWifi();
+TEST_P(WifiRttControllerHidlTest, Create) {
+    stopWifi(GetInstanceName());
+    EXPECT_NE(nullptr, getWifiRttController(GetInstanceName()).get());
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiRttControllerHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
index a413863..30b6fba 100644
--- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -16,10 +16,12 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiStaIface.h>
 #include <android/hardware/wifi/1.3/IWifiStaIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -28,6 +30,7 @@
 using ::android::hardware::wifi::V1_0::Bssid;
 using ::android::hardware::wifi::V1_0::CommandId;
 using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiStaIface;
 using ::android::hardware::wifi::V1_0::Rssi;
 using ::android::hardware::wifi::V1_0::Ssid;
@@ -41,14 +44,14 @@
 /**
  * Fixture to use for all STA Iface HIDL interface tests.
  */
-class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_sta_iface_ = getWifiStaIface();
+        wifi_sta_iface_ = getWifiStaIface(GetInstanceName());
         ASSERT_NE(nullptr, wifi_sta_iface_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
@@ -59,6 +62,7 @@
     }
 
     sp<IWifiStaIface> wifi_sta_iface_;
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -66,15 +70,14 @@
  * Ensures that an instance of the IWifiStaIface proxy object is
  * successfully created.
  */
-TEST(WifiStaIfaceHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiStaIface().get());
-    stopWifi();
+TEST_P(WifiStaIfaceHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
 
 /*
  * GetCapabilities:
  */
-TEST_F(WifiStaIfaceHidlTest, GetCapabilities) {
+TEST_P(WifiStaIfaceHidlTest, GetCapabilities) {
     const auto& status_and_caps = HIDL_INVOKE(wifi_sta_iface_, getCapabilities);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
     EXPECT_GT(status_and_caps.second, 0u);
@@ -84,7 +87,7 @@
  * GetType:
  * Ensures that the correct interface type is returned for station interface.
  */
-TEST_F(WifiStaIfaceHidlTest, GetType) {
+TEST_P(WifiStaIfaceHidlTest, GetType) {
     const auto& status_and_type = HIDL_INVOKE(wifi_sta_iface_, getType);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code);
     EXPECT_EQ(IfaceType::STA, status_and_type.second);
@@ -94,7 +97,7 @@
  * GetApfPacketFilterCapabilities:
  * Ensures that we can retrieve APF packet filter capabilites.
  */
-TEST_F(WifiStaIfaceHidlTest, GetApfPacketFilterCapabilities) {
+TEST_P(WifiStaIfaceHidlTest, GetApfPacketFilterCapabilities) {
     if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) {
         // No-op if APF packet filer is not supported.
         return;
@@ -109,7 +112,7 @@
  * GetBackgroundScanCapabilities:
  * Ensures that we can retrieve background scan capabilities.
  */
-TEST_F(WifiStaIfaceHidlTest, GetBackgroundScanCapabilities) {
+TEST_P(WifiStaIfaceHidlTest, GetBackgroundScanCapabilities) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::BACKGROUND_SCAN)) {
         // No-op if background scan is not supported.
@@ -125,7 +128,7 @@
  * GetValidFrequenciesForBand:
  * Ensures that we can retrieve valid frequencies for 2.4 GHz band.
  */
-TEST_F(WifiStaIfaceHidlTest, GetValidFrequenciesForBand) {
+TEST_P(WifiStaIfaceHidlTest, GetValidFrequenciesForBand) {
     const auto& status_and_freqs = HIDL_INVOKE(
         wifi_sta_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code);
@@ -137,7 +140,7 @@
  * Ensures that calls to enable, disable, and retrieve link layer stats
  * will return a success status code.
  */
-TEST_F(WifiStaIfaceHidlTest, LinkLayerStatsCollection) {
+TEST_P(WifiStaIfaceHidlTest, LinkLayerStatsCollection) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
         // No-op if link layer stats is not supported.
@@ -172,7 +175,7 @@
  * Ensures that calls to disable RSSI monitoring will return an error status
  * code if RSSI monitoring is not enabled.
  */
-TEST_F(WifiStaIfaceHidlTest, RSSIMonitoring) {
+TEST_P(WifiStaIfaceHidlTest, RSSIMonitoring) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::RSSI_MONITOR)) {
         // No-op if RSSI monitor is not supported.
@@ -197,7 +200,7 @@
  * Ensures that calls to configure and enable roaming will return a success
  * status code.
  */
-TEST_F(WifiStaIfaceHidlTest, RoamingControl) {
+TEST_P(WifiStaIfaceHidlTest, RoamingControl) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::CONTROL_ROAMING)) {
         // No-op if roaming control is not supported.
@@ -242,9 +245,9 @@
  * Ensures that calls to enable neighbor discovery offload will return a success
  * status code.
  */
-TEST_F(WifiStaIfaceHidlTest, EnableNDOffload) {
-   if (!isCapabilitySupported(
-           IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) {
+TEST_P(WifiStaIfaceHidlTest, EnableNDOffload) {
+    if (!isCapabilitySupported(
+            IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) {
         // No-op if nd offload is not supported.
         return;
     }
@@ -257,7 +260,7 @@
  * Ensures that calls to set scanning MAC OUI will return a success status
  * code.
  */
-TEST_F(WifiStaIfaceHidlTest, SetScanningMacOui) {
+TEST_P(WifiStaIfaceHidlTest, SetScanningMacOui) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::SCAN_RAND)) {
         // No-op if SetScanningMacOui is not supported.
@@ -274,9 +277,9 @@
  * Ensures that calls to start packet fate monitoring and retrieve TX/RX
  * packets will return a success status code.
  */
-TEST_F(WifiStaIfaceHidlTest, PacketFateMonitoring) {
-   if (!isCapabilitySupported(
-           IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) {
+TEST_P(WifiStaIfaceHidlTest, PacketFateMonitoring) {
+    if (!isCapabilitySupported(
+            IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) {
         // No-op if packet fate monitor is not supported.
         return;
     }
@@ -291,3 +294,9 @@
     EXPECT_EQ(WifiStatusCode::SUCCESS,
               HIDL_INVOKE(wifi_sta_iface_, getDebugRxPacketFates).first.code);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiStaIfaceHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp
index 6662314..775031e 100644
--- a/wifi/1.1/vts/functional/Android.bp
+++ b/wifi/1.1/vts/functional/Android.bp
@@ -26,6 +26,7 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
index 673fed3..4b62b15 100644
--- a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
+++ b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
@@ -14,34 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.1/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
 
-#include "wifi_hidl_test_utils.h"
-
-class WifiHidlEnvironment_1_1 : public WifiHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiHidlEnvironment_1_1* Instance() {
-        static WifiHidlEnvironment_1_1* instance = new WifiHidlEnvironment_1_1;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<android::hardware::wifi::V1_1::IWifi>();
-    }
-
-   private:
-    WifiHidlEnvironment_1_1() {}
-};
-
-WifiHidlEnvironment* gEnv = WifiHidlEnvironment_1_1::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
diff --git a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
index 6323547..08de240 100644
--- a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
@@ -19,8 +19,9 @@
 #include <android/hardware/wifi/1.1/IWifi.h>
 #include <android/hardware/wifi/1.1/IWifiChip.h>
 #include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -45,14 +46,14 @@
 /**
  * Fixture to use for all Wifi chip HIDL interface tests.
  */
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_chip_ = IWifiChip::castFrom(getWifiChip());
+        wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     uint32_t configureChipForStaIfaceAndGetCapabilities() {
@@ -77,12 +78,15 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
  * SelectTxPowerScenario
  */
-TEST_F(WifiChipHidlTest, SelectTxPowerScenario) {
+TEST_P(WifiChipHidlTest, SelectTxPowerScenario) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, selectTxPowerScenario, kFakePowerScenario);
@@ -96,7 +100,7 @@
 /*
  * ResetTxPowerScenario
  */
-TEST_F(WifiChipHidlTest, ResetTxPowerScenario) {
+TEST_P(WifiChipHidlTest, ResetTxPowerScenario) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, resetTxPowerScenario);
@@ -106,3 +110,9 @@
         EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
     }
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp
index b2956ce..f43e49e 100644
--- a/wifi/1.2/vts/functional/Android.bp
+++ b/wifi/1.2/vts/functional/Android.bp
@@ -28,8 +28,10 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    disable_framework: true,
+    test_suites: ["general-tests", "vts-core"],
 }
 
 cc_test {
@@ -44,6 +46,8 @@
         "android.hardware.wifi@1.0",
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
+        "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    disable_framework: true,
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp b/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
index c765cdc..52c7a4a 100644
--- a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
+++ b/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
@@ -14,35 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.2/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
 
-#include "wifi_hidl_test_utils.h"
-
-using ::android::hardware::wifi::V1_2::IWifi;
-
-// Test environment for Wifi HIDL HAL.
-class WifiHidlEnvironment_1_2 : public WifiHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiHidlEnvironment_1_2* Instance() {
-        static WifiHidlEnvironment_1_2* instance = new WifiHidlEnvironment_1_2;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IWifi>(); }
-
-   private:
-    WifiHidlEnvironment_1_2() {}
-};
-
-WifiHidlEnvironment_1_2* gEnv = WifiHidlEnvironment_1_2::Instance();
-
-int main(int argc, char** argv) {
-  ::testing::AddGlobalTestEnvironment(gEnv);
-  ::testing::InitGoogleTest(&argc, argv);
-  gEnv->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
\ No newline at end of file
diff --git a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
index 9d567fe..47faec8 100644
--- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
@@ -16,12 +16,14 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.2/IWifi.h>
 #include <android/hardware/wifi/1.2/IWifiChip.h>
 #include <android/hardware/wifi/1.2/IWifiChipEventCallback.h>
 #include <android/hardware/wifi/1.3/IWifiChip.h>
-
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -50,14 +52,14 @@
 /**
  * Fixture to use for all Wifi chip HIDL interface tests.
  */
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-    wifi_chip_ = IWifiChip::castFrom(getWifiChip());
+    wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
     ASSERT_NE(nullptr, wifi_chip_.get());
   }
 
-  virtual void TearDown() override { stopWifi(); }
+  virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
   // A simple test implementation of WifiChipEventCallback.
   class WifiChipEventCallback
@@ -123,6 +125,9 @@
   }
 
   sp<IWifiChip> wifi_chip_;
+
+ private:
+  std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -130,7 +135,7 @@
  * This test case tests the selectTxPowerScenario_1_2() API with SAR scenarios
  * newly defined in 1.2
  */
-TEST_F(WifiChipHidlTest, SelectTxPowerScenario_1_2_body) {
+TEST_P(WifiChipHidlTest, SelectTxPowerScenario_1_2_body) {
   uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
   const auto& status =
       HIDL_INVOKE(wifi_chip_, selectTxPowerScenario_1_2, kPowerScenarioBody);
@@ -147,7 +152,7 @@
  * This test case tests the selectTxPowerScenario_1_2() API with previously
  * defined SAR scenarios
  */
-TEST_F(WifiChipHidlTest, SelectTxPowerScenario_1_2_voiceCall) {
+TEST_P(WifiChipHidlTest, SelectTxPowerScenario_1_2_voiceCall) {
   uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
   const auto& status =
       HIDL_INVOKE(wifi_chip_, selectTxPowerScenario_1_2, kPowerScenarioVoiceCall);
@@ -167,9 +172,15 @@
  * since event is triggered internally in the HAL implementation, and can not be
  * triggered from the test case
  */
-TEST_F(WifiChipHidlTest, registerEventCallback_1_2) {
+TEST_P(WifiChipHidlTest, registerEventCallback_1_2) {
     sp<WifiChipEventCallback> wifiChipEventCallback = new WifiChipEventCallback();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, registerEventCallback_1_2, wifiChipEventCallback);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_2::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
index 4dbc82b..f3f76e1 100644
--- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -16,10 +16,12 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.2/IWifi.h>
 #include <android/hardware/wifi/1.2/IWifiNanIface.h>
 #include <android/hardware/wifi/1.2/IWifiNanIfaceEventCallback.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -36,19 +38,19 @@
 
 #define TIMEOUT_PERIOD 10
 
-android::sp<android::hardware::wifi::V1_2::IWifiNanIface>
-getWifiNanIface_1_2() {
+android::sp<android::hardware::wifi::V1_2::IWifiNanIface> getWifiNanIface_1_2(
+    const std::string& instance_name) {
     return android::hardware::wifi::V1_2::IWifiNanIface::castFrom(
-        getWifiNanIface());
+        getWifiNanIface(instance_name));
 }
 
 /**
  * Fixture to use for all NAN Iface HIDL interface tests.
  */
-class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        iwifiNanIface = getWifiNanIface_1_2();
+        iwifiNanIface = getWifiNanIface_1_2(GetInstanceName());
         ASSERT_NE(nullptr, iwifiNanIface.get());
         ASSERT_EQ(WifiStatusCode::SUCCESS,
                   HIDL_INVOKE(iwifiNanIface, registerEventCallback_1_2,
@@ -56,7 +58,7 @@
                       .code);
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
     /* Used as a mechanism to inform the test about data/event callback */
     inline void notify() {
@@ -458,6 +460,8 @@
     ::android::hardware::wifi::V1_2::NanDataPathConfirmInd
         nanDataPathConfirmInd_1_2;
     NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd;
+
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -465,15 +469,14 @@
  * Ensures that an instance of the IWifiNanIface proxy object is
  * successfully created.
  */
-TEST(WifiNanIfaceHidlTestNoFixture, Create) {
-    ASSERT_NE(nullptr, getWifiNanIface_1_2().get());
-    stopWifi();
+TEST_P(WifiNanIfaceHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
 
 /*
  * enableRequest_1_2InvalidArgs: validate that fails with invalid arguments
  */
-TEST_F(WifiNanIfaceHidlTest, enableRequest_1_2InvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_2InvalidArgs) {
     uint16_t inputCmdId = 10;
     callbackType = INVALID;
     NanEnableRequest nanEnableRequest = {};
@@ -493,7 +496,7 @@
  * enableRequest_1_2ShimInvalidArgs: validate that fails with invalid arguments
  * to the shim
  */
-TEST_F(WifiNanIfaceHidlTest, enableRequest_1_2ShimInvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_2ShimInvalidArgs) {
     uint16_t inputCmdId = 10;
     NanEnableRequest nanEnableRequest = {};
     nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon =
@@ -508,7 +511,7 @@
 /*
  * configRequest_1_2InvalidArgs: validate that fails with invalid arguments
  */
-TEST_F(WifiNanIfaceHidlTest, configRequest_1_2InvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_2InvalidArgs) {
     uint16_t inputCmdId = 10;
     callbackType = INVALID;
     NanConfigRequest nanConfigRequest = {};
@@ -528,7 +531,7 @@
  * configRequest_1_2ShimInvalidArgs: validate that fails with invalid arguments
  * to the shim
  */
-TEST_F(WifiNanIfaceHidlTest, configRequest_1_2ShimInvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_2ShimInvalidArgs) {
     uint16_t inputCmdId = 10;
     NanConfigRequest nanConfigRequest = {};
     nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128;  // must be <= 127
@@ -538,3 +541,9 @@
                           nanConfigRequest, nanConfigRequestSupp)
                   .code);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiNanIfaceHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_2::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
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
index 92f5d14..1b907b2 100644
--- a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -19,9 +19,11 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.2/IWifi.h>
 #include <android/hardware/wifi/1.2/IWifiStaIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -34,14 +36,15 @@
 /**
  * Fixture to use for all STA Iface HIDL interface tests.
  */
-class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface());
+        wifi_sta_iface_ =
+            IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_sta_iface_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
@@ -52,6 +55,9 @@
     }
 
     sp<IWifiStaIface> wifi_sta_iface_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -59,7 +65,7 @@
  * Ensures that calls to set MAC address will return a success status
  * code.
  */
-TEST_F(WifiStaIfaceHidlTest, SetMacAddress) {
+TEST_P(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,
@@ -76,7 +82,7 @@
  * TODO: We can't execute APF opcodes from this test because there's no way
  * to loop test packets through the wifi firmware (b/73804303#comment29).
  */
-TEST_F(WifiStaIfaceHidlTest, DISABLED_ReadApfPacketFilterData) {
+TEST_P(WifiStaIfaceHidlTest, DISABLED_ReadApfPacketFilterData) {
     if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) {
         // Disable test if APF packet filer is not supported.
         LOG(WARNING) << "TEST SKIPPED: APF packet filtering not supported";
@@ -107,3 +113,9 @@
 
     EXPECT_EQ(status_and_data.second, data);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiStaIfaceHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_2::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp
index 53c8f08..fe9c791 100644
--- a/wifi/1.3/vts/functional/Android.bp
+++ b/wifi/1.3/vts/functional/Android.bp
@@ -28,5 +28,8 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "libwifi-system-iface"
     ],
+    disable_framework: true,
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
index faf426e..52c7a4a 100644
--- a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
+++ b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
@@ -14,37 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.3/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
 
-#include "wifi_hidl_test_utils.h"
-
-using ::android::hardware::wifi::V1_3::IWifi;
-
-// Test environment for Wifi HIDL HAL.
-class WifiHidlEnvironment_1_3 : public WifiHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiHidlEnvironment_1_3* Instance() {
-        static WifiHidlEnvironment_1_3* instance = new WifiHidlEnvironment_1_3;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<android::hardware::wifi::V1_3::IWifi>();
-    }
-
-   private:
-    WifiHidlEnvironment_1_3() {}
-};
-
-WifiHidlEnvironment_1_3* gEnv = WifiHidlEnvironment_1_3::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
\ No newline at end of file
diff --git a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
index d980fcb..db93967 100644
--- a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
@@ -16,9 +16,11 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.3/IWifi.h>
 #include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -39,14 +41,14 @@
 /**
  * Fixture to use for all Wifi chip HIDL interface tests.
  */
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_chip_ = IWifiChip::castFrom(getWifiChip());
+        wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     // Helper function to configure the Chip in one of the supported modes.
@@ -70,6 +72,9 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -77,7 +82,7 @@
  * This test case tests the setLatencyMode() API with
  * Latency mode NORMAL
  */
-TEST_F(WifiChipHidlTest, SetLatencyMode_normal) {
+TEST_P(WifiChipHidlTest, SetLatencyMode_normal) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, setLatencyMode, kLatencyModeNormal);
@@ -92,7 +97,7 @@
  * SetLatencyMode_low
  * This test case tests the setLatencyMode() API with Latency mode LOW
  */
-TEST_F(WifiChipHidlTest, SetLatencyMode_low) {
+TEST_P(WifiChipHidlTest, SetLatencyMode_low) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, setLatencyMode, kLatencyModeLow);
@@ -106,7 +111,7 @@
 /*
  * GetCapabilities_1_3
  */
-TEST_F(WifiChipHidlTest, GetCapabilities_1_3) {
+TEST_P(WifiChipHidlTest, GetCapabilities_1_3) {
     configureChipForIfaceType(IfaceType::STA, true);
     const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities_1_3);
     if (status_and_caps.first.code != WifiStatusCode::SUCCESS) {
@@ -116,3 +121,9 @@
     }
     EXPECT_NE(0u, status_and_caps.second);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_3::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
index d382f30..c5acc3c 100644
--- a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -19,9 +19,11 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.3/IWifi.h>
 #include <android/hardware/wifi/1.3/IWifiStaIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -35,14 +37,15 @@
 /**
  * Fixture to use for all STA Iface HIDL interface tests.
  */
-class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface());
+        wifi_sta_iface_ =
+            IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_sta_iface_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
@@ -53,6 +56,9 @@
     }
 
     sp<IWifiStaIface> wifi_sta_iface_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -60,7 +66,7 @@
  * Ensures that calls to get factory MAC address will retrieve a non-zero MAC
  * and return a success status code.
  */
-TEST_F(WifiStaIfaceHidlTest, GetFactoryMacAddress) {
+TEST_P(WifiStaIfaceHidlTest, GetFactoryMacAddress) {
     std::pair<WifiStatus, hidl_array<uint8_t, 6> > status_and_mac =
         HIDL_INVOKE(wifi_sta_iface_, getFactoryMacAddress);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code);
@@ -73,7 +79,7 @@
  * Ensures that calls to get link layer stats V1_3 will retrieve a non-empty
  * StaLinkLayerStats after link layer stats collection is enabled.
  */
-TEST_F(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) {
+TEST_P(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
         // No-op if link layer stats is not supported.
@@ -94,3 +100,9 @@
         WifiStatusCode::SUCCESS,
         HIDL_INVOKE(wifi_sta_iface_, disableLinkLayerStatsCollection).code);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiStaIfaceHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_3::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp
index e197859..5750e42 100644
--- a/wifi/1.4/Android.bp
+++ b/wifi/1.4/Android.bp
@@ -13,6 +13,7 @@
         "IWifiChip.hal",
         "IWifiRttController.hal",
         "IWifiRttControllerEventCallback.hal",
+        "IWifiStaIface.hal",
     ],
     interfaces: [
         "android.hardware.wifi@1.0",
diff --git a/wifi/1.4/IWifiStaIface.hal b/wifi/1.4/IWifiStaIface.hal
new file mode 100644
index 0000000..fb658cd
--- /dev/null
+++ b/wifi/1.4/IWifiStaIface.hal
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.4;
+
+import @1.0::WifiStatus;
+import @1.0::MacAddress;
+import @1.0::IWifiStaIface;
+import @1.3::IWifiStaIface;
+
+/**
+ * Interface used to represent a single STA iface.
+ *
+ * IWifiChip.createStaIface() may return a @1.4::IWifiStaIface when supported.
+ */
+interface IWifiStaIface extends @1.3::IWifiStaIface {
+
+    enum StaIfaceCapabilityMask : @1.0::IWifiStaIface.StaIfaceCapabilityMask {
+        STA_6G = 1 << 15
+    };
+
+  /**
+   * Get the capabilities supported by this STA iface.
+   *
+   * @return status WifiStatus of the operation.
+   *         Possible status codes:
+   *         |WifiStatusCode.SUCCESS|,
+   *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+   *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+   *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+   *         |WifiStatusCode.ERROR_UNKNOWN|
+   * @return capabilities Bitset of |StaIfaceCapabilityMask| values.
+   */
+  getCapabilities_1_4()
+      generates (WifiStatus status,
+                 bitfield<StaIfaceCapabilityMask> capabilities);
+};
diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp
index 61f311e..13a09f3 100644
--- a/wifi/1.4/default/hidl_struct_util.cpp
+++ b/wifi/1.4/default/hidl_struct_util.cpp
@@ -91,7 +91,7 @@
 }
 
 IWifiStaIface::StaIfaceCapabilityMask
-convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) {
+convertLegacyFeatureToHidlStaIfaceCapability(uint64_t feature) {
     using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
     switch (feature) {
         case WIFI_FEATURE_GSCAN:
@@ -120,6 +120,8 @@
             return HidlStaIfaceCaps::ND_OFFLOAD;
         case WIFI_FEATURE_MKEEP_ALIVE:
             return HidlStaIfaceCaps::KEEP_ALIVE;
+        case WIFI_FEATURE_INFRA_6G:
+            return HidlStaIfaceCaps::STA_6G;
     };
     CHECK(false) << "Unknown legacy feature: " << feature;
     return {};
@@ -365,7 +367,7 @@
 }
 
 bool convertLegacyFeaturesToHidlStaCapabilities(
-    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
     uint32_t* hidl_caps) {
     if (!hidl_caps) {
         return false;
@@ -384,7 +386,8 @@
           WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND,
           WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO,
           WIFI_FEATURE_TDLS, WIFI_FEATURE_TDLS_OFFCHANNEL,
-          WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) {
+          WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE,
+          WIFI_FEATURE_INFRA_6G}) {
         if (feature & legacy_feature_set) {
             *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
         }
diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h
index a99c1ac..cfaa4ad 100644
--- a/wifi/1.4/default/hidl_struct_util.h
+++ b/wifi/1.4/default/hidl_struct_util.h
@@ -25,6 +25,7 @@
 #include <android/hardware/wifi/1.2/types.h>
 #include <android/hardware/wifi/1.3/IWifiChip.h>
 #include <android/hardware/wifi/1.3/types.h>
+#include <android/hardware/wifi/1.4/IWifiStaIface.h>
 #include <android/hardware/wifi/1.4/types.h>
 
 #include "wifi_legacy_hal.h"
@@ -69,7 +70,7 @@
 
 // STA iface conversion methods.
 bool convertLegacyFeaturesToHidlStaCapabilities(
-    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
     uint32_t* hidl_caps);
 bool convertLegacyApfCapabilitiesToHidl(
     const legacy_hal::PacketFilterCapabilities& legacy_caps,
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
index 8139253..ae3c447 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -479,7 +479,7 @@
 std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet(
     const std::string& iface_name) {
     feature_set set;
-    static_assert(sizeof(set) == sizeof(uint32_t),
+    static_assert(sizeof(set) == sizeof(uint64_t),
                   "Some feature_flags can not be represented in output");
     wifi_error status = global_func_table_.wifi_get_supported_feature_set(
         getIfaceHandle(iface_name), &set);
diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp
index 3e0127e..8e1ada1 100644
--- a/wifi/1.4/default/wifi_sta_iface.cpp
+++ b/wifi/1.4/default/wifi_sta_iface.cpp
@@ -266,6 +266,13 @@
                            hidl_status_cb);
 }
 
+Return<void> WifiStaIface::getCapabilities_1_4(
+    getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getCapabilitiesInternal_1_4,
+                           hidl_status_cb);
+}
+
 std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
     return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
 }
@@ -283,26 +290,7 @@
 }
 
 std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    uint32_t legacy_feature_set;
-    std::tie(legacy_status, legacy_feature_set) =
-        legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), 0};
-    }
-    uint32_t legacy_logger_feature_set;
-    std::tie(legacy_status, legacy_logger_feature_set) =
-        legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        // some devices don't support querying logger feature set
-        legacy_logger_feature_set = 0;
-    }
-    uint32_t hidl_caps;
-    if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
-            legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
 }
 
 std::pair<WifiStatus, StaApfPacketFilterCapabilities>
@@ -640,6 +628,29 @@
     return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
 }
 
+std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal_1_4() {
+    legacy_hal::wifi_error legacy_status;
+    uint64_t legacy_feature_set;
+    std::tie(legacy_status, legacy_feature_set) =
+        legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), 0};
+    }
+    uint32_t legacy_logger_feature_set;
+    std::tie(legacy_status, legacy_logger_feature_set) =
+        legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        // some devices don't support querying logger feature set
+        legacy_logger_feature_set = 0;
+    }
+    uint32_t hidl_caps;
+    if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
+            legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
 }  // namespace implementation
 }  // namespace V1_4
 }  // namespace wifi
diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h
index d8f7a01..ccf234f 100644
--- a/wifi/1.4/default/wifi_sta_iface.h
+++ b/wifi/1.4/default/wifi_sta_iface.h
@@ -19,7 +19,7 @@
 
 #include <android-base/macros.h>
 #include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-#include <android/hardware/wifi/1.3/IWifiStaIface.h>
+#include <android/hardware/wifi/1.4/IWifiStaIface.h>
 
 #include "hidl_callback_util.h"
 #include "wifi_iface_util.h"
@@ -35,7 +35,7 @@
 /**
  * HIDL interface object used to control a STA Iface instance.
  */
-class WifiStaIface : public V1_3::IWifiStaIface {
+class WifiStaIface : public V1_4::IWifiStaIface {
    public:
     WifiStaIface(const std::string& ifname,
                  const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
@@ -111,6 +111,8 @@
                                setMacAddress_cb hidl_status_cb) override;
     Return<void> getFactoryMacAddress(
         getFactoryMacAddress_cb hidl_status_cb) override;
+    Return<void> getCapabilities_1_4(
+        getCapabilities_1_4_cb hidl_status_cb) override;
 
    private:
     // Corresponding worker functions for the HIDL methods.
@@ -159,6 +161,7 @@
     WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
     std::pair<WifiStatus, std::array<uint8_t, 6>>
     getFactoryMacAddressInternal();
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_4();
 
     std::string ifname_;
     std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp
index 42c60f2..c71b319 100644
--- a/wifi/1.4/vts/functional/Android.bp
+++ b/wifi/1.4/vts/functional/Android.bp
@@ -29,5 +29,7 @@
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
         "android.hardware.wifi@1.4",
+        "libwifi-system-iface"
     ],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp
index deac0fa..7e0f3cd 100644
--- a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp
+++ b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp
@@ -14,37 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.4/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
 
-#include "wifi_hidl_test_utils.h"
-
-using ::android::hardware::wifi::V1_4::IWifi;
-
-// Test environment for Wifi HIDL HAL.
-class WifiHidlEnvironment_1_4 : public WifiHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiHidlEnvironment_1_4* Instance() {
-        static WifiHidlEnvironment_1_4* instance = new WifiHidlEnvironment_1_4;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<android::hardware::wifi::V1_4::IWifi>();
-    }
-
-   private:
-    WifiHidlEnvironment_1_4() {}
-};
-
-WifiHidlEnvironment_1_4* gEnv = WifiHidlEnvironment_1_4::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
\ No newline at end of file
diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
index 68e9bbb..017ecb6 100644
--- a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
+#include <android/hardware/wifi/1.4/IWifi.h>
 #include <android/hardware/wifi/1.4/IWifiApIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -25,6 +27,7 @@
 using ::android::hardware::hidl_array;
 using ::android::hardware::wifi::V1_0::WifiStatus;
 using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_4::IWifi;
 using ::android::hardware::wifi::V1_4::IWifiApIface;
 
 extern WifiHidlEnvironment* gEnv;
@@ -32,19 +35,21 @@
 /**
  * Fixture to use for all STA Iface HIDL interface tests.
  */
-class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_ap_iface_ = IWifiApIface::castFrom(getWifiApIface());
+        wifi_ap_iface_ =
+            IWifiApIface::castFrom(getWifiApIface(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_ap_iface_.get());
     }
 
-    virtual void TearDown() override {
-        stopWifi();
-    }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     sp<IWifiApIface> wifi_ap_iface_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -52,7 +57,7 @@
  * Ensures that calls to set MAC address will return a success status
  * code.
  */
-TEST_F(WifiApIfaceHidlTest, SetMacAddress) {
+TEST_P(WifiApIfaceHidlTest, SetMacAddress) {
     const hidl_array<uint8_t, 6> kMac{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}};
     EXPECT_EQ(WifiStatusCode::SUCCESS,
               HIDL_INVOKE(wifi_ap_iface_, setMacAddress, kMac).code);
@@ -63,10 +68,16 @@
  * Ensures that calls to get factory MAC address will retrieve a non-zero MAC
  * and return a success status code.
  */
-TEST_F(WifiApIfaceHidlTest, GetFactoryMacAddress) {
+TEST_P(WifiApIfaceHidlTest, GetFactoryMacAddress) {
     std::pair<WifiStatus, hidl_array<uint8_t, 6> > status_and_mac =
         HIDL_INVOKE(wifi_ap_iface_, getFactoryMacAddress);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code);
     hidl_array<uint8_t, 6> all_zero{};
     EXPECT_NE(all_zero, status_and_mac.second);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiApIfaceHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp
new file mode 100644
index 0000000..ec4b2c9
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 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.4/IWifiStaIface.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_4::IWifiStaIface;
+
+/**
+ * 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_;
+};
+
+/*
+ * GetCapabilities_1_4
+ */
+TEST_F(WifiStaIfaceHidlTest, GetCapabilities_1_4) {
+    configureChipForIfaceType(IfaceType::STA, true);
+
+    const auto& status_and_caps =
+        HIDL_INVOKE(wifi_sta_iface_, getCapabilities_1_4);
+    if (status_and_caps.first.code != WifiStatusCode::SUCCESS) {
+        EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED,
+                  status_and_caps.first.code);
+        return;
+    }
+    EXPECT_NE(0u, status_and_caps.second);
+}
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index ba79738..15525bb 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -51,7 +51,7 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
 cc_test {
@@ -71,4 +71,5 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
index 6ca0546..f582cc1 100644
--- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
@@ -14,40 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-
 #include "supplicant_hidl_test_utils.h"
-#include "wifi_hidl_test_utils.h"
 
-class WifiSupplicantHidlEnvironment_1_0 : public WifiSupplicantHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiSupplicantHidlEnvironment_1_0* Instance() {
-        static WifiSupplicantHidlEnvironment_1_0* instance =
-            new WifiSupplicantHidlEnvironment_1_0;
-        return instance;
-    }
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::wifi::V1_0::IWifi>();
-        registerTestService<
-            ::android::hardware::wifi::supplicant::V1_0::ISupplicant>();
-    }
-
-   private:
-    WifiSupplicantHidlEnvironment_1_0() {}
-};
-
-WifiSupplicantHidlEnvironment* gEnv =
-    WifiSupplicantHidlEnvironment_1_0::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        int status = RUN_ALL_TESTS();
-        LOG(INFO) << "Test result = " << status;
-    }
-    return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_call_util.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_call_util.h
index 1c0fcec..3fa6f9d 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_call_util.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_call_util.h
@@ -25,8 +25,6 @@
 #include <type_traits>
 #include <utility>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace {
 namespace detail {
 template <typename>
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
index 436b88b..4f25465 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
@@ -16,35 +16,47 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicant.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "supplicant_hidl_test_utils.h"
 
 using ::android::sp;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantIface;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
-using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
 
-extern WifiSupplicantHidlEnvironment* gEnv;
-
-class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        supplicant_ = getSupplicant();
+        wifi_instance_name_ = std::get<0>(GetParam());
+        supplicant_instance_name_ = std::get<1>(GetParam());
+        stopSupplicant(wifi_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                             supplicant_instance_name_);
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
         ASSERT_NE(supplicant_.get(), nullptr);
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
+    virtual void TearDown() override { stopSupplicant(wifi_instance_name_); }
 
    protected:
     // ISupplicant object used for all tests in this fixture.
     sp<ISupplicant> supplicant_;
+    bool isP2pOn_ = false;
+    std::string wifi_instance_name_;
+    std::string supplicant_instance_name_;
 };
 
 /*
@@ -52,16 +64,19 @@
  * Ensures that an instance of the ISupplicant proxy object is
  * successfully created.
  */
-TEST(SupplicantHidlTestNoFixture, Create) {
-    startSupplicantAndWaitForHidlService();
-    EXPECT_NE(nullptr, getSupplicant().get());
-    stopSupplicant();
+TEST_P(SupplicantHidlTest, Create) {
+    // Stop the proxy object created in setup.
+    stopSupplicant(wifi_instance_name_);
+    startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                         supplicant_instance_name_);
+    EXPECT_NE(nullptr,
+              getSupplicant(supplicant_instance_name_, isP2pOn_).get());
 }
 
 /*
  * ListInterfaces
  */
-TEST_F(SupplicantHidlTest, ListInterfaces) {
+TEST_P(SupplicantHidlTest, ListInterfaces) {
     std::vector<ISupplicant::IfaceInfo> ifaces;
     supplicant_->listInterfaces(
         [&](const SupplicantStatus& status,
@@ -74,7 +89,7 @@
               std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) {
                   return iface.type == IfaceType::STA;
               }));
-    if (gEnv->isP2pOn) {
+    if (isP2pOn_) {
         EXPECT_NE(
             ifaces.end(),
             std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) {
@@ -86,7 +101,7 @@
 /*
  * GetInterface
  */
-TEST_F(SupplicantHidlTest, GetInterface) {
+TEST_P(SupplicantHidlTest, GetInterface) {
     std::vector<ISupplicant::IfaceInfo> ifaces;
     supplicant_->listInterfaces(
         [&](const SupplicantStatus& status,
@@ -107,7 +122,7 @@
 /*
  * SetDebugParams
  */
-TEST_F(SupplicantHidlTest, SetDebugParams) {
+TEST_P(SupplicantHidlTest, SetDebugParams) {
     bool show_timestamp = true;
     bool show_keys = true;
     ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
@@ -124,7 +139,7 @@
 /*
  * GetDebugLevel
  */
-TEST_F(SupplicantHidlTest, GetDebugLevel) {
+TEST_P(SupplicantHidlTest, GetDebugLevel) {
     bool show_timestamp = true;
     bool show_keys = true;
     ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
@@ -142,7 +157,7 @@
 /*
  * IsDebugShowTimestampEnabled
  */
-TEST_F(SupplicantHidlTest, IsDebugShowTimestampEnabled) {
+TEST_P(SupplicantHidlTest, IsDebugShowTimestampEnabled) {
     bool show_timestamp = true;
     bool show_keys = true;
     ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
@@ -160,7 +175,7 @@
 /*
  * IsDebugShowKeysEnabled
  */
-TEST_F(SupplicantHidlTest, IsDebugShowKeysEnabled) {
+TEST_P(SupplicantHidlTest, IsDebugShowKeysEnabled) {
     bool show_timestamp = true;
     bool show_keys = true;
     ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
@@ -178,15 +193,24 @@
 /*
  * SetConcurrenyPriority
  */
-TEST_F(SupplicantHidlTest, SetConcurrencyPriority) {
+TEST_P(SupplicantHidlTest, SetConcurrencyPriority) {
     supplicant_->setConcurrencyPriority(
         IfaceType::STA, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
         });
-    if (gEnv->isP2pOn) {
+    if (isP2pOn_) {
         supplicant_->setConcurrencyPriority(
             IfaceType::P2P, [](const SupplicantStatus& status) {
                 EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
             });
     }
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            ISupplicant::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index 7bd04dc..d47e42f 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -56,8 +56,8 @@
 
 // Helper function to initialize the driver and firmware to STA mode
 // using the vendor HAL HIDL interface.
-void initilializeDriverAndFirmware() {
-    sp<IWifiChip> wifi_chip = getWifiChip();
+void initilializeDriverAndFirmware(const std::string& wifi_instance_name) {
+    sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
     ChipModeId mode_id;
     EXPECT_TRUE(configureChipToSupportIfaceType(
         wifi_chip, ::android::hardware::wifi::V1_0::IfaceType::STA, &mode_id));
@@ -65,7 +65,9 @@
 
 // Helper function to deinitialize the driver and firmware
 // using the vendor HAL HIDL interface.
-void deInitilializeDriverAndFirmware() { stopWifi(); }
+void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) {
+    stopWifi(wifi_instance_name);
+}
 
 // Helper function to find any iface of the desired type exposed.
 bool findIfaceOfType(sp<ISupplicant> supplicant, IfaceType desired_type,
@@ -154,28 +156,38 @@
     std::condition_variable condition_;
 };
 
-void stopSupplicant() {
+void stopSupplicant() { stopSupplicant(""); }
+
+void stopSupplicant(const std::string& wifi_instance_name) {
     SupplicantManager supplicant_manager;
 
     ASSERT_TRUE(supplicant_manager.StopSupplicant());
-    deInitilializeDriverAndFirmware();
+    deInitilializeDriverAndFirmware(wifi_instance_name);
     ASSERT_FALSE(supplicant_manager.IsSupplicantRunning());
 }
 
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 void startSupplicantAndWaitForHidlService() {
-    initilializeDriverAndFirmware();
+    startSupplicantAndWaitForHidlService("",
+                                         gEnv->getServiceName<ISupplicant>());
+}
+
+void startSupplicantAndWaitForHidlService(
+    const std::string& wifi_instance_name,
+    const std::string& supplicant_instance_name) {
+    initilializeDriverAndFirmware(wifi_instance_name);
 
     android::sp<ServiceNotificationListener> notification_listener =
         new ServiceNotificationListener();
-    string service_name = gEnv->getServiceName<ISupplicant>();
     ASSERT_TRUE(notification_listener->registerForHidlServiceNotifications(
-        service_name));
+        supplicant_instance_name));
 
     SupplicantManager supplicant_manager;
     ASSERT_TRUE(supplicant_manager.StartSupplicant());
     ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
 
-    ASSERT_TRUE(notification_listener->waitForHidlService(500, service_name));
+    ASSERT_TRUE(notification_listener->waitForHidlService(
+        500, supplicant_instance_name));
 }
 
 bool is_1_1(const sp<ISupplicant>& supplicant) {
@@ -218,6 +230,7 @@
         });
 }
 
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 sp<ISupplicant> getSupplicant() {
     sp<ISupplicant> supplicant =
         ::testing::VtsHalHidlTargetTestBase::getService<ISupplicant>(
@@ -232,8 +245,28 @@
     return supplicant;
 }
 
+sp<ISupplicant> getSupplicant(const std::string& supplicant_instance_name,
+                              bool isP2pOn) {
+    sp<ISupplicant> supplicant =
+        ISupplicant::getService(supplicant_instance_name);
+    // For 1.1 supplicant, we need to add interfaces at initialization.
+    if (is_1_1(supplicant)) {
+        addSupplicantStaIface_1_1(supplicant);
+        if (isP2pOn) {
+            addSupplicantP2pIface_1_1(supplicant);
+        }
+    }
+    return supplicant;
+}
+
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 sp<ISupplicantStaIface> getSupplicantStaIface() {
     sp<ISupplicant> supplicant = getSupplicant();
+    return getSupplicantStaIface(supplicant);
+}
+
+sp<ISupplicantStaIface> getSupplicantStaIface(
+    const sp<ISupplicant>& supplicant) {
     if (!supplicant.get()) {
         return nullptr;
     }
@@ -257,8 +290,14 @@
     return sta_iface;
 }
 
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 sp<ISupplicantStaNetwork> createSupplicantStaNetwork() {
-    sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface();
+    return createSupplicantStaNetwork(getSupplicant());
+}
+
+sp<ISupplicantStaNetwork> createSupplicantStaNetwork(
+    const sp<ISupplicant>& supplicant) {
+    sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface(supplicant);
     if (!sta_iface.get()) {
         return nullptr;
     }
@@ -278,8 +317,13 @@
     return sta_network;
 }
 
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 sp<ISupplicantP2pIface> getSupplicantP2pIface() {
-    sp<ISupplicant> supplicant = getSupplicant();
+    return getSupplicantP2pIface(getSupplicant());
+}
+
+sp<ISupplicantP2pIface> getSupplicantP2pIface(
+    const sp<ISupplicant>& supplicant) {
     if (!supplicant.get()) {
         return nullptr;
     }
@@ -303,8 +347,12 @@
     return p2p_iface;
 }
 
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
 bool turnOnExcessiveLogging() {
-    sp<ISupplicant> supplicant = getSupplicant();
+    return turnOnExcessiveLogging(getSupplicant());
+}
+
+bool turnOnExcessiveLogging(const sp<ISupplicant>& supplicant) {
     if (!supplicant.get()) {
         return false;
     }
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
index 21a1ae6..40ad695 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
@@ -25,21 +25,47 @@
 
 #include <getopt.h>
 
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include "wifi_hidl_test_utils.h"
 
 // Used to stop the android wifi framework before every test.
 void stopWifiFramework();
+void stopWifiFramework(const std::string& wifi_instance_name);
 void startWifiFramework();
+void startWifiFramework(const std::string& wifi_instance_name);
+
 void stopSupplicant();
+void stopSupplicant(const std::string& wifi_instance_name);
 // Used to configure the chip, driver and start wpa_supplicant before every
 // test.
-void startSupplicantAndWaitForHidlService();
+void startSupplicantAndWaitForHidlService(
+    const std::string& wifi_instance_name,
+    const std::string& supplicant_instance_name);
 
 // Helper functions to obtain references to the various HIDL interface objects.
 // Note: We only have a single instance of each of these objects currently.
 // These helper functions should be modified to return vectors if we support
 // multiple instances.
 android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>
+getSupplicant(const std::string& supplicant_instance_name, bool isP2pOn);
+android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface>
+getSupplicantStaIface(
+    const android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>&
+        supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork>
+createSupplicantStaNetwork(
+    const android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>&
+        supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface>
+getSupplicantP2pIface(
+    const android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>&
+        supplicant);
+bool turnOnExcessiveLogging(
+    const android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>&
+        supplicant);
+
+// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
+void startSupplicantAndWaitForHidlService();
+android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>
 getSupplicant();
 android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface>
 getSupplicantStaIface();
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
index 0181f7b..8d6f38d 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
@@ -15,9 +15,12 @@
  */
 
 #include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIface.h>
 
 #include "supplicant_hidl_call_util.h"
@@ -30,11 +33,13 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIfaceCallback;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantNetworkId;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::V1_0::IWifi;
 
 namespace {
 constexpr uint8_t kTestSsidPostfix[] = {'t', 'e', 's', 't'};
@@ -66,26 +71,38 @@
 constexpr SupplicantNetworkId kTestNetworkId = 5;
 }  // namespace
 
-class SupplicantP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantP2pIfaceHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        EXPECT_TRUE(turnOnExcessiveLogging());
-        p2p_iface_ = getSupplicantP2pIface();
+        wifi_instance_name_ = std::get<0>(GetParam());
+        supplicant_instance_name_ = std::get<1>(GetParam());
+        stopSupplicant(wifi_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                             supplicant_instance_name_);
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        p2p_iface_ = getSupplicantP2pIface(supplicant_);
         ASSERT_NE(p2p_iface_.get(), nullptr);
 
         memcpy(mac_addr_.data(), kTestMacAddr, mac_addr_.size());
         memcpy(peer_mac_addr_.data(), kTestPeerMacAddr, peer_mac_addr_.size());
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
+    virtual void TearDown() override { stopSupplicant(wifi_instance_name_); }
 
    protected:
+    bool isP2pOn_ = false;
+    sp<ISupplicant> supplicant_;
     // ISupplicantP2pIface object used for all tests in this fixture.
     sp<ISupplicantP2pIface> p2p_iface_;
     // MAC address to use for various tests.
     std::array<uint8_t, 6> mac_addr_;
     std::array<uint8_t, 6> peer_mac_addr_;
+    std::string wifi_instance_name_;
+    std::string supplicant_instance_name_;
 };
 
 class IfaceCallback : public ISupplicantP2pIfaceCallback {
@@ -177,16 +194,20 @@
  * Ensures that an instance of the ISupplicantP2pIface proxy object is
  * successfully created.
  */
-TEST(SupplicantP2pIfaceHidlTestNoFixture, Create) {
-    startSupplicantAndWaitForHidlService();
-    EXPECT_NE(nullptr, getSupplicantP2pIface().get());
-    stopSupplicant();
+TEST_P(SupplicantP2pIfaceHidlTest, Create) {
+    stopSupplicant(wifi_instance_name_);
+    startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                         supplicant_instance_name_);
+    sp<ISupplicantP2pIface> p2p_iface = getSupplicantP2pIface(
+        getSupplicant(supplicant_instance_name_, isP2pOn_));
+
+    EXPECT_NE(nullptr, p2p_iface.get());
 }
 
 /*
  * RegisterCallback
  */
-TEST_F(SupplicantP2pIfaceHidlTest, RegisterCallback) {
+TEST_P(SupplicantP2pIfaceHidlTest, RegisterCallback) {
     p2p_iface_->registerCallback(
         new IfaceCallback(), [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -196,7 +217,7 @@
 /*
  * GetName
  */
-TEST_F(SupplicantP2pIfaceHidlTest, GetName) {
+TEST_P(SupplicantP2pIfaceHidlTest, GetName) {
     const auto& status_and_interface_name = HIDL_INVOKE(p2p_iface_, getName);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               status_and_interface_name.first.code);
@@ -206,7 +227,7 @@
 /*
  * GetType
  */
-TEST_F(SupplicantP2pIfaceHidlTest, GetType) {
+TEST_P(SupplicantP2pIfaceHidlTest, GetType) {
     const auto& status_and_interface_type = HIDL_INVOKE(p2p_iface_, getType);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               status_and_interface_type.first.code);
@@ -216,7 +237,7 @@
 /*
  * GetDeviceAddress
  */
-TEST_F(SupplicantP2pIfaceHidlTest, GetDeviceAddress) {
+TEST_P(SupplicantP2pIfaceHidlTest, GetDeviceAddress) {
     p2p_iface_->getDeviceAddress(
         [](const SupplicantStatus& status,
            const hidl_array<uint8_t, 6>& /* mac_addr */) {
@@ -227,7 +248,7 @@
 /*
  * SetSsidPostfix
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetSsidPostfix) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetSsidPostfix) {
     std::vector<uint8_t> ssid(kTestSsidPostfix,
                               kTestSsidPostfix + sizeof(kTestSsidPostfix));
     p2p_iface_->setSsidPostfix(ssid, [](const SupplicantStatus& status) {
@@ -238,7 +259,7 @@
 /*
  * Find
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Find) {
+TEST_P(SupplicantP2pIfaceHidlTest, Find) {
     p2p_iface_->find(kTestFindTimeout, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -247,7 +268,7 @@
 /*
  * StopFind
  */
-TEST_F(SupplicantP2pIfaceHidlTest, StopFind) {
+TEST_P(SupplicantP2pIfaceHidlTest, StopFind) {
     p2p_iface_->find(kTestFindTimeout, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -260,7 +281,7 @@
 /*
  * Flush
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Flush) {
+TEST_P(SupplicantP2pIfaceHidlTest, Flush) {
     p2p_iface_->flush([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -269,7 +290,7 @@
 /*
  * Connect
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Connect) {
+TEST_P(SupplicantP2pIfaceHidlTest, Connect) {
     p2p_iface_->connect(
         mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
         kTestConnectPin, false, false, kTestConnectGoIntent,
@@ -282,7 +303,7 @@
 /*
  * CancelConnect
  */
-TEST_F(SupplicantP2pIfaceHidlTest, CancelConnect) {
+TEST_P(SupplicantP2pIfaceHidlTest, CancelConnect) {
     p2p_iface_->connect(
         mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
         kTestConnectPin, false, false, kTestConnectGoIntent,
@@ -299,7 +320,7 @@
 /*
  * ProvisionDiscovery
  */
-TEST_F(SupplicantP2pIfaceHidlTest, ProvisionDiscovery) {
+TEST_P(SupplicantP2pIfaceHidlTest, ProvisionDiscovery) {
     p2p_iface_->provisionDiscovery(
         mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
         [](const SupplicantStatus& status) {
@@ -311,7 +332,7 @@
 /*
  * AddGroup
  */
-TEST_F(SupplicantP2pIfaceHidlTest, AddGroup) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddGroup) {
     p2p_iface_->addGroup(false, kTestNetworkId,
                          [](const SupplicantStatus& /* status */) {
                              // TODO: Figure out the initialization sequence for
@@ -324,7 +345,7 @@
 /*
  * RemoveGroup
  */
-TEST_F(SupplicantP2pIfaceHidlTest, RemoveGroup) {
+TEST_P(SupplicantP2pIfaceHidlTest, RemoveGroup) {
     // This is not going to work with fake values.
     EXPECT_NE(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(p2p_iface_, removeGroup, kTestGroupIfName).code);
@@ -333,7 +354,7 @@
 /*
  * Reject
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Reject) {
+TEST_P(SupplicantP2pIfaceHidlTest, Reject) {
     p2p_iface_->reject(mac_addr_, [](const SupplicantStatus& status) {
         // This is not going to work with fake values.
         EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
@@ -343,7 +364,7 @@
 /*
  * Invite
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Invite) {
+TEST_P(SupplicantP2pIfaceHidlTest, Invite) {
     p2p_iface_->invite(kTestGroupIfName, mac_addr_, peer_mac_addr_,
                        [](const SupplicantStatus& status) {
                            // This is not going to work with fake values.
@@ -355,7 +376,7 @@
 /*
  * Reinvoke
  */
-TEST_F(SupplicantP2pIfaceHidlTest, Reinvoke) {
+TEST_P(SupplicantP2pIfaceHidlTest, Reinvoke) {
     p2p_iface_->reinvoke(
         kTestNetworkId, mac_addr_, [](const SupplicantStatus& status) {
             // This is not going to work with fake values.
@@ -367,7 +388,7 @@
 /*
  * ConfigureExtListen
  */
-TEST_F(SupplicantP2pIfaceHidlTest, ConfigureExtListen) {
+TEST_P(SupplicantP2pIfaceHidlTest, ConfigureExtListen) {
     p2p_iface_->configureExtListen(kTestExtListenPeriod, kTestExtListenInterval,
                                    [](const SupplicantStatus& status) {
                                        EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -378,7 +399,7 @@
 /*
  * SetListenChannel
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetListenChannel) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetListenChannel) {
     p2p_iface_->setListenChannel(
         kTestChannel, kTestOperatingClass, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -388,7 +409,7 @@
 /*
  * SetDisallowedFrequencies
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetDisallowedFrequencies) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetDisallowedFrequencies) {
     std::vector<ISupplicantP2pIface::FreqRange> ranges = {
         {kTestFreqRange[0], kTestFreqRange[1]}};
     p2p_iface_->setDisallowedFrequencies(
@@ -400,7 +421,7 @@
 /*
  * GetSsid
  */
-TEST_F(SupplicantP2pIfaceHidlTest, GetSsid) {
+TEST_P(SupplicantP2pIfaceHidlTest, GetSsid) {
     std::array<uint8_t, 6> mac_addr;
     memcpy(mac_addr.data(), kTestMacAddr, mac_addr.size());
     p2p_iface_->getSsid(mac_addr, [](const SupplicantStatus& status,
@@ -413,7 +434,7 @@
 /*
  * GetGroupCapability
  */
-TEST_F(SupplicantP2pIfaceHidlTest, GetGroupCapability) {
+TEST_P(SupplicantP2pIfaceHidlTest, GetGroupCapability) {
     std::array<uint8_t, 6> mac_addr;
     memcpy(mac_addr.data(), kTestMacAddr, mac_addr.size());
     p2p_iface_->getGroupCapability(
@@ -426,7 +447,7 @@
 /*
  * FlushServices
  */
-TEST_F(SupplicantP2pIfaceHidlTest, FlushServices) {
+TEST_P(SupplicantP2pIfaceHidlTest, FlushServices) {
     p2p_iface_->flushServices([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -435,7 +456,7 @@
 /*
  * SetMiracastMode
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetMiracastMode) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetMiracastMode) {
     p2p_iface_->setMiracastMode(ISupplicantP2pIface::MiracastMode::DISABLED,
                                 [](const SupplicantStatus& status) {
                                     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -456,7 +477,7 @@
 /*
  * SetGroupIdle
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetGroupIdle) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetGroupIdle) {
     // This is not going to work with fake values.
     EXPECT_NE(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(p2p_iface_, setGroupIdle, kTestGroupIfName,
@@ -467,7 +488,7 @@
 /*
  * SetPowerSave
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetPowerSave) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetPowerSave) {
     // This is not going to work with fake values.
     EXPECT_NE(
         SupplicantStatusCode::SUCCESS,
@@ -481,7 +502,7 @@
 /*
  * SetWpsDeviceName
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsDeviceName) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsDeviceName) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsDeviceName, kTestWpsDeviceName).code);
@@ -490,7 +511,7 @@
 /*
  * SetWpsDeviceType
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsDeviceType) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsDeviceType) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsDeviceType, kTestWpsDeviceType).code);
@@ -499,7 +520,7 @@
 /*
  * SetWpsManufacturer
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsManufacturer) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsManufacturer) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsManufacturer, kTestWpsManufacturer).code);
@@ -508,7 +529,7 @@
 /*
  * SetWpsModelName
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsModelName) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsModelName) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(p2p_iface_, setWpsModelName, kTestWpsModelName).code);
 }
@@ -516,7 +537,7 @@
 /*
  * SetWpsModelNumber
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsModelNumber) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsModelNumber) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsModelNumber, kTestWpsModelNumber).code);
@@ -525,7 +546,7 @@
 /*
  * SetWpsSerialNumber
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsSerialNumber) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsSerialNumber) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsSerialNumber, kTestWpsSerialNumber).code);
@@ -534,7 +555,7 @@
 /*
  * SetWpsConfigMethods
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWpsConfigMethods) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWpsConfigMethods) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWpsConfigMethods, kTestWpsConfigMethods)
@@ -548,7 +569,7 @@
  * This also tests that removeBonjourSerive() returns error when there is no
  * existing bonjour service with the same query data.
  */
-TEST_F(SupplicantP2pIfaceHidlTest, AddAndRemoveBonjourService) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddAndRemoveBonjourService) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(
                   p2p_iface_, addBonjourService,
@@ -584,7 +605,7 @@
  * This also tests that removeUpnpService() returns error when there is no
  * exsiting upnp service with the same service name.
  */
-TEST_F(SupplicantP2pIfaceHidlTest, AddAndRemoveUpnpService) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddAndRemoveUpnpService) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(p2p_iface_, addUpnpService, 0 /* version */,
                           kTestUpnpServiceName)
@@ -604,7 +625,7 @@
 /*
  * EnableWfd
  */
-TEST_F(SupplicantP2pIfaceHidlTest, EnableWfd) {
+TEST_P(SupplicantP2pIfaceHidlTest, EnableWfd) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(p2p_iface_, enableWfd, true).code);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -614,8 +635,17 @@
 /*
  * SetWfdDeviceInfo
  */
-TEST_F(SupplicantP2pIfaceHidlTest, SetWfdDeviceInfo) {
+TEST_P(SupplicantP2pIfaceHidlTest, SetWfdDeviceInfo) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(p2p_iface_, setWfdDeviceInfo, kTestWfdDeviceInfo).code);
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantP2pIfaceHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            ISupplicant::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
index ec102d5..089b3cd 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -15,9 +15,12 @@
  */
 
 #include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIface.h>
 
 #include "supplicant_hidl_call_util.h"
@@ -30,12 +33,14 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIfaceCallback;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantNetworkId;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::V1_0::IWifi;
 
 namespace {
 constexpr uint8_t kTestMacAddr[] = {0x56, 0x67, 0x67, 0xf4, 0x56, 0x92};
@@ -61,24 +66,36 @@
 constexpr uint16_t kTestWpsConfigMethods = 0xffff;
 }  // namespace
 
-class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantStaIfaceHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        EXPECT_TRUE(turnOnExcessiveLogging());
-        sta_iface_ = getSupplicantStaIface();
+        wifi_instance_name_ = std::get<0>(GetParam());
+        supplicant_instance_name_ = std::get<1>(GetParam());
+        stopSupplicant(wifi_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                             supplicant_instance_name_);
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_iface_ = getSupplicantStaIface(supplicant_);
         ASSERT_NE(sta_iface_.get(), nullptr);
 
         memcpy(mac_addr_.data(), kTestMacAddr, mac_addr_.size());
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
+    virtual void TearDown() override { stopSupplicant(wifi_instance_name_); }
 
    protected:
+    bool isP2pOn_ = false;
+    sp<ISupplicant> supplicant_;
     // ISupplicantStaIface object used for all tests in this fixture.
     sp<ISupplicantStaIface> sta_iface_;
     // MAC address to use for various tests.
     std::array<uint8_t, 6> mac_addr_;
+    std::string wifi_instance_name_;
+    std::string supplicant_instance_name_;
 };
 
 class IfaceCallback : public ISupplicantStaIfaceCallback {
@@ -159,16 +176,19 @@
  * Ensures that an instance of the ISupplicantStaIface proxy object is
  * successfully created.
  */
-TEST(SupplicantStaIfaceHidlTestNoFixture, Create) {
-    startSupplicantAndWaitForHidlService();
-    EXPECT_NE(nullptr, getSupplicantStaIface().get());
-    stopSupplicant();
+TEST_P(SupplicantStaIfaceHidlTest, Create) {
+    stopSupplicant(wifi_instance_name_);
+    startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                         supplicant_instance_name_);
+    EXPECT_NE(nullptr, getSupplicantStaIface(
+                           getSupplicant(supplicant_instance_name_, isP2pOn_))
+                           .get());
 }
 
 /*
  * RegisterCallback
  */
-TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback) {
+TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback) {
     sta_iface_->registerCallback(
         new IfaceCallback(), [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -178,7 +198,7 @@
 /*
  * GetName
  */
-TEST_F(SupplicantStaIfaceHidlTest, GetName) {
+TEST_P(SupplicantStaIfaceHidlTest, GetName) {
     const auto& status_and_interface_name = HIDL_INVOKE(sta_iface_, getName);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               status_and_interface_name.first.code);
@@ -188,7 +208,7 @@
 /*
  * GetType
  */
-TEST_F(SupplicantStaIfaceHidlTest, GetType) {
+TEST_P(SupplicantStaIfaceHidlTest, GetType) {
     const auto& status_and_interface_type = HIDL_INVOKE(sta_iface_, getType);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               status_and_interface_type.first.code);
@@ -198,14 +218,15 @@
 /*
  * listNetworks.
  */
-TEST_F(SupplicantStaIfaceHidlTest, listNetworks) {
+TEST_P(SupplicantStaIfaceHidlTest, listNetworks) {
     sta_iface_->listNetworks([](const SupplicantStatus& status,
                                 const hidl_vec<SupplicantNetworkId>& ids) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
         EXPECT_EQ(0u, ids.size());
     });
 
-    sp<ISupplicantStaNetwork> sta_network = createSupplicantStaNetwork();
+    sp<ISupplicantStaNetwork> sta_network =
+        createSupplicantStaNetwork(supplicant_);
     EXPECT_NE(nullptr, sta_network.get());
 
     sta_iface_->listNetworks([](const SupplicantStatus& status,
@@ -218,7 +239,7 @@
 /*
  * Reassociate.
  */
-TEST_F(SupplicantStaIfaceHidlTest, Reassociate) {
+TEST_P(SupplicantStaIfaceHidlTest, Reassociate) {
     sta_iface_->reassociate([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -227,7 +248,7 @@
 /*
  * Reconnect.
  */
-TEST_F(SupplicantStaIfaceHidlTest, Reconnect) {
+TEST_P(SupplicantStaIfaceHidlTest, Reconnect) {
     sta_iface_->reconnect([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::FAILURE_IFACE_NOT_DISCONNECTED,
                   status.code);
@@ -237,7 +258,7 @@
 /*
  * Disconnect.
  */
-TEST_F(SupplicantStaIfaceHidlTest, Disconnect) {
+TEST_P(SupplicantStaIfaceHidlTest, Disconnect) {
     sta_iface_->disconnect([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -246,7 +267,7 @@
 /*
  * SetPowerSave.
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetPowerSave) {
+TEST_P(SupplicantStaIfaceHidlTest, SetPowerSave) {
     sta_iface_->setPowerSave(true, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -258,7 +279,7 @@
 /*
  * InitiateTdlsDiscover.
  */
-TEST_F(SupplicantStaIfaceHidlTest, InitiateTdlsDiscover) {
+TEST_P(SupplicantStaIfaceHidlTest, InitiateTdlsDiscover) {
     sta_iface_->initiateTdlsDiscover(
         mac_addr_, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -268,7 +289,7 @@
 /*
  * InitiateTdlsSetup.
  */
-TEST_F(SupplicantStaIfaceHidlTest, InitiateTdlsSetup) {
+TEST_P(SupplicantStaIfaceHidlTest, InitiateTdlsSetup) {
     sta_iface_->initiateTdlsSetup(
         mac_addr_, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -278,7 +299,7 @@
 /*
  * InitiateTdlsTeardown.
  */
-TEST_F(SupplicantStaIfaceHidlTest, InitiateTdlsTeardown) {
+TEST_P(SupplicantStaIfaceHidlTest, InitiateTdlsTeardown) {
     sta_iface_->initiateTdlsTeardown(
         mac_addr_, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -288,7 +309,7 @@
 /*
  * InitiateAnqpQuery.
  */
-TEST_F(SupplicantStaIfaceHidlTest, InitiateAnqpQuery) {
+TEST_P(SupplicantStaIfaceHidlTest, InitiateAnqpQuery) {
     std::vector<ISupplicantStaIface::AnqpInfoId> anqp_ids(
         kTestAnqpInfoIds, kTestAnqpInfoIds + sizeof(kTestAnqpInfoIds));
     std::vector<ISupplicantStaIface::Hs20AnqpSubtypes> hs_types(
@@ -304,7 +325,7 @@
 /*
  * InitiateHs20IconQuery.
  */
-TEST_F(SupplicantStaIfaceHidlTest, InitiateHs20IconQuery) {
+TEST_P(SupplicantStaIfaceHidlTest, InitiateHs20IconQuery) {
     sta_iface_->initiateHs20IconQuery(
         mac_addr_, kTestHs20IconFile, [](const SupplicantStatus& status) {
             // These requests will fail unless the BSSID mentioned is actually
@@ -316,7 +337,7 @@
 /*
  * GetMacAddress.
  */
-TEST_F(SupplicantStaIfaceHidlTest, GetMacAddress) {
+TEST_P(SupplicantStaIfaceHidlTest, GetMacAddress) {
     sta_iface_->getMacAddress([](const SupplicantStatus& status,
                                  const hidl_array<uint8_t, 6>& mac_addr) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -328,7 +349,7 @@
 /*
  * StartRxFilter.
  */
-TEST_F(SupplicantStaIfaceHidlTest, StartRxFilter) {
+TEST_P(SupplicantStaIfaceHidlTest, StartRxFilter) {
     sta_iface_->startRxFilter([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -337,7 +358,7 @@
 /*
  * StopRxFilter.
  */
-TEST_F(SupplicantStaIfaceHidlTest, StopRxFilter) {
+TEST_P(SupplicantStaIfaceHidlTest, StopRxFilter) {
     sta_iface_->stopRxFilter([](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -346,7 +367,7 @@
 /*
  * AddRxFilter.
  */
-TEST_F(SupplicantStaIfaceHidlTest, AddRxFilter) {
+TEST_P(SupplicantStaIfaceHidlTest, AddRxFilter) {
     sta_iface_->addRxFilter(ISupplicantStaIface::RxFilterType::V4_MULTICAST,
                             [](const SupplicantStatus& status) {
                                 EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -362,7 +383,7 @@
 /*
  * RemoveRxFilter.
  */
-TEST_F(SupplicantStaIfaceHidlTest, RemoveRxFilter) {
+TEST_P(SupplicantStaIfaceHidlTest, RemoveRxFilter) {
     sta_iface_->removeRxFilter(ISupplicantStaIface::RxFilterType::V4_MULTICAST,
                                [](const SupplicantStatus& status) {
                                    EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -378,7 +399,7 @@
 /*
  * SetBtCoexistenceMode.
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetBtCoexistenceMode) {
+TEST_P(SupplicantStaIfaceHidlTest, SetBtCoexistenceMode) {
     sta_iface_->setBtCoexistenceMode(
         ISupplicantStaIface::BtCoexistenceMode::ENABLED,
         [](const SupplicantStatus& status) {
@@ -399,7 +420,7 @@
 /*
  * SetBtCoexistenceScanModeEnabled.
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetBtCoexistenceScanModeEnabled) {
+TEST_P(SupplicantStaIfaceHidlTest, SetBtCoexistenceScanModeEnabled) {
     sta_iface_->setBtCoexistenceScanModeEnabled(
         true, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -413,7 +434,7 @@
 /*
  * SetSuspendModeEnabled.
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetSuspendModeEnabled) {
+TEST_P(SupplicantStaIfaceHidlTest, SetSuspendModeEnabled) {
     sta_iface_->setSuspendModeEnabled(true, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -426,7 +447,7 @@
 /*
  * SetCountryCode.
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetCountryCode) {
+TEST_P(SupplicantStaIfaceHidlTest, SetCountryCode) {
     sta_iface_->setCountryCode(
         kTestCountryCode, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -436,7 +457,7 @@
 /*
  * SetWpsDeviceName
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsDeviceName) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsDeviceName) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsDeviceName, kTestWpsDeviceName).code);
@@ -445,7 +466,7 @@
 /*
  * SetWpsDeviceType
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsDeviceType) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsDeviceType) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsDeviceType, kTestWpsDeviceType).code);
@@ -454,7 +475,7 @@
 /*
  * SetWpsManufacturer
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsManufacturer) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsManufacturer) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsManufacturer, kTestWpsManufacturer).code);
@@ -463,7 +484,7 @@
 /*
  * SetWpsModelName
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsModelName) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsModelName) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_iface_, setWpsModelName, kTestWpsModelName).code);
 }
@@ -471,7 +492,7 @@
 /*
  * SetWpsModelNumber
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsModelNumber) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsModelNumber) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsModelNumber, kTestWpsModelNumber).code);
@@ -480,7 +501,7 @@
 /*
  * SetWpsSerialNumber
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsSerialNumber) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsSerialNumber) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsSerialNumber, kTestWpsSerialNumber).code);
@@ -489,7 +510,7 @@
 /*
  * SetWpsConfigMethods
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetWpsConfigMethods) {
+TEST_P(SupplicantStaIfaceHidlTest, SetWpsConfigMethods) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, setWpsConfigMethods, kTestWpsConfigMethods)
@@ -499,7 +520,7 @@
 /*
  * SetExternalSim
  */
-TEST_F(SupplicantStaIfaceHidlTest, SetExternalSim) {
+TEST_P(SupplicantStaIfaceHidlTest, SetExternalSim) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_iface_, setExternalSim, true).code);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -509,7 +530,7 @@
 /*
  * AddExtRadioWork
  */
-TEST_F(SupplicantStaIfaceHidlTest, AddExtRadioWork) {
+TEST_P(SupplicantStaIfaceHidlTest, AddExtRadioWork) {
     const auto& status_and_radio_work_id =
         HIDL_INVOKE(sta_iface_, addExtRadioWork, kTestRadioWorkName,
                     kTestRadioWorkFrequency, kTestRadioWorkTimeout);
@@ -524,9 +545,18 @@
 /*
  * RemoveExtRadioWork
  */
-TEST_F(SupplicantStaIfaceHidlTest, RemoveExtRadioWork) {
+TEST_P(SupplicantStaIfaceHidlTest, RemoveExtRadioWork) {
     // This fails because there is no on going radio work with kTestRadioWorkId.
     EXPECT_NE(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_iface_, removeExtRadioWork, kTestRadioWorkId).code);
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaIfaceHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            ISupplicant::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
index 832dd41..52f77a1 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -16,14 +16,16 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "supplicant_hidl_call_util.h"
 #include "supplicant_hidl_test_utils.h"
+#include "wifi_hidl_test_utils.h"
 
 using ::android::sp;
 using ::android::hardware::hidl_array;
@@ -32,12 +34,14 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
 using ::android::hardware::wifi::supplicant::V1_0::
     ISupplicantStaNetworkCallback;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::V1_0::IWifi;
 
 namespace {
 constexpr char kTestSsidStr[] = "TestSsid1234";
@@ -74,37 +78,50 @@
      ISupplicantStaNetwork::PairwiseCipherMask::TKIP);
 }  // namespace
 
-class SupplicantStaNetworkHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantStaNetworkHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        EXPECT_TRUE(turnOnExcessiveLogging());
-        sta_network_ = createSupplicantStaNetwork();
+        wifi_instance_name_ = std::get<0>(GetParam());
+        supplicant_instance_name_ = std::get<1>(GetParam());
+        stopSupplicant(wifi_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                             supplicant_instance_name_);
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        supplicant_ = getSupplicant(supplicant_instance_name_, isP2pOn_);
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_network_ = createSupplicantStaNetwork(supplicant_);
         ASSERT_NE(sta_network_.get(), nullptr);
 
         ssid_.assign(kTestSsidStr, kTestSsidStr + strlen(kTestSsidStr));
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
+    virtual void TearDown() override { stopSupplicant(wifi_instance_name_); }
 
    protected:
     void removeNetwork() {
-      sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface();
-      ASSERT_NE(nullptr, sta_iface.get());
-      uint32_t net_id;
-      sta_network_->getId([&](const SupplicantStatus& status, int network_id) {
-              ASSERT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-              net_id = network_id;
-          });
-      sta_iface->removeNetwork(net_id, [](const SupplicantStatus& status) {
-              ASSERT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-          });
+        sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface(supplicant_);
+        ASSERT_NE(nullptr, sta_iface.get());
+        uint32_t net_id;
+        sta_network_->getId(
+            [&](const SupplicantStatus& status, int network_id) {
+                ASSERT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                net_id = network_id;
+            });
+        sta_iface->removeNetwork(net_id, [](const SupplicantStatus& status) {
+            ASSERT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
     }
 
+    bool isP2pOn_ = false;
+    sp<ISupplicant> supplicant_;
     // ISupplicantStaNetwork object used for all tests in this fixture.
     sp<ISupplicantStaNetwork> sta_network_;
     // SSID to use for various tests.
     std::vector<uint8_t> ssid_;
+    std::string wifi_instance_name_;
+    std::string supplicant_instance_name_;
 };
 
 class NetworkCallback : public ISupplicantStaNetworkCallback {
@@ -126,16 +143,20 @@
  * Ensures that an instance of the ISupplicantStaNetwork proxy object is
  * successfully created.
  */
-TEST(SupplicantStaNetworkHidlTestNoFixture, Create) {
-    startSupplicantAndWaitForHidlService();
-    EXPECT_NE(nullptr, createSupplicantStaNetwork().get());
-    stopSupplicant();
+TEST_P(SupplicantStaNetworkHidlTest, Create) {
+    stopSupplicant(wifi_instance_name_);
+    startSupplicantAndWaitForHidlService(wifi_instance_name_,
+                                         supplicant_instance_name_);
+    sp<ISupplicant> supplicant =
+        getSupplicant(supplicant_instance_name_, isP2pOn_);
+    EXPECT_TRUE(turnOnExcessiveLogging(supplicant));
+    EXPECT_NE(nullptr, createSupplicantStaNetwork(supplicant).get());
 }
 
 /*
  * RegisterCallback
  */
-TEST_F(SupplicantStaNetworkHidlTest, RegisterCallback) {
+TEST_P(SupplicantStaNetworkHidlTest, RegisterCallback) {
     sta_network_->registerCallback(
         new NetworkCallback(), [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -145,7 +166,7 @@
 /*
  * GetInterfaceName
  */
-TEST_F(SupplicantStaNetworkHidlTest, GetInterfaceName) {
+TEST_P(SupplicantStaNetworkHidlTest, GetInterfaceName) {
     const auto& status_and_interface_name =
         HIDL_INVOKE(sta_network_, getInterfaceName);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -156,7 +177,7 @@
 /*
  * GetType
  */
-TEST_F(SupplicantStaNetworkHidlTest, GetType) {
+TEST_P(SupplicantStaNetworkHidlTest, GetType) {
     const auto& status_and_interface_type = HIDL_INVOKE(sta_network_, getType);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               status_and_interface_type.first.code);
@@ -167,7 +188,7 @@
 /*
  * SetGetSsid
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetSsid) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetSsid) {
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -181,7 +202,7 @@
 /*
  * SetGetBssid
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetBssid) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetBssid) {
     std::array<uint8_t, 6> set_bssid;
     memcpy(set_bssid.data(), kTestBssid, set_bssid.size());
     sta_network_->setBssid(set_bssid, [](const SupplicantStatus& status) {
@@ -199,7 +220,7 @@
 /*
  * SetGetKeyMgmt
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt) {
     sta_network_->setKeyMgmt(kTestKeyMgmt, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -213,7 +234,7 @@
 /*
  * SetGetProto
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetProto) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetProto) {
     sta_network_->setProto(kTestProto, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -226,7 +247,7 @@
 /*
  * SetGetKeyAuthAlg
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetAuthAlg) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetAuthAlg) {
     sta_network_->setAuthAlg(kTestAuthAlg, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -240,7 +261,7 @@
 /*
  * SetGetGroupCipher
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher) {
     sta_network_->setGroupCipher(
         kTestGroupCipher, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -255,7 +276,7 @@
 /*
  * SetGetPairwiseCipher
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher) {
     sta_network_->setPairwiseCipher(
         kTestPairwiseCipher, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -270,7 +291,7 @@
 /*
  * SetGetPskPassphrase
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetPskPassphrase) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetPskPassphrase) {
     sta_network_->setPskPassphrase(
         kTestPskPassphrase, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -285,7 +306,7 @@
 /*
  * SetGetPsk
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetPsk) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetPsk) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, setPsk, kTestPsk).code);
     const auto& status_and_psk = HIDL_INVOKE(sta_network_, getPsk);
@@ -297,7 +318,7 @@
 /*
  * SetGetWepKeys
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetWepTxKeyIdx) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetWepTxKeyIdx) {
     sta_network_->setWepTxKeyIdx(
         kTestWepTxKeyIdx, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -312,7 +333,7 @@
 /*
  * SetGetWepKeys
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetWepKeys) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetWepKeys) {
     for (uint32_t i = 0;
          i < static_cast<uint32_t>(
                  ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM);
@@ -334,7 +355,7 @@
 /*
  * SetGetScanSsid
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetScanSsid) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetScanSsid) {
     sta_network_->setScanSsid(
         true, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -349,7 +370,7 @@
 /*
  * SetGetRequirePmf
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetRequirePmf) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetRequirePmf) {
     sta_network_->setRequirePmf(
         true, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -364,7 +385,7 @@
 /*
  * SetGetIdStr
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetIdStr) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetIdStr) {
     sta_network_->setIdStr(
         kTestIdStr, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -376,11 +397,10 @@
         });
 }
 
-
 /*
  * SetGetEapMethod
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapMethod) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapMethod) {
     ISupplicantStaNetwork::EapMethod set_eap_method =
         ISupplicantStaNetwork::EapMethod::PEAP;
     sta_network_->setEapMethod(
@@ -398,7 +418,7 @@
 /*
  * SetGetEapPhase2Method
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapPhase2Method) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapPhase2Method) {
     ISupplicantStaNetwork::EapMethod set_eap_method =
         ISupplicantStaNetwork::EapMethod::PEAP;
     sta_network_->setEapMethod(
@@ -422,7 +442,7 @@
 /*
  * SetGetEapIdentity
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapIdentity) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapIdentity) {
     std::vector<uint8_t> set_identity(kTestIdentity, kTestIdentity + sizeof(kTestIdentity));
     sta_network_->setEapIdentity(
         set_identity, [](const SupplicantStatus& status) {
@@ -438,7 +458,7 @@
 /*
  * SetGetEapAnonymousIdentity
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapAnonymousIdentity) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapAnonymousIdentity) {
     std::vector<uint8_t> set_identity(kTestIdentity, kTestIdentity + sizeof(kTestIdentity));
     sta_network_->setEapAnonymousIdentity(
         set_identity, [](const SupplicantStatus& status) {
@@ -454,7 +474,7 @@
 /*
  * SetGetEapPassword
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapPassword) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapPassword) {
     std::vector<uint8_t> set_eap_passwd(
         kTestEapPasswdStr, kTestEapPasswdStr + strlen(kTestEapPasswdStr));
     sta_network_->setEapPassword(
@@ -471,7 +491,7 @@
 /*
  * SetGetEapCACert
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapCACert) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapCACert) {
     sta_network_->setEapCACert(
         kTestEapCert, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -486,7 +506,7 @@
 /*
  * SetGetEapCAPath
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapCAPath) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapCAPath) {
     sta_network_->setEapCAPath(
         kTestEapCert, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -501,7 +521,7 @@
 /*
  * SetGetEapClientCert
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapClientCert) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapClientCert) {
     sta_network_->setEapClientCert(
         kTestEapCert, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -516,7 +536,7 @@
 /*
  * SetGetEapPrivateKeyId
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapPrivateKeyId) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapPrivateKeyId) {
     sta_network_->setEapPrivateKeyId(
         kTestEapPrivateKeyId, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -531,7 +551,7 @@
 /*
  * SetGetEapAltSubjectMatch
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapAltSubjectMatch) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapAltSubjectMatch) {
     sta_network_->setEapAltSubjectMatch(
         kTestEapMatch, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -546,7 +566,7 @@
 /*
  * SetGetEapSubjectMatch
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapSubjectMatch) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapSubjectMatch) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_network_, setEapSubjectMatch, kTestEapMatch).code);
@@ -561,7 +581,7 @@
 /*
  * SetGetEapDomainSuffixMatch
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapDomainSuffixMatch) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapDomainSuffixMatch) {
     sta_network_->setEapDomainSuffixMatch(
         kTestEapMatch, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -576,7 +596,7 @@
 /*
  * SetGetEapEngine
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapEngine) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapEngine) {
     sta_network_->setEapEngine(
         true, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -591,7 +611,7 @@
 /*
  * SetGetEapEngineID
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetEapEngineID) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetEapEngineID) {
     sta_network_->setEapEngineID(
         kTestEapEngineID, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -606,7 +626,7 @@
 /*
  * Enable
  */
-TEST_F(SupplicantStaNetworkHidlTest, Enable) {
+TEST_P(SupplicantStaNetworkHidlTest, Enable) {
     // wpa_supplicant doesn't perform any connection initiation
     // unless atleast the Ssid and Ket mgmt params are set.
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
@@ -633,7 +653,7 @@
 /*
  * Disable
  */
-TEST_F(SupplicantStaNetworkHidlTest, Disable) {
+TEST_P(SupplicantStaNetworkHidlTest, Disable) {
     // wpa_supplicant doesn't perform any connection initiation
     // unless atleast the Ssid and Ket mgmt params are set.
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
@@ -656,7 +676,7 @@
 /*
  * Select.
  */
-TEST_F(SupplicantStaNetworkHidlTest, Select) {
+TEST_P(SupplicantStaNetworkHidlTest, Select) {
     // wpa_supplicant doesn't perform any connection initiation
     // unless atleast the Ssid and Ket mgmt params are set.
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
@@ -679,7 +699,7 @@
 /*
  * SendNetworkEapSimGsmAuthResponse
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimGsmAuthResponse) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapSimGsmAuthResponse) {
     std::vector<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
         params;
     ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams param;
@@ -695,7 +715,7 @@
 /*
  * SendNetworkEapSimGsmAuthFailure
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimGsmAuthFailure) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapSimGsmAuthFailure) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, sendNetworkEapSimGsmAuthFailure).code);
 }
@@ -703,7 +723,7 @@
 /*
  * SendNetworkEapSimUmtsAuthResponse
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAuthResponse) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAuthResponse) {
     ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams params;
     params.res = std::vector<uint8_t>(kTestRes, kTestRes + sizeof(kTestRes));
     memcpy(params.ik.data(), kTestIk, params.ik.size());
@@ -717,7 +737,7 @@
 /*
  * SendNetworkEapSimUmtsAuthFailure
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAuthFailure) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAuthFailure) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, sendNetworkEapSimUmtsAuthFailure).code);
 }
@@ -725,7 +745,7 @@
 /*
  * SendNetworkEapSimUmtsAutsResponse
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAutsResponse) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAutsResponse) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, sendNetworkEapSimUmtsAutsResponse,
                           kTestAutParam)
@@ -735,7 +755,7 @@
 /*
  * SendNetworkEapIdentityResponse
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse) {
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse) {
     sta_network_->sendNetworkEapIdentityResponse(
         std::vector<uint8_t>(kTestIdentity,
                              kTestIdentity + sizeof(kTestIdentity)),
@@ -747,7 +767,7 @@
 /*
  * SetUpdateIdentifier
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetUpdateIdentifier) {
+TEST_P(SupplicantStaNetworkHidlTest, SetUpdateIdentifier) {
     EXPECT_EQ(
         SupplicantStatusCode::SUCCESS,
         HIDL_INVOKE(sta_network_, setUpdateIdentifier, kTestUpdateIdentifier)
@@ -757,7 +777,7 @@
 /*
  * SetProactiveKeyCaching
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetProactiveKeyCaching) {
+TEST_P(SupplicantStaNetworkHidlTest, SetProactiveKeyCaching) {
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, setProactiveKeyCaching, true).code);
     EXPECT_EQ(SupplicantStatusCode::SUCCESS,
@@ -767,7 +787,7 @@
 /*
  * GetWpsNfcConfigurationToken
  */
-TEST_F(SupplicantStaNetworkHidlTest, GetWpsNfcConfigurationToken) {
+TEST_P(SupplicantStaNetworkHidlTest, GetWpsNfcConfigurationToken) {
     ASSERT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, setSsid, ssid_).code);
     ASSERT_EQ(SupplicantStatusCode::SUCCESS,
@@ -780,3 +800,12 @@
     EXPECT_EQ(SupplicantStatusCode::SUCCESS, status_and_token.first.code);
     EXPECT_FALSE(0 == status_and_token.second.size());
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaNetworkHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            ISupplicant::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file