Merge "Convert VtsHalWifiSupplicantV1_*TargetTest to be parameterized test"
diff --git a/audio/effect/2.0/xml/Android.bp b/audio/effect/2.0/xml/Android.bp
new file mode 100644
index 0000000..050425a
--- /dev/null
+++ b/audio/effect/2.0/xml/Android.bp
@@ -0,0 +1,8 @@
+genrule {
+    name: "audio_effects_conf_V2_0",
+    srcs: ["audio_effects_conf.xsd"],
+    out: [
+        "audio_effects_conf_V2_0.xsd",
+    ],
+    cmd: "cp -f $(in) $(genDir)/audio_effects_conf_V2_0.xsd",
+}
diff --git a/audio/effect/4.0/xml/Android.bp b/audio/effect/4.0/xml/Android.bp
new file mode 100644
index 0000000..27ffd02
--- /dev/null
+++ b/audio/effect/4.0/xml/Android.bp
@@ -0,0 +1,8 @@
+genrule {
+    name: "audio_effects_conf_V4_0",
+    srcs: ["audio_effects_conf.xsd"],
+    out: [
+        "audio_effects_conf_V4_0.xsd",
+    ],
+    cmd: "cp -f $(in) $(genDir)/audio_effects_conf_V4_0.xsd",
+}
diff --git a/audio/effect/5.0/xml/Android.bp b/audio/effect/5.0/xml/Android.bp
index eb2bcee..67b2f97 100644
--- a/audio/effect/5.0/xml/Android.bp
+++ b/audio/effect/5.0/xml/Android.bp
@@ -1,4 +1,3 @@
-
 xsd_config {
     name: "audio_effects_conf_V5_0",
     srcs: ["audio_effects_conf.xsd"],
diff --git a/audio/effect/6.0/xml/Android.bp b/audio/effect/6.0/xml/Android.bp
index 353686b..8d68672 100644
--- a/audio/effect/6.0/xml/Android.bp
+++ b/audio/effect/6.0/xml/Android.bp
@@ -1,4 +1,3 @@
-
 xsd_config {
     name: "audio_effects_conf_V6_0",
     srcs: ["audio_effects_conf.xsd"],
diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp
index edc9076..4ab572e 100644
--- a/audio/effect/all-versions/vts/functional/Android.bp
+++ b/audio/effect/all-versions/vts/functional/Android.bp
@@ -31,16 +31,22 @@
     header_libs: [
         "android.hardware.audio.common.util@all-versions",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
 cc_test {
     name: "VtsHalAudioEffectV2_0TargetTest",
     defaults: ["VtsHalAudioEffectTargetTest_default"],
+    // Use test_config for vts-core suite.
+    // TODO(b/146104851): Add auto-gen rules and remove it.
+    test_config: "VtsHalAudioEffectV2_0TargetTest.xml",
     static_libs: [
         "android.hardware.audio.common@2.0",
         "android.hardware.audio.effect@2.0",
     ],
+    data: [
+        ":audio_effects_conf_V2_0",
+    ],
     cflags: [
         "-DMAJOR_VERSION=2",
         "-DMINOR_VERSION=0",
@@ -51,10 +57,16 @@
 cc_test {
     name: "VtsHalAudioEffectV4_0TargetTest",
     defaults: ["VtsHalAudioEffectTargetTest_default"],
+    // Use test_config for vts-core suite.
+    // TODO(b/146104851): Add auto-gen rules and remove it.
+    test_config: "VtsHalAudioEffectV4_0TargetTest.xml",
     static_libs: [
         "android.hardware.audio.common@4.0",
         "android.hardware.audio.effect@4.0",
     ],
+    data: [
+        ":audio_effects_conf_V4_0",
+    ],
     cflags: [
         "-DMAJOR_VERSION=4",
         "-DMINOR_VERSION=0",
@@ -65,10 +77,16 @@
 cc_test {
     name: "VtsHalAudioEffectV5_0TargetTest",
     defaults: ["VtsHalAudioEffectTargetTest_default"],
+    // Use test_config for vts-core suite.
+    // TODO(b/146104851): Add auto-gen rules and remove it.
+    test_config: "VtsHalAudioEffectV5_0TargetTest.xml",
     static_libs: [
         "android.hardware.audio.common@5.0",
         "android.hardware.audio.effect@5.0",
     ],
+    data: [
+        ":audio_effects_conf_V5_0",
+    ],
     cflags: [
         "-DMAJOR_VERSION=5",
         "-DMINOR_VERSION=0",
@@ -79,10 +97,16 @@
 cc_test {
     name: "VtsHalAudioEffectV6_0TargetTest",
     defaults: ["VtsHalAudioEffectTargetTest_default"],
+    // Use test_config for vts-core suite.
+    // TODO(b/146104851): Add auto-gen rules and remove it.
+    test_config: "VtsHalAudioEffectV6_0TargetTest.xml",
     static_libs: [
         "android.hardware.audio.common@6.0",
         "android.hardware.audio.effect@6.0",
     ],
+    data: [
+        ":audio_effects_conf_V6_0",
+    ],
     cflags: [
         "-DMAJOR_VERSION=6",
         "-DMINOR_VERSION=0",
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index c151d3a..390d4ee 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -28,14 +28,9 @@
 
 #include <common/all-versions/VersionUtils.h>
 
-#if MAJOR_VERSION <= 5
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-#elif MAJOR_VERSION >= 6
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
-#endif
 
 using ::android::sp;
 using ::android::hardware::hidl_handle;
@@ -55,45 +50,12 @@
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 #endif
 
-#if MAJOR_VERSION <= 5
-// For HAL versions 2..5 Vts Environment and Test base classes are used.
-// The tests are non-parametrized.
-#define EFFECT_TEST TEST_F
-
-// Test environment for Audio Effects Factory HIDL HAL.
-class AudioEffectsFactoryHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static AudioEffectsFactoryHidlEnvironment* Instance() {
-        static AudioEffectsFactoryHidlEnvironment* instance =
-            new AudioEffectsFactoryHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IEffectsFactory>(); }
-};
-
-// The main test class for Audio Effects Factory HIDL HAL.
-class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
-    void SetUp() override {
-        effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>(
-            AudioEffectsFactoryHidlEnvironment::Instance()->getServiceName<IEffectsFactory>());
-        ASSERT_NE(effectsFactory, nullptr);
-    }
-
-#elif MAJOR_VERSION >= 6
-// For HAL version 6 and above, standard GTest Environment and Test base classes are used.
-// The tests are parametrized by the IEffectsFactory instance name.
-#define EFFECT_TEST TEST_P
-
 class AudioEffectsFactoryHidlTest : public ::testing::TestWithParam<std::string> {
   public:
     void SetUp() override {
         effectsFactory = IEffectsFactory::getService(GetParam());
         ASSERT_NE(effectsFactory, nullptr);
     }
-#endif  // The rest of the AudioEffectsFactoryHidlTest class definition is the same.
     void TearDown() override { effectsFactory.clear(); }
 
    protected:
@@ -104,7 +66,7 @@
     sp<IEffectsFactory> effectsFactory;
 };
 
-EFFECT_TEST(AudioEffectsFactoryHidlTest, EnumerateEffects) {
+TEST_P(AudioEffectsFactoryHidlTest, EnumerateEffects) {
     description("Verify that EnumerateEffects returns at least one effect");
     Result retval = Result::NOT_INITIALIZED;
     size_t effectCount = 0;
@@ -118,7 +80,7 @@
     EXPECT_GT(effectCount, 0u);
 }
 
-EFFECT_TEST(AudioEffectsFactoryHidlTest, CreateEffect) {
+TEST_P(AudioEffectsFactoryHidlTest, CreateEffect) {
     description("Verify that an effect can be created via CreateEffect");
     bool gotEffect = false;
     Uuid effectUuid;
@@ -149,7 +111,7 @@
     EXPECT_NE(nullptr, effect.get());
 }
 
-EFFECT_TEST(AudioEffectsFactoryHidlTest, GetDescriptor) {
+TEST_P(AudioEffectsFactoryHidlTest, GetDescriptor) {
     description(
         "Verify that effects factory can provide an effect descriptor via "
         "GetDescriptor");
@@ -172,7 +134,7 @@
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) {
+TEST_P(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) {
     description("Verify that debugDump doesn't crash on invalid arguments");
 #if MAJOR_VERSION == 2
     Return<void> ret = effectsFactory->debugDump(hidl_handle());
@@ -194,17 +156,10 @@
     std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}};
 
 // The main test class for Audio Effect HIDL HAL.
-#if MAJOR_VERSION <= 5
-class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
-    void SetUp() override {
-        effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>();
-#elif MAJOR_VERSION >= 6
 class AudioEffectHidlTest : public ::testing::TestWithParam<std::string> {
   public:
     void SetUp() override {
         effectsFactory = IEffectsFactory::getService(GetParam());
-#endif
         ASSERT_NE(nullptr, effectsFactory.get());
 
         findAndCreateEffect(getEffectType());
@@ -286,14 +241,14 @@
         static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels));
 }
 
-EFFECT_TEST(AudioEffectHidlTest, Close) {
+TEST_P(AudioEffectHidlTest, Close) {
     description("Verify that an effect can be closed");
     Return<Result> ret = effect->close();
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, GetDescriptor) {
+TEST_P(AudioEffectHidlTest, GetDescriptor) {
     description("Verify that an effect can return its own descriptor via GetDescriptor");
     Result retval = Result::NOT_INITIALIZED;
     Uuid actualType;
@@ -308,7 +263,7 @@
     EXPECT_EQ(getEffectType(), actualType);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, GetSetConfig) {
+TEST_P(AudioEffectHidlTest, GetSetConfig) {
     description(
         "Verify that it is possible to manipulate effect config via Get / "
         "SetConfig");
@@ -327,26 +282,26 @@
     EXPECT_EQ(Result::OK, ret2);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, GetConfigReverse) {
+TEST_P(AudioEffectHidlTest, GetConfigReverse) {
     description("Verify that GetConfigReverse does not crash");
     Return<void> ret = effect->getConfigReverse([&](Result, const EffectConfig&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) {
+TEST_P(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) {
     description("Verify that GetSupportedAuxChannelsConfigs does not crash");
     Return<void> ret = effect->getSupportedAuxChannelsConfigs(
         0, [&](Result, const hidl_vec<EffectAuxChannelsConfig>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, GetAuxChannelsConfig) {
+TEST_P(AudioEffectHidlTest, GetAuxChannelsConfig) {
     description("Verify that GetAuxChannelsConfig does not crash");
     Return<void> ret = effect->getAuxChannelsConfig([&](Result, const EffectAuxChannelsConfig&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, SetAuxChannelsConfig) {
+TEST_P(AudioEffectHidlTest, SetAuxChannelsConfig) {
     description("Verify that SetAuxChannelsConfig does not crash");
     Return<Result> ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig());
     EXPECT_TRUE(ret.isOk());
@@ -385,7 +340,7 @@
 }  // namespace hardware
 }  // namespace android
 
-EFFECT_TEST(AudioEffectHidlTest, Reset) {
+TEST_P(AudioEffectHidlTest, Reset) {
     description("Verify that Reset preserves effect configuration");
     Result retval = Result::NOT_INITIALIZED;
     EffectConfig originalConfig;
@@ -410,7 +365,7 @@
     EXPECT_EQ(originalConfig, configAfterReset);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, DisableEnableDisable) {
+TEST_P(AudioEffectHidlTest, DisableEnableDisable) {
     description("Verify Disable -> Enable -> Disable sequence for an effect");
     Return<Result> ret = effect->disable();
     EXPECT_TRUE(ret.isOk());
@@ -423,14 +378,14 @@
     EXPECT_EQ(Result::OK, ret);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, SetDevice) {
+TEST_P(AudioEffectHidlTest, SetDevice) {
     description("Verify that SetDevice works for an output chain effect");
     Return<Result> ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER));
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, SetAndGetVolume) {
+TEST_P(AudioEffectHidlTest, SetAndGetVolume) {
     description("Verify that SetAndGetVolume method works for an effect");
     uint32_t channelCount;
     getChannelCount(&channelCount);
@@ -446,7 +401,7 @@
     EXPECT_EQ(Result::OK, retval);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, VolumeChangeNotification) {
+TEST_P(AudioEffectHidlTest, VolumeChangeNotification) {
     description("Verify that effect accepts VolumeChangeNotification");
     uint32_t channelCount;
     getChannelCount(&channelCount);
@@ -460,32 +415,32 @@
     EXPECT_EQ(Result::OK, ret);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, SetAudioMode) {
+TEST_P(AudioEffectHidlTest, SetAudioMode) {
     description("Verify that SetAudioMode works for an effect");
     Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL);
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, SetConfigReverse) {
+TEST_P(AudioEffectHidlTest, SetConfigReverse) {
     description("Verify that SetConfigReverse does not crash");
     Return<Result> ret = effect->setConfigReverse(EffectConfig(), nullptr, nullptr);
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, SetInputDevice) {
+TEST_P(AudioEffectHidlTest, SetInputDevice) {
     description("Verify that SetInputDevice does not crash");
     Return<Result> ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC));
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, SetAudioSource) {
+TEST_P(AudioEffectHidlTest, SetAudioSource) {
     description("Verify that SetAudioSource does not crash");
     Return<Result> ret = effect->setAudioSource(AudioSource::MIC);
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, Offload) {
+TEST_P(AudioEffectHidlTest, Offload) {
     description("Verify that calling Offload method does not crash");
     EffectOffloadParameter offloadParam;
     offloadParam.isOffload = false;
@@ -494,7 +449,7 @@
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, PrepareForProcessing) {
+TEST_P(AudioEffectHidlTest, PrepareForProcessing) {
     description("Verify that PrepareForProcessing method works for an effect");
     Result retval = Result::NOT_INITIALIZED;
     Return<void> ret = effect->prepareForProcessing(
@@ -503,7 +458,7 @@
     EXPECT_EQ(Result::OK, retval);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, SetProcessBuffers) {
+TEST_P(AudioEffectHidlTest, SetProcessBuffers) {
     description("Verify that SetProcessBuffers works for an effect");
     sp<IAllocator> ashmem = IAllocator::getService("ashmem");
     ASSERT_NE(nullptr, ashmem.get());
@@ -522,41 +477,41 @@
     EXPECT_EQ(Result::OK, ret2);
 }
 
-EFFECT_TEST(AudioEffectHidlTest, Command) {
+TEST_P(AudioEffectHidlTest, Command) {
     description("Verify that Command does not crash");
     Return<void> ret =
         effect->command(0, hidl_vec<uint8_t>(), 0, [&](int32_t, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, SetParameter) {
+TEST_P(AudioEffectHidlTest, SetParameter) {
     description("Verify that SetParameter does not crash");
     Return<Result> ret = effect->setParameter(hidl_vec<uint8_t>(), hidl_vec<uint8_t>());
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, GetParameter) {
+TEST_P(AudioEffectHidlTest, GetParameter) {
     description("Verify that GetParameter does not crash");
     Return<void> ret =
         effect->getParameter(hidl_vec<uint8_t>(), 0, [&](Result, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
+TEST_P(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
     description("Verify that GetSupportedConfigsForFeature does not crash");
     Return<void> ret = effect->getSupportedConfigsForFeature(
         0, 0, 0, [&](Result, uint32_t, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, GetCurrentConfigForFeature) {
+TEST_P(AudioEffectHidlTest, GetCurrentConfigForFeature) {
     description("Verify that GetCurrentConfigForFeature does not crash");
     Return<void> ret =
         effect->getCurrentConfigForFeature(0, 0, [&](Result, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-EFFECT_TEST(AudioEffectHidlTest, SetCurrentConfigForFeature) {
+TEST_P(AudioEffectHidlTest, SetCurrentConfigForFeature) {
     description("Verify that SetCurrentConfigForFeature does not crash");
     Return<Result> ret = effect->setCurrentConfigForFeature(0, hidl_vec<uint8_t>());
     EXPECT_TRUE(ret.isOk());
@@ -642,21 +597,21 @@
     ASSERT_EQ(Result::OK, retval);
 }
 
-EFFECT_TEST(EqualizerAudioEffectHidlTest, GetNumBands) {
+TEST_P(EqualizerAudioEffectHidlTest, GetNumBands) {
     description("Verify that Equalizer effect reports at least one band");
     uint16_t numBands = 0;
     getNumBands(&numBands);
     EXPECT_GT(numBands, 0);
 }
 
-EFFECT_TEST(EqualizerAudioEffectHidlTest, GetLevelRange) {
+TEST_P(EqualizerAudioEffectHidlTest, GetLevelRange) {
     description("Verify that Equalizer effect reports adequate band level range");
     int16_t minLevel = 0x7fff, maxLevel = 0;
     getLevelRange(&minLevel, &maxLevel);
     EXPECT_GT(maxLevel, minLevel);
 }
 
-EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
+TEST_P(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
     description("Verify that manipulating band levels works for Equalizer effect");
     uint16_t numBands = 0;
     getNumBands(&numBands);
@@ -685,7 +640,7 @@
     }
 }
 
-EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
+TEST_P(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
     description("Verify that Equalizer effect reports adequate band frequency range");
     uint16_t numBands = 0;
     getNumBands(&numBands);
@@ -700,7 +655,7 @@
     }
 }
 
-EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
+TEST_P(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
     description("Verify that Equalizer effect supports GetBandForFrequency correctly");
     uint16_t numBands = 0;
     getNumBands(&numBands);
@@ -729,14 +684,14 @@
     }
 }
 
-EFFECT_TEST(EqualizerAudioEffectHidlTest, GetPresetNames) {
+TEST_P(EqualizerAudioEffectHidlTest, GetPresetNames) {
     description("Verify that Equalizer effect reports at least one preset");
     size_t presetCount;
     getPresetCount(&presetCount);
     EXPECT_GT(presetCount, 0u);
 }
 
-EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
+TEST_P(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
     description("Verify that manipulating the current preset for Equalizer effect");
     size_t presetCount;
     getPresetCount(&presetCount);
@@ -759,7 +714,7 @@
     }
 }
 
-EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
+TEST_P(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
     description(
         "Verify that setting band levels and presets works via Get / "
         "SetAllProperties for Equalizer effect");
@@ -823,7 +778,7 @@
     sp<ILoudnessEnhancerEffect> enhancer;
 };
 
-EFFECT_TEST(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
+TEST_P(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
     description(
         "Verify that manipulating the target gain works for Loudness Enhancer "
         "effect");
@@ -844,21 +799,15 @@
     EXPECT_EQ(gain, actualGain);
 }
 
-#if MAJOR_VERSION <= 5
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(AudioEffectsFactoryHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    AudioEffectsFactoryHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
-#elif MAJOR_VERSION >= 6
 INSTANTIATE_TEST_SUITE_P(
         EffectsFactory, AudioEffectsFactoryHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
         android::hardware::PrintInstanceNameToString);
 INSTANTIATE_TEST_SUITE_P(
+        Equalizer, AudioEffectHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(
         Equalizer, EqualizerAudioEffectHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
         android::hardware::PrintInstanceNameToString);
@@ -866,4 +815,3 @@
         LoudnessEnhancer, LoudnessEnhancerAudioEffectHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
         android::hardware::PrintInstanceNameToString);
-#endif
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV2_0TargetTest.xml b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV2_0TargetTest.xml
new file mode 100644
index 0000000..b6e720b
--- /dev/null
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV2_0TargetTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalAudioEffectV2_0TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="stop"/>
+        <option name="run-command" value="setprop vts.native_server.on 1"/>
+        <option name="teardown-command" value="start"/>
+        <option name="teardown-command" value="setprop vts.native_server.on 0"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalAudioEffectV2_0TargetTest->/data/local/tmp/VtsHalAudioEffectV2_0TargetTest" />
+        <option name="push" value="audio_effects_conf_V2_0.xsd->/data/local/tmp/audio_effects_conf_V2_0.xsd" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalAudioEffectV2_0TargetTest" />
+    </test>
+</configuration>
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV4_0TargetTest.xml b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV4_0TargetTest.xml
new file mode 100644
index 0000000..df826c8
--- /dev/null
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV4_0TargetTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalAudioEffectV4_0TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="stop"/>
+        <option name="run-command" value="setprop vts.native_server.on 1"/>
+        <option name="teardown-command" value="start"/>
+        <option name="teardown-command" value="setprop vts.native_server.on 0"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalAudioEffectV4_0TargetTest->/data/local/tmp/VtsHalAudioEffectV4_0TargetTest" />
+        <option name="push" value="audio_effects_conf_V4_0.xsd->/data/local/tmp/audio_effects_conf_V4_0.xsd" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalAudioEffectV4_0TargetTest" />
+    </test>
+</configuration>
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV5_0TargetTest.xml b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV5_0TargetTest.xml
new file mode 100644
index 0000000..14bdf43
--- /dev/null
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV5_0TargetTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalAudioEffectV5_0TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="stop"/>
+        <option name="run-command" value="setprop vts.native_server.on 1"/>
+        <option name="teardown-command" value="start"/>
+        <option name="teardown-command" value="setprop vts.native_server.on 0"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalAudioEffectV5_0TargetTest->/data/local/tmp/VtsHalAudioEffectV5_0TargetTest" />
+        <option name="push" value="audio_effects_conf_V5_0.xsd->/data/local/tmp/audio_effects_conf_V5_0.xsd" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalAudioEffectV5_0TargetTest" />
+    </test>
+</configuration>
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV6_0TargetTest.xml b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV6_0TargetTest.xml
new file mode 100644
index 0000000..23adad0
--- /dev/null
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV6_0TargetTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalAudioEffectV6_0TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="stop"/>
+        <option name="run-command" value="setprop vts.native_server.on 1"/>
+        <option name="teardown-command" value="start"/>
+        <option name="teardown-command" value="setprop vts.native_server.on 0"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalAudioEffectV6_0TargetTest->/data/local/tmp/VtsHalAudioEffectV6_0TargetTest" />
+        <option name="push" value="audio_effects_conf_V6_0.xsd->/data/local/tmp/audio_effects_conf_V6_0.xsd" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalAudioEffectV6_0TargetTest" />
+    </test>
+</configuration>
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 454ab00..8fb09eb 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -42,6 +42,8 @@
 
     struct canfd_frame frame = {};
     frame.can_id = message.id;
+    if (message.isExtendedId) frame.can_id |= CAN_EFF_FLAG;
+    if (message.remoteTransmissionRequest) frame.can_id |= CAN_RTR_FLAG;
     frame.len = message.payload.size();
     memcpy(frame.data, message.payload.data(), message.payload.size());
 
@@ -226,8 +228,8 @@
 static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) {
     // TODO(b/144458917) add testing for this to VTS tests
     if (filterFlag == FilterFlag::DONT_CARE) return true;
-    if (filterFlag == FilterFlag::REQUIRE) return flag;
-    if (filterFlag == FilterFlag::EXCLUDE) return !flag;
+    if (filterFlag == FilterFlag::SET) return flag;
+    if (filterFlag == FilterFlag::NOT_SET) return !flag;
     return false;
 }
 
@@ -241,25 +243,26 @@
  * \param id Message id to filter
  * \return true if the message id matches the filter, false otherwise
  */
-static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isExtendedId,
-                  bool isRtr) {
+static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isRtr,
+                  bool isExtendedId) {
     if (filter.size() == 0) return true;
 
-    bool anyNonInvertedPresent = false;
-    bool anyNonInvertedSatisfied = false;
+    bool anyNonExcludeRulePresent = false;
+    bool anyNonExcludeRuleSatisfied = false;
     for (auto& rule : filter) {
-        const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted &&
+        const bool satisfied = ((id & rule.mask) == rule.id) &&
                                satisfiesFilterFlag(rule.rtr, isRtr) &&
                                satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
-        if (rule.inverted) {
-            // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set.
-            if (!satisfied) return false;
+
+        if (rule.exclude) {
+            // Any excluded (blacklist) rule not being satisfied invalidates the whole filter set.
+            if (satisfied) return false;
         } else {
-            anyNonInvertedPresent = true;
-            if (satisfied) anyNonInvertedSatisfied = true;
+            anyNonExcludeRulePresent = true;
+            if (satisfied) anyNonExcludeRuleSatisfied = true;
         }
     }
-    return !anyNonInvertedPresent || anyNonInvertedSatisfied;
+    return !anyNonExcludeRulePresent || anyNonExcludeRuleSatisfied;
 }
 
 void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) {
diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp
index 88f9175..047b090 100644
--- a/automotive/can/1.0/default/CanBusNative.cpp
+++ b/automotive/can/1.0/default/CanBusNative.cpp
@@ -31,6 +31,11 @@
         return ICanController::Result::BAD_ADDRESS;
     }
 
+    if (mBaudrate == 0) {
+        // interface is already up and we just want to register it
+        return ICanController::Result::OK;
+    }
+
     if (!netdevice::down(mIfname)) {
         LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)";
         return ICanController::Result::UNKNOWN_ERROR;
diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp
index 29d9d3c..e42005b 100644
--- a/automotive/can/1.0/default/CanBusSlcan.cpp
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -47,13 +47,34 @@
 CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate)
     : CanBus(), mUartName(uartName), kBitrate(bitrate) {}
 
+/** helper function to update CanBusSlcan object's iface name */
+ICanController::Result CanBusSlcan::updateIfaceName(base::unique_fd& uartFd) {
+    struct ifreq ifrequest = {};
+    /*
+     * Fetching the iface name with an ioctl won't interfere with an open socketCAN iface attached
+     * to this tty. This is important in the event we are trying to register a SLCAN based iface
+     * that has already been configured and brought up.
+     */
+    if (ioctl(uartFd.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;
+}
+
 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;
+    std::optional<std::string> canBitrateCommand = std::nullopt;
+    if (kBitrate != 0) {
+        const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate);
+        if (lookupIt == slcanprotocol::kBitrateCommands.end()) {
+            return ICanController::Result::BAD_BAUDRATE;
+        }
+        canBitrateCommand = lookupIt->second;
     }
-    const auto canBitrateCommand = lookupIt->second;
 
     /* Attempt to open the uart in r/w without blocking or becoming the
      * controlling terminal */
@@ -63,6 +84,11 @@
         return ICanController::Result::BAD_ADDRESS;
     }
 
+    // If the device is already up, update the iface name in our CanBusSlcan object
+    if (kBitrate == 0) {
+        return updateIfaceName(mFd);
+    }
+
     // blank terminal settings and pull them from the device
     struct termios terminalSettings = {};
     if (tcgetattr(mFd.get(), &terminalSettings) < 0) {
@@ -102,7 +128,7 @@
     }
 
     // apply speed setting for CAN
-    if (write(mFd.get(), canBitrateCommand.c_str(), canBitrateCommand.length()) <= 0) {
+    if (write(mFd.get(), canBitrateCommand->c_str(), canBitrateCommand->length()) <= 0) {
         LOG(ERROR) << "Failed to apply CAN bitrate: " << strerror(errno);
         return ICanController::Result::UNKNOWN_ERROR;
     }
@@ -120,17 +146,8 @@
         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;
+    return updateIfaceName(mFd);
 }
 
 bool CanBusSlcan::postDown() {
diff --git a/automotive/can/1.0/default/CanBusSlcan.h b/automotive/can/1.0/default/CanBusSlcan.h
index 3328a9f..2328a2c 100644
--- a/automotive/can/1.0/default/CanBusSlcan.h
+++ b/automotive/can/1.0/default/CanBusSlcan.h
@@ -32,6 +32,8 @@
     virtual bool postDown() override;
 
   private:
+    ICanController::Result updateIfaceName(base::unique_fd& uartFd);
+
     const std::string mUartName;
     const uint32_t kBitrate;
     base::unique_fd mFd;
diff --git a/automotive/can/1.0/types.hal b/automotive/can/1.0/types.hal
index f09c940..5eeed53 100644
--- a/automotive/can/1.0/types.hal
+++ b/automotive/can/1.0/types.hal
@@ -73,23 +73,22 @@
  * Single filter rule for CAN messages.
  *
  * A filter is satisfied if:
- * ((receivedId & mask) == (id & mask)) == !inverted
+ * ((receivedId & mask) == (id & mask)) == !exclude
  *
- * In order for set of filters to match, at least one non-inverted filters must match (if there is
- * one) and all inverted filters must match. In other words:
- *  - a single matching non-inverted filter makes the whole set matching;
- *  - a single non-matching inverted filter makes the whole set non-matching.
- *
- * Additional less common options for filtering include:
- * rtr - Remote Transmission Request; another ECU requests DLC bytes of data on this message ID
- * extendedFormat - 29 bit message ID is used instead of 11 bits
+ * In order for set of filters to match, at least one non-exclude filters must match (if there is
+ * one) and all exclude filters must match. In other words:
+ *  - a single matching non-exclude filter makes the whole set matching;
+ *  - a single non-matching excluded filter makes the whole set non-matching.
  */
 struct CanMessageFilter {
     CanMessageId id;
     uint32_t mask;
-    bool inverted;
+    /** Remote Transmission Request; another ECU requests <DLC> bytes of data on this message ID */
     FilterFlag rtr;
+    /** 29 bit message ID is used instead of 11 bits */
     FilterFlag extendedFormat;
+    /** 'exclude' *DOES* apply to rtr and extendedFormat! */
+    bool exclude;
 };
 
 
@@ -100,9 +99,9 @@
     /** Default, FilterFlag doesn't effect what messages filtered */
     DONT_CARE = 0,
     /** This FilterFlag MUST be present in received messages to pass though the filter */
-    REQUIRE,
+    SET,
     /** This FilterFlag must NOT be present in received messages to pass though the filter */
-    EXCLUDE,
+    NOT_SET,
 };
 
 enum Result : uint8_t {
diff --git a/automotive/can/1.0/vts/functional/Android.bp b/automotive/can/1.0/vts/functional/Android.bp
index b4d9132..e3e770b 100644
--- a/automotive/can/1.0/vts/functional/Android.bp
+++ b/automotive/can/1.0/vts/functional/Android.bp
@@ -16,13 +16,16 @@
 
 cc_defaults {
     name: "android.hardware.automotive.can@vts-defaults",
-    defaults: ["VtsHalTargetTestDefaults", "android.hardware.automotive.can@defaults"],
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "android.hardware.automotive.can@defaults",
+    ],
     header_libs: [
         "android.hardware.automotive.can@hidl-utils-lib",
-        "android.hardware.automotive.can@vts-utils-lib",
     ],
     static_libs: [
         "android.hardware.automotive.can@1.0",
+        "android.hardware.automotive.can@vts-utils-lib",
         "libgmock",
     ],
     test_suites: ["general-tests"],
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
index 8deaed6..cdea8b6 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -78,7 +78,7 @@
 TEST_F(CanBusHalTest, SendNoPayload) {
     CanMessage msg = {};
     msg.id = 0x123;
-
+    ASSERT_NE(mCanBus, nullptr);
     const auto result = mCanBus->send(msg);
     ASSERT_EQ(Result::OK, result);
 }
@@ -118,9 +118,9 @@
 
 TEST_F(CanBusHalTest, ListenSomeFilter) {
     hidl_vec<CanMessageFilter> filters = {
-            {0x123, 0x1FF, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
-            {0x001, 0x00F, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
-            {0x200, 0x100, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+            {0x123, 0x1FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+            {0x001, 0x00F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x200, 0x100, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
     };
 
     const auto [result, closeHandle] = listen(filters, new CanMessageListener());
@@ -171,14 +171,20 @@
 }  // namespace android::hardware::automotive::can::V1_0::vts
 
 /**
+ * This test requires that you bring up a valid bus first.
+ *
+ * Before running:
+ * mma -j && adb root && adb remount && adb sync
+ *
  * Example manual invocation:
  * adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest \
- *     --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/test
+ *     --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/<NAME_OF_VALID_BUS>
  */
 int main(int argc, char** argv) {
     using android::hardware::automotive::can::V1_0::ICanBus;
     using android::hardware::automotive::can::V1_0::vts::gEnv;
     using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+    setenv("TREBLE_TESTING_OVERRIDE", "true", true);
     android::base::SetDefaultTag("CanBusVts");
     android::base::SetMinimumLogSeverity(android::base::VERBOSE);
     gEnv = new SimpleHidlEnvironment<ICanBus>;
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
index 1663663..efaad53 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -21,6 +21,7 @@
 #include <android/hardware/automotive/can/1.0/ICanController.h>
 #include <android/hardware/automotive/can/1.0/types.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
 #include <can-vts-utils/can-hal-printers.h>
 #include <can-vts-utils/environment-utils.h>
 #include <gmock/gmock.h>
@@ -120,6 +121,7 @@
     }
 
     void send(const CanMessage& msg) {
+        EXPECT_NE(mBus, nullptr);
         const auto result = mBus->send(msg);
         EXPECT_EQ(Result::OK, result);
     }
@@ -139,18 +141,26 @@
 
     Bus makeBus();
 
+  protected:
+    static hidl_vec<hidl_string> mBusNames;
+
   private:
     unsigned mLastIface = 0;
     static sp<ICanController> mCanController;
     static bool mVirtualSupported;
+    static bool mTestCaseInitialized;
 };
 
 sp<ICanController> CanBusVirtualHalTest::mCanController = nullptr;
 bool CanBusVirtualHalTest::mVirtualSupported;
+hidl_vec<hidl_string> CanBusVirtualHalTest::mBusNames;
+bool CanBusVirtualHalTest::mTestCaseInitialized = false;
 
-static CanMessage makeMessage(CanMessageId id) {
+static CanMessage makeMessage(CanMessageId id, bool rtr, bool extended) {
     CanMessage msg = {};
     msg.id = id;
+    msg.remoteTransmissionRequest = rtr;
+    msg.isExtendedId = extended;
     return msg;
 }
 
@@ -160,6 +170,7 @@
 
 void CanBusVirtualHalTest::SetUp() {
     if (!mVirtualSupported) GTEST_SKIP();
+    ASSERT_TRUE(mTestCaseInitialized);
 }
 
 void CanBusVirtualHalTest::SetUpTestCase() {
@@ -170,6 +181,11 @@
     hidl_vec<InterfaceType> supported;
     mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).assertOk();
     mVirtualSupported = supported.contains(InterfaceType::VIRTUAL);
+
+    mBusNames = utils::getBusNames();
+    ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest";
+
+    mTestCaseInitialized = true;
 }
 
 void CanBusVirtualHalTest::TearDownTestCase() {
@@ -177,10 +193,11 @@
 }
 
 Bus CanBusVirtualHalTest::makeBus() {
-    const auto idx = ++mLastIface;
+    const auto idx = mLastIface++;
+    EXPECT_LT(idx, mBusNames.size());
 
     ICanController::BusConfiguration config = {};
-    config.name = "test" + std::to_string(idx);
+    config.name = mBusNames[idx];
     config.iftype = InterfaceType::VIRTUAL;
     config.interfaceId.address("vcan50");
 
@@ -207,6 +224,7 @@
 }
 
 TEST_F(CanBusVirtualHalTest, SendAndRecv) {
+    if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
     auto bus1 = makeBus();
     auto bus2 = makeBus();
 
@@ -226,6 +244,8 @@
 }
 
 TEST_F(CanBusVirtualHalTest, DownOneOfTwo) {
+    if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+
     auto bus1 = makeBus();
     auto bus2 = makeBus();
 
@@ -234,55 +254,621 @@
     bus1.send({});
 }
 
-TEST_F(CanBusVirtualHalTest, Filter) {
+TEST_F(CanBusVirtualHalTest, FilterPositive) {
+    if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
     auto bus1 = makeBus();
     auto bus2 = makeBus();
 
+    /* clang-format off */
+    /*        id,            mask,           rtr,                   eff,          exclude */
     hidl_vec<CanMessageFilter> filterPositive = {
-            {0x101, 0x100, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
-            {0x010, 0x0F0, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+            {0x334,           0x73F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+            {0x49D,           0x700, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+            {0x325,           0x7FC, FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   false},
+            {0x246,           0x7FF, FilterFlag::SET,       FilterFlag::DONT_CARE, false},
+            {0x1A2,           0x7FB, FilterFlag::SET,       FilterFlag::NOT_SET,   false},
+            {0x607,           0x7C9, FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, false},
+            {0x7F4,           0x777, FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   false},
+            {0x1BF19EAF, 0x10F0F0F0, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+            {0x12E99200, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       false},
+            {0x06B70270, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::DONT_CARE, false},
+            {0x096CFD2B, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       false},
+            {0x1BDCB008, 0x0F0F0F0F, FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, false},
+            {0x08318B46, 0x10F0F0F0, FilterFlag::NOT_SET,   FilterFlag::SET,       false},
+            {0x06B,           0x70F, FilterFlag::DONT_CARE, FilterFlag::SET,       false},
+            {0x750,           0x70F, FilterFlag::SET,       FilterFlag::SET,       false},
+            {0x5CF,           0x70F, FilterFlag::NOT_SET,   FilterFlag::SET,       false},
     };
+    /* clang-format on */
     auto listenerPositive = bus2.listen(filterPositive);
 
-    hidl_vec<CanMessageFilter> filterNegative = {
-            {0x123, 0x0FF, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
-            {0x004, 0x00F, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
-    };
-    auto listenerNegative = bus2.listen(filterNegative);
+    // 334:73F, DNC, DNC
+    bus1.send(makeMessage(0x3F4, false, false));
+    bus1.send(makeMessage(0x334, false, true));
+    bus1.send(makeMessage(0x374, true, false));
+    bus1.send(makeMessage(0x3F4, true, true));
 
-    bus1.send(makeMessage(0));
-    bus1.send(makeMessage(0x1A0));
-    bus1.send(makeMessage(0x1A1));
-    bus1.send(makeMessage(0x2A0));
-    bus1.send(makeMessage(0x3A0));
-    bus1.send(makeMessage(0x010));
-    bus1.send(makeMessage(0x123));
-    bus1.send(makeMessage(0x023));
-    bus1.send(makeMessage(0x124));
+    // 49D:700, DNC, DNC
+    bus1.send(makeMessage(0x404, false, false));
+    bus1.send(makeMessage(0x4A5, false, true));
+    bus1.send(makeMessage(0x4FF, true, false));
+    bus1.send(makeMessage(0x46B, true, true));
+
+    // 325:7FC, DNC, NS
+    bus1.send(makeMessage(0x324, false, false));
+    bus1.send(makeMessage(0x325, false, true));  // filtered out
+    bus1.send(makeMessage(0x326, true, false));
+    bus1.send(makeMessage(0x327, true, true));  // filtered out
+
+    // 246:7FF, SET, DNC
+    bus1.send(makeMessage(0x246, false, false));  // filtered out
+    bus1.send(makeMessage(0x246, false, true));   // filtered out
+    bus1.send(makeMessage(0x246, true, false));
+    bus1.send(makeMessage(0x246, true, true));
+
+    // 1A2:7FB, SET, NS
+    bus1.send(makeMessage(0x1A2, false, false));  // filtered out
+    bus1.send(makeMessage(0x1A6, false, true));   // filtered out
+    bus1.send(makeMessage(0x1A2, true, false));
+    bus1.send(makeMessage(0x1A6, true, true));  // filtered out
+
+    // 607:7C9, NS, DNC
+    bus1.send(makeMessage(0x607, false, false));
+    bus1.send(makeMessage(0x613, false, true));
+    bus1.send(makeMessage(0x625, true, false));  // filtered out
+    bus1.send(makeMessage(0x631, true, true));   // filtered out
+
+    // 7F4:777, NS, NS
+    bus1.send(makeMessage(0x774, false, false));
+    bus1.send(makeMessage(0x7F4, false, true));  // filtered out
+    bus1.send(makeMessage(0x77C, true, false));  // filtered out
+    bus1.send(makeMessage(0x7FC, true, false));  // filtered out
+
+    // 1BF19EAF:10F0F0F0, DNC, DNC
+    bus1.send(makeMessage(0x11F293A4, false, false));
+    bus1.send(makeMessage(0x15F697A8, false, true));
+    bus1.send(makeMessage(0x19FA9BAC, true, false));
+    bus1.send(makeMessage(0x1DFE9FA0, true, true));
+
+    // 12E99200:1FFFFFFF, DNC, SET
+    bus1.send(makeMessage(0x12E99200, false, false));  // filtered out
+    bus1.send(makeMessage(0x12E99200, false, true));
+    bus1.send(makeMessage(0x12E99200, true, false));  // filtered out
+    bus1.send(makeMessage(0x12E99200, true, true));
+
+    // 06B70270:1FFFFFFF, SET, DNC
+    bus1.send(makeMessage(0x06B70270, false, false));  // filtered out
+    bus1.send(makeMessage(0x06B70270, false, true));   // filtered out
+    bus1.send(makeMessage(0x06B70270, true, false));
+    bus1.send(makeMessage(0x06B70270, true, true));
+
+    // 096CFD2B:1FFFFFFF, SET, SET
+    bus1.send(makeMessage(0x096CFD2B, false, false));  // filtered out
+    bus1.send(makeMessage(0x096CFD2B, false, true));   // filtered out
+    bus1.send(makeMessage(0x096CFD2B, true, false));   // filtered out
+    bus1.send(makeMessage(0x096CFD2B, true, true));
+
+    // 1BDCB008:0F0F0F0F, NS, DNC
+    bus1.send(makeMessage(0x1B2C3048, false, false));
+    bus1.send(makeMessage(0x0B5C6078, false, true));
+    bus1.send(makeMessage(0x1B8C90A8, true, false));  // filtered out
+    bus1.send(makeMessage(0x0BBCC0D8, true, true));   // filtered out
+
+    // 08318B46:10F0F0F0, NS, SET
+    bus1.send(makeMessage(0x0F3E8D4C, false, false));  // filtered out
+    bus1.send(makeMessage(0x0B3A8948, false, true));
+    bus1.send(makeMessage(0x07368544, true, false));  // filtered out
+    bus1.send(makeMessage(0x03328140, true, true));   // filtered out
+
+    // 06B:70F, DNC, SET
+    bus1.send(makeMessage(0x00B, false, false));  // filtered out
+    bus1.send(makeMessage(0x04B, false, true));
+    bus1.send(makeMessage(0x08B, true, false));  // filtered out
+    bus1.send(makeMessage(0x0FB, true, true));
+
+    // 750:70F, SET, SET
+    bus1.send(makeMessage(0x7F0, false, false));  // filtered out
+    bus1.send(makeMessage(0x780, false, true));   // filtered out
+    bus1.send(makeMessage(0x740, true, false));   // filtered out
+    bus1.send(makeMessage(0x700, true, true));
+
+    // 5CF:70F, NS, SET
+    bus1.send(makeMessage(0x51F, false, false));  // filtered out
+    bus1.send(makeMessage(0x53F, false, true));
+    bus1.send(makeMessage(0x57F, true, false));  // filtered out
+    bus1.send(makeMessage(0x5FF, true, true));   // filtered out
 
     std::vector<can::V1_0::CanMessage> expectedPositive{
-            makeMessage(0x1A0),  //
-            makeMessage(0x1A1),  //
-            makeMessage(0x3A0),  //
-            makeMessage(0x010),  //
-            makeMessage(0x123),  //
-            makeMessage(0x124),  //
+            makeMessage(0x3F4, false, false),       // 334:73F, DNC, DNC
+            makeMessage(0x334, false, true),        // 334:73F, DNC, DNC
+            makeMessage(0x374, true, false),        // 334:73F, DNC, DNC
+            makeMessage(0x3F4, true, true),         // 334:73F, DNC, DNC
+            makeMessage(0x404, false, false),       // 49D:700, DNC, DNC
+            makeMessage(0x4A5, false, true),        // 49D:700, DNC, DNC
+            makeMessage(0x4FF, true, false),        // 49D:700, DNC, DNC
+            makeMessage(0x46B, true, true),         // 49D:700, DNC, DNC
+            makeMessage(0x324, false, false),       // 325:7FC, DNC, NS
+            makeMessage(0x326, true, false),        // 325:7FC, DNC, NS
+            makeMessage(0x246, true, false),        // 246:7FF, SET, DNC
+            makeMessage(0x246, true, true),         // 246:7FF, SET, DNC
+            makeMessage(0x1A2, true, false),        // 1A2:7FB, SET, NS
+            makeMessage(0x607, false, false),       // 607:7C9, NS, DNC
+            makeMessage(0x613, false, true),        // 607:7C9, NS, DNC
+            makeMessage(0x774, false, false),       // 7F4:777, NS, NS
+            makeMessage(0x11F293A4, false, false),  // 1BF19EAF:10F0F0F0, DNC, DNC
+            makeMessage(0x15F697A8, false, true),   // 1BF19EAF:10F0F0F0, DNC, DNC
+            makeMessage(0x19FA9BAC, true, false),   // 1BF19EAF:10F0F0F0, DNC, DNC
+            makeMessage(0x1DFE9FA0, true, true),    // 1BF19EAF:10F0F0F0, DNC, DNC
+            makeMessage(0x12E99200, false, true),   // 12E99200:1FFFFFFF, DNC, SET
+            makeMessage(0x12E99200, true, true),    // 12E99200:1FFFFFFF, DNC, SET
+            makeMessage(0x06B70270, true, false),   // 06B70270:1FFFFFFF, SET, DNC
+            makeMessage(0x06B70270, true, true),    // 06B70270:1FFFFFFF, SET, DNC
+            makeMessage(0x096CFD2B, true, true),    // 096CFD2B:1FFFFFFF, SET, SET
+            makeMessage(0x1B2C3048, false, false),  // 1BDCB008:0F0F0F0F, NS, DNC
+            makeMessage(0x0B5C6078, false, true),   // 1BDCB008:0F0F0F0F, NS, DNC
+            makeMessage(0x0B3A8948, false, true),   // 08318B46:10F0F0F0, NS, SET
+            makeMessage(0x04B, false, true),        // 06B:70F, DNC, SET
+            makeMessage(0x0FB, true, true),         // 06B:70F, DNC, SET
+            makeMessage(0x700, true, true),         // 750:70F, SET, SET
+            makeMessage(0x53F, false, true),        // 5CF:70F, NS, SET
     };
+
+    auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size());
+    clearTimestamps(messagesPositive);
+    ASSERT_EQ(expectedPositive, messagesPositive);
+}
+
+TEST_F(CanBusVirtualHalTest, FilterNegative) {
+    if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    /* clang-format off */
+    /*        id,             mask,           rtr,                   eff          exclude */
+    hidl_vec<CanMessageFilter> filterNegative = {
+            {0x063,           0x7F3, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x0A1,           0x78F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x18B,           0x7E3, FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x1EE,           0x7EC, FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x23F,           0x7A5, FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x31F,           0x77F, FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x341,           0x77F, FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x196573DB, 0x1FFFFF7F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x1CFCB417, 0x1FFFFFEC, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x17CCC433, 0x1FFFFFEC, FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x0BC2F508, 0x1FFFFFC3, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x1179B5D2, 0x1FFFFFC3, FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x082AF63D, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x66D,           0x76F, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x748,           0x7CC, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x784,           0x7CC, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+    };
+    /* clang-format on */
+
+    auto listenerNegative = bus2.listen(filterNegative);
+
+    // 063:7F3, DNC, DNC: ~06[3,7,B,F]
+    bus1.send(makeMessage(0x063, false, false));  // filtered out
+    bus1.send(makeMessage(0x060, false, true));
+    bus1.send(makeMessage(0x05B, true, false));
+    bus1.send(makeMessage(0x06F, true, true));  // filtered out
+
+    // 0A1:78F, DNC, DNC: ~0[8-F]1
+    bus1.send(makeMessage(0x081, false, false));  // filtered out
+    bus1.send(makeMessage(0x031, false, true));
+    bus1.send(makeMessage(0x061, true, false));
+    bus1.send(makeMessage(0x071, true, true));
+
+    // 18B:7E3, DNC, NS: ~1[8-9][7,B,F]
+    bus1.send(makeMessage(0x18B, false, false));  // filtered out
+    bus1.send(makeMessage(0x188, false, true));
+    bus1.send(makeMessage(0x123, true, false));
+    bus1.send(makeMessage(0x1D5, true, true));
+
+    // 1EE:7EC, SET, DNC: ~1[E-F][C-F]
+    bus1.send(makeMessage(0x17E, false, false));
+    bus1.send(makeMessage(0x138, false, true));
+    bus1.send(makeMessage(0x123, true, false));
+    bus1.send(makeMessage(0x1EC, true, true));  // filtered out
+
+    // 23F:7A5, SET, NS: ~2[2,3,6,7][5,7,D,F]
+    bus1.send(makeMessage(0x222, false, false));
+    bus1.send(makeMessage(0x275, false, true));
+    bus1.send(makeMessage(0x23f, true, false));  // filtered out
+    bus1.send(makeMessage(0x241, true, false));
+    bus1.send(makeMessage(0x2FF, true, true));
+
+    // 31F:77F, NS, DNC: ~3[1,9]F
+    bus1.send(makeMessage(0x32F, false, false));
+    bus1.send(makeMessage(0x31F, false, true));  // filtered out
+    bus1.send(makeMessage(0x36F, false, true));
+    bus1.send(makeMessage(0x31F, true, false));
+    bus1.send(makeMessage(0x3F3, true, true));
+
+    // 341:77F, NS, NS: ~3[4,C]1
+    bus1.send(makeMessage(0x341, false, false));  // filtered out
+    bus1.send(makeMessage(0x352, false, false));
+    bus1.send(makeMessage(0x3AA, false, true));
+    bus1.send(makeMessage(0x3BC, true, false));
+    bus1.send(makeMessage(0x3FF, true, true));
+
+    // 196573DB:1FFFFF7F, DNC, DNC: ~196573[5,D]B
+    bus1.send(makeMessage(0x1965733B, false, false));
+    bus1.send(makeMessage(0x1965734B, false, true));
+    bus1.send(makeMessage(0x1965735B, true, false));  // filtered out
+    bus1.send(makeMessage(0x1965736B, true, true));
+
+    // 1CFCB417:1FFFFFEC, DNC, SET: ~1CFCB4[0-1][4-7]
+    bus1.send(makeMessage(0x1CFCB407, false, false));
+    bus1.send(makeMessage(0x1CFCB4FF, false, true));
+    bus1.send(makeMessage(0x1CFCB414, true, false));
+    bus1.send(makeMessage(0x1CFCB407, true, true));  // filtered out
+
+    // 17CCC433:1FFFFFEC, SET, DNC: ~17CCC4[2-3][0-3]
+    bus1.send(makeMessage(0x17CCC430, false, false));
+    bus1.send(makeMessage(0x17CCC423, false, true));
+    bus1.send(makeMessage(0x17CCC420, true, false));  // filtered out
+    bus1.send(makeMessage(0x17CCC444, true, true));
+
+    // 0BC2F508:1FFFFFC3, SET, SET: ~5[0-3][0,4,8,C]
+    bus1.send(makeMessage(0x0BC2F504, false, false));
+    bus1.send(makeMessage(0x0BC2F518, false, true));
+    bus1.send(makeMessage(0x0BC2F52C, true, false));
+    bus1.send(makeMessage(0x0BC2F500, true, true));  // filtered out
+    bus1.send(makeMessage(0x0BC2F543, true, true));
+
+    // 1179B5D2:1FFFFFC3, NS, DNC: ~5[C-F][2,6,A,E]
+    bus1.send(makeMessage(0x1179B5BB, false, false));
+    bus1.send(makeMessage(0x1179B5EA, false, true));  // filtered out
+    bus1.send(makeMessage(0x1179B5C2, true, false));
+    bus1.send(makeMessage(0x1179B5DA, true, true));
+
+    // 082AF63D:1FFFFF6F, NS, SET: ~6[2,3,A,B]D
+    bus1.send(makeMessage(0x082AF62D, false, false));
+    bus1.send(makeMessage(0x082AF63D, false, true));  // filtered out
+    bus1.send(makeMessage(0x082AF60D, false, true));
+    bus1.send(makeMessage(0x082AF6AD, true, false));
+    bus1.send(makeMessage(0x082AF6BD, true, true));
+
+    // 66D:76F, DNC, SET: ~6[6,7,E,F]D
+    bus1.send(makeMessage(0x66D, false, false));
+    bus1.send(makeMessage(0x68D, false, true));
+    bus1.send(makeMessage(0x67D, true, false));
+    bus1.send(makeMessage(0x6ED, true, true));  // filtered out
+
+    // 748:7CC, SET, SET: ~0x7[4-7][8-F]
+    bus1.send(makeMessage(0x749, false, false));
+    bus1.send(makeMessage(0x75A, false, true));
+    bus1.send(makeMessage(0x76B, true, false));
+    bus1.send(makeMessage(0x748, true, true));  // filtered out
+    bus1.send(makeMessage(0x788, true, true));
+
+    // 784:7CC, NS, SET: ~0x7[8-F][4-7]
+    bus1.send(makeMessage(0x795, false, false));
+    bus1.send(makeMessage(0x784, false, true));  // filtered out
+    bus1.send(makeMessage(0x71B, false, true));
+    bus1.send(makeMessage(0x769, true, false));
+    bus1.send(makeMessage(0x784, true, true));
+
     std::vector<can::V1_0::CanMessage> expectedNegative{
-            makeMessage(0),      //
-            makeMessage(0x1A0),  //
-            makeMessage(0x1A1),  //
-            makeMessage(0x2A0),  //
-            makeMessage(0x3A0),  //
-            makeMessage(0x010),  //
+            makeMessage(0x060, false, true),        // 063:7F3, DNC, DNC
+            makeMessage(0x05B, true, false),        // 063:7F3, DNC, DNC
+            makeMessage(0x031, false, true),        // 0A1:78F, DNC, DNC
+            makeMessage(0x061, true, false),        // 0A1:78F, DNC, DNC
+            makeMessage(0x071, true, true),         // 0A1:78F, DNC, DNC
+            makeMessage(0x188, false, true),        // 18B:7E3, DNC, NS
+            makeMessage(0x123, true, false),        // 18B:7E3, DNC, NS
+            makeMessage(0x1D5, true, true),         // 18B:7E3, DNC, NS
+            makeMessage(0x17E, false, false),       // 1EE:7EC, SET, DNC
+            makeMessage(0x138, false, true),        // 1EE:7EC, SET, DNC
+            makeMessage(0x123, true, false),        // 1EE:7EC, SET, DNC
+            makeMessage(0x222, false, false),       // 23F:7A5, SET, NS
+            makeMessage(0x275, false, true),        // 23F:7A5, SET, NS
+            makeMessage(0x241, true, false),        // 23F:7A5, SET, NS
+            makeMessage(0x2FF, true, true),         // 23F:7A5, SET, NS
+            makeMessage(0x32F, false, false),       // 31F:77F, NS, DNC
+            makeMessage(0x36F, false, true),        // 31F:77F, NS, DNC
+            makeMessage(0x31F, true, false),        // 31F:77F, NS, DNC
+            makeMessage(0x3F3, true, true),         // 31F:77F, NS, DNC
+            makeMessage(0x352, false, false),       // 341:77F, NS, NS
+            makeMessage(0x3AA, false, true),        // 341:77F, NS, NS
+            makeMessage(0x3BC, true, false),        // 341:77F, NS, NS
+            makeMessage(0x3FF, true, true),         // 341:77F, NS, NS
+            makeMessage(0x1965733B, false, false),  // 196573DB:1FFFFF7F, DNC, DNC
+            makeMessage(0x1965734B, false, true),   // 196573DB:1FFFFF7F, DNC, DNC
+            makeMessage(0x1965736B, true, true),    // 196573DB:1FFFFF7F, DNC, DNC
+            makeMessage(0x1CFCB407, false, false),  // 1CFCB417:1FFFFFEC, DNC, SET
+            makeMessage(0x1CFCB4FF, false, true),   // 1CFCB417:1FFFFFEC, DNC, SET
+            makeMessage(0x1CFCB414, true, false),   // 1CFCB417:1FFFFFEC, DNC, SET
+            makeMessage(0x17CCC430, false, false),  // 17CCC433:1FFFFFEC, SET, DNC
+            makeMessage(0x17CCC423, false, true),   // 17CCC433:1FFFFFEC, SET, DNC
+            makeMessage(0x17CCC444, true, true),    // 17CCC433:1FFFFFEC, SET, DNC
+            makeMessage(0x0BC2F504, false, false),  // 0BC2F508:1FFFFFC3, SET, SET
+            makeMessage(0x0BC2F518, false, true),   // 0BC2F508:1FFFFFC3, SET, SET
+            makeMessage(0x0BC2F52C, true, false),   // 0BC2F508:1FFFFFC3, SET, SET
+            makeMessage(0x0BC2F543, true, true),    // 0BC2F508:1FFFFFC3, SET, SET
+            makeMessage(0x1179B5BB, false, false),  // 1179B5D2:1FFFFFC3, NS, DNC
+            makeMessage(0x1179B5C2, true, false),   // 1179B5D2:1FFFFFC3, NS, DNC
+            makeMessage(0x1179B5DA, true, true),    // 1179B5D2:1FFFFFC3, NS, DNC
+            makeMessage(0x082AF62D, false, false),  // 082AF63D:1FFFFF6F, NS, SET
+            makeMessage(0x082AF60D, false, true),   // 082AF63D:1FFFFF6F, NS, SET
+            makeMessage(0x082AF6AD, true, false),   // 082AF63D:1FFFFF6F, NS, SET
+            makeMessage(0x082AF6BD, true, true),    // 082AF63D:1FFFFF6F, NS, SET
+            makeMessage(0x66D, false, false),       // 66D:76F, DNC, SET
+            makeMessage(0x68D, false, true),        // 66D:76F, DNC, SET
+            makeMessage(0x67D, true, false),        // 66D:76F, DNC, SET
+            makeMessage(0x749, false, false),       // 748:7CC, SET, SET
+            makeMessage(0x75A, false, true),        // 748:7CC, SET, SET
+            makeMessage(0x76B, true, false),        // 748:7CC, SET, SET
+            makeMessage(0x788, true, true),         // 748:7CC, SET, SET
+            makeMessage(0x795, false, false),       // 784:7CC, NS, SET
+            makeMessage(0x71B, false, true),        // 784:7CC, NS, SET
+            makeMessage(0x769, true, false),        // 784:7CC, NS, SET
+            makeMessage(0x784, true, true),         // 784:7CC, NS, SET
     };
 
     auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size());
-    auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size());
     clearTimestamps(messagesNegative);
-    clearTimestamps(messagesPositive);
     ASSERT_EQ(expectedNegative, messagesNegative);
-    ASSERT_EQ(expectedPositive, messagesPositive);
+}
+
+TEST_F(CanBusVirtualHalTest, FilterMixed) {
+    if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    /* clang-format off */
+    /*        id,           mask,             rtr,                   eff          exclude */
+    hidl_vec<CanMessageFilter> filterMixed = {
+            {0x000,      0x700,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+            {0x0D5,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x046,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x11D89097, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x0AB,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x00D,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x0F82400E, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x08F,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x0BE,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x0A271011, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x0BE,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x100,      0x700,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   false},
+            {0x138,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x1BF,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x13AB6165, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x17A,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x13C,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x102C5197, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x19B,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x1B8,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x0D6D5185, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x1B8,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x096A2200, 0x1FFFFF00, FilterFlag::DONT_CARE, FilterFlag::SET,       false},
+            {0x201,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x22A,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x1D1C3238, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x2C0,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x23C,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x016182C6, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x27B,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x2A5,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x160EB24B, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x2A5,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x300,      0x700,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, false},
+            {0x339,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x3D4,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x182263BE, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x327,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x36B,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x1A1D8374, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x319,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x39E,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x1B657332, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x39E,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x06C5D400, 0x1FFFFF00, FilterFlag::NOT_SET,   FilterFlag::SET,       false},
+            {0x492,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x4EE,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x07725454, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x4D5,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x402,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x139714A7, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x464,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x454,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x0EF4B46F, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x454,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x500,      0x700,      FilterFlag::SET,       FilterFlag::DONT_CARE, false},
+            {0x503,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x566,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x137605E7, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x564,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x58E,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x05F9052D, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x595,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x563,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x13358537, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x563,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x600,      0x700,      FilterFlag::SET,       FilterFlag::NOT_SET,   false},
+            {0x64D,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x620,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x1069A676, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x62D,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x6C4,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x14C76629, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x689,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x6A4,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x0BCCA6C2, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x6A4,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x04BB1700, 0x1FFFFF00, FilterFlag::SET,       FilterFlag::SET,       false},
+            {0x784,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x7F9,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x0200F77D, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x783,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x770,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x06602719, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x76B,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x7DF,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x1939E736, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x7DF,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+    };
+    /* clang-format on */
+
+    auto listenerMixed = bus2.listen(filterMixed);
+
+    bus1.send(makeMessage(0x000, true, true));  // positive filter
+    bus1.send(makeMessage(0x0D5, false, false));
+    bus1.send(makeMessage(0x046, true, false));
+    bus1.send(makeMessage(0x046, false, false));
+    bus1.send(makeMessage(0x11D89097, true, true));
+    bus1.send(makeMessage(0x11D89097, false, true));
+    bus1.send(makeMessage(0x0AB, false, false));
+    bus1.send(makeMessage(0x0AB, false, true));
+    bus1.send(makeMessage(0x00D, false, false));
+    bus1.send(makeMessage(0x0F82400E, false, true));
+    bus1.send(makeMessage(0x08F, true, false));
+    bus1.send(makeMessage(0x08F, true, true));
+    bus1.send(makeMessage(0x0BE, true, false));
+    bus1.send(makeMessage(0x0A271011, true, true));
+    bus1.send(makeMessage(0x0BE, false, true));   // not filtered
+    bus1.send(makeMessage(0x100, false, false));  // positive filter
+    bus1.send(makeMessage(0x138, false, true));
+    bus1.send(makeMessage(0x138, true, false));
+    bus1.send(makeMessage(0x1BF, false, false));
+    bus1.send(makeMessage(0x1BF, true, false));
+    bus1.send(makeMessage(0x13AB6165, false, true));
+    bus1.send(makeMessage(0x13AB6165, true, true));
+    bus1.send(makeMessage(0x17A, false, false));
+    bus1.send(makeMessage(0x17A, false, true));
+    bus1.send(makeMessage(0x13C, false, false));
+    bus1.send(makeMessage(0x102C5197, false, true));
+    bus1.send(makeMessage(0x19B, true, false));
+    bus1.send(makeMessage(0x19B, true, true));
+    bus1.send(makeMessage(0x1B8, true, false));
+    bus1.send(makeMessage(0x0D6D5185, true, true));
+    bus1.send(makeMessage(0x1B8, false, true));       // not filtered
+    bus1.send(makeMessage(0x096A2200, false, true));  // positive filter
+    bus1.send(makeMessage(0x201, false, true));
+    bus1.send(makeMessage(0x201, true, false));
+    bus1.send(makeMessage(0x22A, false, false));
+    bus1.send(makeMessage(0x22A, true, false));
+    bus1.send(makeMessage(0x1D1C3238, false, true));
+    bus1.send(makeMessage(0x1D1C3238, true, true));
+    bus1.send(makeMessage(0x2C0, false, false));
+    bus1.send(makeMessage(0x2C0, false, true));
+    bus1.send(makeMessage(0x23C, false, false));
+    bus1.send(makeMessage(0x016182C6, false, true));
+    bus1.send(makeMessage(0x27B, true, false));
+    bus1.send(makeMessage(0x27B, true, true));
+    bus1.send(makeMessage(0x2A5, true, false));
+    bus1.send(makeMessage(0x160EB24B, true, true));
+    bus1.send(makeMessage(0x2A5, false, true));   // not filtereed
+    bus1.send(makeMessage(0x300, false, false));  // positive filter
+    bus1.send(makeMessage(0x339, false, true));
+    bus1.send(makeMessage(0x339, false, false));
+    bus1.send(makeMessage(0x3D4, true, false));
+    bus1.send(makeMessage(0x182263BE, false, true));
+    bus1.send(makeMessage(0x182263BE, true, true));
+    bus1.send(makeMessage(0x327, false, false));
+    bus1.send(makeMessage(0x327, false, true));
+    bus1.send(makeMessage(0x36B, false, false));
+    bus1.send(makeMessage(0x1A1D8374, false, true));
+    bus1.send(makeMessage(0x319, true, false));
+    bus1.send(makeMessage(0x319, true, true));
+    bus1.send(makeMessage(0x39E, true, false));
+    bus1.send(makeMessage(0x1B657332, true, true));
+    bus1.send(makeMessage(0x39E, false, true));       // not filtered
+    bus1.send(makeMessage(0x06C5D400, false, true));  // positive filter
+    bus1.send(makeMessage(0x492, false, true));
+    bus1.send(makeMessage(0x492, true, false));
+    bus1.send(makeMessage(0x4EE, false, false));
+    bus1.send(makeMessage(0x4EE, true, false));
+    bus1.send(makeMessage(0x07725454, false, true));
+    bus1.send(makeMessage(0x07725454, true, true));
+    bus1.send(makeMessage(0x4D5, false, false));
+    bus1.send(makeMessage(0x4D5, false, true));
+    bus1.send(makeMessage(0x402, false, false));
+    bus1.send(makeMessage(0x139714A7, false, true));
+    bus1.send(makeMessage(0x464, true, false));
+    bus1.send(makeMessage(0x464, true, true));
+    bus1.send(makeMessage(0x454, true, false));
+    bus1.send(makeMessage(0x0EF4B46F, true, true));
+    bus1.send(makeMessage(0x454, false, true));  // not filtered
+    bus1.send(makeMessage(0x500, true, false));  // positive filter
+    bus1.send(makeMessage(0x503, false, true));
+    bus1.send(makeMessage(0x503, true, false));
+    bus1.send(makeMessage(0x566, false, false));
+    bus1.send(makeMessage(0x566, true, false));
+    bus1.send(makeMessage(0x137605E7, false, true));
+    bus1.send(makeMessage(0x137605E7, true, true));
+    bus1.send(makeMessage(0x564, false, false));
+    bus1.send(makeMessage(0x564, false, true));
+    bus1.send(makeMessage(0x58E, false, false));
+    bus1.send(makeMessage(0x05F9052D, false, true));
+    bus1.send(makeMessage(0x595, true, false));
+    bus1.send(makeMessage(0x595, true, true));
+    bus1.send(makeMessage(0x563, true, false));
+    bus1.send(makeMessage(0x13358537, true, true));
+    bus1.send(makeMessage(0x563, false, true));  // not filtered
+    bus1.send(makeMessage(0x600, true, false));  // positive filter
+    bus1.send(makeMessage(0x64D, false, true));
+    bus1.send(makeMessage(0x64D, true, false));
+    bus1.send(makeMessage(0x620, false, false));
+    bus1.send(makeMessage(0x620, true, false));
+    bus1.send(makeMessage(0x1069A676, false, true));
+    bus1.send(makeMessage(0x1069A676, true, true));
+    bus1.send(makeMessage(0x62D, false, false));
+    bus1.send(makeMessage(0x62D, false, true));
+    bus1.send(makeMessage(0x6C4, false, false));
+    bus1.send(makeMessage(0x14C76629, false, true));
+    bus1.send(makeMessage(0x689, true, false));
+    bus1.send(makeMessage(0x689, true, true));
+    bus1.send(makeMessage(0x6A4, true, false));
+    bus1.send(makeMessage(0x0BCCA6C2, true, true));
+    bus1.send(makeMessage(0x6A4, false, true));      // not filtered
+    bus1.send(makeMessage(0x04BB1700, true, true));  // positive filter
+    bus1.send(makeMessage(0x784, false, true));
+    bus1.send(makeMessage(0x784, true, false));
+    bus1.send(makeMessage(0x7F9, false, false));
+    bus1.send(makeMessage(0x7F9, true, false));
+    bus1.send(makeMessage(0x0200F77D, false, true));
+    bus1.send(makeMessage(0x0200F77D, true, true));
+    bus1.send(makeMessage(0x783, false, false));
+    bus1.send(makeMessage(0x783, false, true));
+    bus1.send(makeMessage(0x770, false, false));
+    bus1.send(makeMessage(0x06602719, false, true));
+    bus1.send(makeMessage(0x76B, true, false));
+    bus1.send(makeMessage(0x76B, true, true));
+    bus1.send(makeMessage(0x7DF, true, false));
+    bus1.send(makeMessage(0x1939E736, true, true));
+    bus1.send(makeMessage(0x7DF, false, true));  // not filtered
+
+    std::vector<can::V1_0::CanMessage> expectedMixed{
+            makeMessage(0x000, true, true),  // 0x000:0x700, DONT_CARE, DONT_CARE
+            makeMessage(0x0BE, false, true),
+            makeMessage(0x100, false, false),  // 0x100:0x700, DONT_CARE, NOT_SET
+            makeMessage(0x1B8, false, true),
+            makeMessage(0x096A2200, false, true),  // 0x096A2200:0x1FFFFF00, DONT_CARE, SET
+            makeMessage(0x2A5, false, true),
+            makeMessage(0x300, false, false),  // 0x300:0x700, NOT_SET, DONT_CARE
+            makeMessage(0x39E, false, true),
+            makeMessage(0x06C5D400, false, true),  // 0x06C5D400:0x1FFFFF00, NOT_SET, SET
+            makeMessage(0x454, false, true),
+            makeMessage(0x500, true, false),  // 0x500:0x700, SET, DONT_CARE
+            makeMessage(0x563, false, true),
+            makeMessage(0x600, true, false),  // 0x600:0x700, SET, NOT_SET
+            makeMessage(0x6A4, false, true),
+            makeMessage(0x04BB1700, true, true),  // 0x04BB1700:0x1FFFFF00, SET, SET
+            makeMessage(0x7DF, false, true),
+    };
+
+    auto messagesMixed = listenerMixed->fetchMessages(100ms, expectedMixed.size());
+    clearTimestamps(messagesMixed);
+    ASSERT_EQ(expectedMixed, messagesMixed);
 }
 
 }  // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
index 22dec2c..9bc789a 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -21,6 +21,7 @@
 #include <android/hardware/automotive/can/1.0/ICanController.h>
 #include <android/hardware/automotive/can/1.0/types.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
 #include <can-vts-utils/can-hal-printers.h>
 #include <can-vts-utils/environment-utils.h>
 #include <gmock/gmock.h>
@@ -37,6 +38,7 @@
   protected:
     virtual void SetUp() override;
     virtual void TearDown() override;
+    static void SetUpTestCase();
 
     hidl_vec<InterfaceType> getSupportedInterfaceTypes();
     bool isSupported(InterfaceType iftype);
@@ -46,9 +48,18 @@
     void assertRegistered(const std::string srvname, bool expectRegistered);
 
     sp<ICanController> mCanController;
+    static hidl_vec<hidl_string> mBusNames;
+
+  private:
+    static bool mTestCaseInitialized;
 };
 
+hidl_vec<hidl_string> CanControllerHalTest::mBusNames;
+bool CanControllerHalTest::mTestCaseInitialized = false;
+
 void CanControllerHalTest::SetUp() {
+    ASSERT_TRUE(mTestCaseInitialized);
+
     const auto serviceName = gEnv->getServiceName<ICanController>();
     mCanController = getService<ICanController>(serviceName);
     ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName;
@@ -58,6 +69,13 @@
     mCanController.clear();
 }
 
+void CanControllerHalTest::SetUpTestCase() {
+    mBusNames = utils::getBusNames();
+    ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest";
+
+    mTestCaseInitialized = true;
+}
+
 hidl_vec<InterfaceType> CanControllerHalTest::getSupportedInterfaceTypes() {
     hidl_vec<InterfaceType> iftypesResult;
     mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult)).assertOk();
@@ -104,7 +122,7 @@
 }
 
 TEST_F(CanControllerHalTest, BringUpDown) {
-    const std::string name = "dummy";
+    const std::string name = mBusNames[0];
 
     assertRegistered(name, false);
     if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::OK)) GTEST_SKIP();
@@ -122,7 +140,7 @@
 }
 
 TEST_F(CanControllerHalTest, UpTwice) {
-    const std::string name = "dummy";
+    const std::string name = mBusNames[0];
 
     assertRegistered(name, false);
     if (!up(InterfaceType::VIRTUAL, name, "vcan72", ICanController::Result::OK)) GTEST_SKIP();
@@ -211,7 +229,7 @@
 }
 
 TEST_F(CanControllerHalTest, FailBadVirtualAddress) {
-    const std::string name = "dummy";
+    const std::string name = mBusNames[0];
 
     assertRegistered(name, false);
     if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP();
@@ -219,7 +237,7 @@
 }
 
 TEST_F(CanControllerHalTest, FailBadSocketcanAddress) {
-    const std::string name = "dummy";
+    const std::string name = mBusNames[0];
 
     assertRegistered(name, false);
     if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) {
diff --git a/automotive/can/1.0/vts/utils/Android.bp b/automotive/can/1.0/vts/utils/Android.bp
index e925c8f..d03ead3 100644
--- a/automotive/can/1.0/vts/utils/Android.bp
+++ b/automotive/can/1.0/vts/utils/Android.bp
@@ -14,7 +14,17 @@
 // limitations under the License.
 //
 
-cc_library_headers {
+cc_library_static {
     name: "android.hardware.automotive.can@vts-utils-lib",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "bus-enumerator.cpp",
+    ],
     export_include_dirs: ["include"],
+    header_libs: [
+        "android.hardware.automotive.can@hidl-utils-lib",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@1.0",
+    ],
 }
diff --git a/automotive/can/1.0/vts/utils/bus-enumerator.cpp b/automotive/can/1.0/vts/utils/bus-enumerator.cpp
new file mode 100644
index 0000000..c012dd2
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/bus-enumerator.cpp
@@ -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.
+ */
+
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android::hardware::automotive::can::V1_0::vts::utils {
+
+hidl_vec<hidl_string> getBusNames() {
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    hidl_vec<hidl_string> services;
+    manager->listManifestByInterface(ICanBus::descriptor, hidl_utils::fill(&services));
+    return services;
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::vts::utils
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h
new file mode 100644
index 0000000..ef385eb
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+
+namespace android::hardware::automotive::can::V1_0::vts::utils {
+
+hidl_vec<hidl_string> getBusNames();
+
+}  // namespace android::hardware::automotive::can::V1_0::vts::utils
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
index 975b6c6..fc68e60 100644
--- a/automotive/evs/1.1/IEvsCamera.hal
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -34,6 +34,23 @@
     getCameraInfo_1_1() generates (CameraDesc info);
 
     /**
+     * Returns the description of the physical camera device that backs this
+     * logical camera.
+     *
+     * If a requested device does not either exist or back this logical device,
+     * this method returns a null camera descriptor.  And, if this is called on
+     * a physical camera device, this method is the same as getCameraInfo_1_1()
+     * method if a given device ID is matched.  Otherwise, this will return a
+     * null camera descriptor.
+     *
+     * @param  deviceId Physical camera device identifier string.
+     * @return info     The description of a member physical camera device.
+     *                  This must be the same value as reported by
+     *                  EvsEnumerator::getCameraList_1_1().
+     */
+    getPhysicalCameraInfo(string deviceId) generates (CameraDesc info);
+
+    /**
      * Requests to pause EVS camera stream events.
      *
      * Like stopVideoStream(), events may continue to arrive for some time
@@ -51,7 +68,7 @@
     resumeVideoStream() generates (EvsResult result);
 
     /**
-     * Returns a frame that was delivered by to the IEvsCameraStream.
+     * Returns frame that were delivered by to the IEvsCameraStream.
      *
      * When done consuming a frame delivered to the IEvsCameraStream
      * interface, it must be returned to the IEvsCamera for reuse.
@@ -59,10 +76,10 @@
      * as one), and if the supply is exhausted, no further frames may be
      * delivered until a buffer is returned.
      *
-     * @param  buffer A buffer to be returned.
+     * @param  buffer Buffers to be returned.
      * @return result Return EvsResult::OK if this call is successful.
      */
-    doneWithFrame_1_1(BufferDesc buffer) generates (EvsResult result);
+    doneWithFrame_1_1(vec<BufferDesc> buffer) generates (EvsResult result);
 
     /**
      * Requests to be a master client.
@@ -127,8 +144,13 @@
         generates (int32_t min, int32_t max, int32_t step);
 
     /**
-     * Requests to set a camera parameter.  Only a request from the master
-     * client will be processed successfully.
+     * Requests to set a camera parameter.
+     *
+     * Only a request from the master client will be processed successfully.
+     * When this method is called on a logical camera device, it will be forwarded
+     * to each physical device and, if it fails to program any physical device,
+     * it will return an error code with the same number of effective values as
+     * the number of backing camera devices.
      *
      * @param  id             The identifier of camera parameter, CameraParam enum.
      *         value          A desired parameter value.
@@ -138,21 +160,22 @@
      *                        parameter is not supported.
      *                        EvsResult::UNDERLYING_SERVICE_ERROR if it fails to
      *                        program a value by any other reason.
-     *         effectiveValue A programmed parameter value.  This may differ
+     *         effectiveValue Programmed parameter values.  This may differ
      *                        from what the client gives if, for example, the
      *                        driver does not support a target parameter.
      */
     setIntParameter(CameraParam id, int32_t value)
-        generates (EvsResult result, int32_t effectiveValue);
+        generates (EvsResult result, vec<int32_t> effectiveValue);
 
     /**
-     * Retrieves a value of given camera parameter.
+     * Retrieves values of given camera parameter.
      *
      * @param  id     The identifier of camera parameter, CameraParam enum.
      * @return result EvsResult::OK if it succeeds to read a parameter.
      *                EvsResult::INVALID_ARG if either a requested parameter is
      *                not supported.
-     *         value  A value of requested camera parameter.
+     *         value  Values of requested camera parameter, the same number of
+     *                values as backing camera devices.
      */
-    getIntParameter(CameraParam id) generates(EvsResult result, int32_t value);
+    getIntParameter(CameraParam id) generates(EvsResult result, vec<int32_t> value);
 };
diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal
index 9e4ea19..aa35c62 100644
--- a/automotive/evs/1.1/IEvsCameraStream.hal
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -18,7 +18,7 @@
 
 import @1.0::IEvsCameraStream;
 import @1.1::BufferDesc;
-import @1.1::EvsEvent;
+import @1.1::EvsEventDesc;
 
 /**
  * Implemented on client side to receive asynchronous streaming event deliveries.
@@ -26,7 +26,7 @@
 interface IEvsCameraStream extends @1.0::IEvsCameraStream {
 
     /**
-     * Receives calls from the HAL each time a video frame is ready for inspection.
+     * Receives calls from the HAL each time video frames is ready for inspection.
      * Buffer handles received by this method must be returned via calls to
      * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call
      * to IEvsCamera::stopVideoStream(), this callback may continue to happen for
@@ -35,14 +35,19 @@
      * event must be delivered.  No further frame deliveries may happen
      * thereafter.
      *
-     * @param buffer a buffer descriptor of a delivered image frame.
+     * A camera device will deliver the same number of frames as number of
+     * backing physical camera devices; it means, a physical camera device
+     * sends always a single frame and a logical camera device sends multiple
+     * frames as many as number of backing physical camera devices.
+     *
+     * @param buffer Buffer descriptors of delivered image frames.
      */
-    oneway deliverFrame_1_1(BufferDesc buffer);
+    oneway deliverFrame_1_1(vec<BufferDesc> buffer);
 
     /**
      * Receives calls from the HAL each time an event happens.
      *
      * @param  event EVS event with possible event information.
      */
-    oneway notify(EvsEvent event);
+    oneway notify(EvsEventDesc event);
 };
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
index 41cb426..88fd657 100644
--- a/automotive/evs/1.1/default/Android.bp
+++ b/automotive/evs/1.1/default/Android.bp
@@ -16,7 +16,7 @@
     shared_libs: [
         "android.hardware.automotive.evs@1.0",
         "android.hardware.automotive.evs@1.1",
-        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
         "libbase",
         "libbinder",
         "liblog",
diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp
index 96a2f98..986793e 100644
--- a/automotive/evs/1.1/default/ConfigManager.cpp
+++ b/automotive/evs/1.1/default/ConfigManager.cpp
@@ -42,55 +42,32 @@
     while (curElem != nullptr) {
         if (!strcmp(curElem->Name(), "group")) {
             /* camera group identifier */
-            const char *group_id = curElem->FindAttribute("group_id")->Value();
+            const char *id = curElem->FindAttribute("id")->Value();
 
-            /* create CameraGroup */
-            unique_ptr<ConfigManager::CameraGroup> aCameraGroup(new ConfigManager::CameraGroup());
+            /* create a camera group to be filled */
+            CameraGroupInfo *aCamera = new CameraGroupInfo();
 
-            /* add a camera device to its group */
-            addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup);
-
-            /* a list of camera stream configurations */
-            const XMLElement *childElem =
-                curElem->FirstChildElement("caps")->FirstChildElement("stream");
-            while (childElem != nullptr) {
-                /* read 5 attributes */
-                const XMLAttribute *idAttr     = childElem->FindAttribute("id");
-                const XMLAttribute *widthAttr  = childElem->FindAttribute("width");
-                const XMLAttribute *heightAttr = childElem->FindAttribute("height");
-                const XMLAttribute *fmtAttr    = childElem->FindAttribute("format");
-                const XMLAttribute *fpsAttr    = childElem->FindAttribute("framerate");
-
-                const int32_t id = stoi(idAttr->Value());
-                int32_t framerate = 0;
-                if (fpsAttr != nullptr) {
-                    framerate = stoi(fpsAttr->Value());
-                }
-
-                int32_t pixFormat;
-                if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
-                                                            pixFormat)) {
-                    RawStreamConfiguration cfg = {
-                        id,
-                        stoi(widthAttr->Value()),
-                        stoi(heightAttr->Value()),
-                        pixFormat,
-                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-                        framerate
-                    };
-                    aCameraGroup->streamConfigurations[id] = cfg;
-                }
-
-                childElem = childElem->NextSiblingElement("stream");
+            /* read camera device information */
+            if (!readCameraDeviceInfo(aCamera, curElem)) {
+                ALOGW("Failed to read a camera information of %s", id);
+                delete aCamera;
+                continue;
             }
 
             /* camera group synchronization */
             const char *sync = curElem->FindAttribute("synchronized")->Value();
-            aCameraGroup->synchronized =
-                static_cast<bool>(strcmp(sync, "false"));
+            if (!strcmp(sync, "CALIBRATED")) {
+                aCamera->synchronized =
+                    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED;
+            } else if (!strcmp(sync, "APPROXIMATE")) {
+                aCamera->synchronized =
+                    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE;
+            } else {
+                aCamera->synchronized = 0; // Not synchronized
+            }
 
             /* add a group to hash map */
-            mCameraGroups[group_id] = std::move(aCameraGroup);
+            mCameraGroupInfos.insert_or_assign(id, unique_ptr<CameraGroupInfo>(aCamera));
         } else if (!strcmp(curElem->Name(), "device")) {
             /* camera unique identifier */
             const char *id = curElem->FindAttribute("id")->Value();
@@ -98,8 +75,18 @@
             /* camera mount location */
             const char *pos = curElem->FindAttribute("position")->Value();
 
+            /* create a camera device to be filled */
+            CameraInfo *aCamera = new CameraInfo();
+
+            /* read camera device information */
+            if (!readCameraDeviceInfo(aCamera, curElem)) {
+                ALOGW("Failed to read a camera information of %s", id);
+                delete aCamera;
+                continue;
+            }
+
             /* store read camera module information */
-            mCameraInfo[id] = readCameraDeviceInfo(curElem);
+            mCameraInfo.insert_or_assign(id, unique_ptr<CameraInfo>(aCamera));
 
             /* assign a camera device to a position group */
             mCameraPosition[pos].emplace(id);
@@ -113,15 +100,13 @@
 }
 
 
-unique_ptr<ConfigManager::CameraInfo>
-ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) {
-    if (aDeviceElem == nullptr) {
-        return nullptr;
+bool
+ConfigManager::readCameraDeviceInfo(CameraInfo *aCamera,
+                                    const XMLElement *aDeviceElem) {
+    if (aCamera == nullptr || aDeviceElem == nullptr) {
+        return false;
     }
 
-    /* create a CameraInfo to be filled */
-    unique_ptr<ConfigManager::CameraInfo> aCamera(new ConfigManager::CameraInfo());
-
     /* size information to allocate camera_metadata_t */
     size_t totalEntries = 0;
     size_t totalDataSize = 0;
@@ -145,14 +130,15 @@
               "allocated memory was not large enough");
     }
 
-    return aCamera;
+    return true;
 }
 
 
-size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
-                                             unique_ptr<ConfigManager::CameraInfo> &aCamera,
-                                             size_t &dataSize) {
-    if (aCapElem == nullptr) {
+size_t
+ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+                                      CameraInfo *aCamera,
+                                      size_t &dataSize) {
+    if (aCapElem == nullptr || aCamera == nullptr) {
         return 0;
     }
 
@@ -214,7 +200,7 @@
                 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
                 framerate
             };
-            aCamera->streamConfigurations[id] = cfg;
+            aCamera->streamConfigurations.insert_or_assign(id, cfg);
         }
 
         curElem = curElem->NextSiblingElement("stream");
@@ -232,10 +218,11 @@
 }
 
 
-size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
-                                       unique_ptr<ConfigManager::CameraInfo> &aCamera,
-                                       size_t &dataSize) {
-    if (aParamElem == nullptr) {
+size_t
+ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
+                                  CameraInfo *aCamera,
+                                  size_t &dataSize) {
+    if (aParamElem == nullptr || aCamera == nullptr) {
         return 0;
     }
 
@@ -258,8 +245,9 @@
                                         count
                                    );
 
-                    aCamera->cameraMetadata[tag] =
-                        make_pair(make_unique<void *>(data), count);
+                    aCamera->cameraMetadata.insert_or_assign(
+                        tag, make_pair(make_unique<void *>(data), count)
+                    );
 
                     ++numEntries;
                     dataSize += calculate_camera_metadata_entry_data_size(
@@ -269,6 +257,52 @@
                     break;
                 }
 
+                case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
+                    camera_metadata_enum_android_request_available_capabilities_t *data =
+                        new camera_metadata_enum_android_request_available_capabilities_t[1];
+                    if (ConfigManagerUtil::convertToCameraCapability(
+                            curElem->FindAttribute("value")->Value(), *data)) {
+                                        curElem->FindAttribute("value")->Value(),
+                        aCamera->cameraMetadata.insert_or_assign(
+                            tag, make_pair(make_unique<void *>(data), 1)
+                        );
+
+                        ++numEntries;
+                        dataSize += calculate_camera_metadata_entry_data_size(
+                                        get_camera_metadata_tag_type(tag), 1
+                                    );
+                    }
+                    break;
+                }
+
+                case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
+                    /* a comma-separated list of physical camera devices */
+                    size_t len = strlen(curElem->FindAttribute("value")->Value());
+                    char *data = new char[len + 1];
+                    memcpy(data,
+                           curElem->FindAttribute("value")->Value(),
+                           len * sizeof(char));
+
+                    /* replace commas with null char */
+                    char *p = data;
+                    while (*p != '\0') {
+                        if (*p == ',') {
+                            *p = '\0';
+                        }
+                        ++p;
+                    }
+
+                    aCamera->cameraMetadata.insert_or_assign(
+                        tag, make_pair(make_unique<void *>(data), len)
+                    );
+
+                    ++numEntries;
+                    dataSize += calculate_camera_metadata_entry_data_size(
+                                    get_camera_metadata_tag_type(tag), len
+                                );
+                    break;
+                }
+
                 default:
                     ALOGW("Parameter %s is not supported",
                           curElem->FindAttribute("name")->Value());
@@ -283,10 +317,11 @@
 }
 
 
-bool ConfigManager::constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
-                                            const size_t totalEntries,
-                                            const size_t totalDataSize) {
-    if (!aCamera->allocate(totalEntries, totalDataSize)) {
+bool
+ConfigManager::constructCameraMetadata(CameraInfo *aCamera,
+                                       const size_t totalEntries,
+                                       const size_t totalDataSize) {
+    if (aCamera == nullptr || !aCamera->allocate(totalEntries, totalDataSize)) {
         ALOGE("Failed to allocate memory for camera metadata");
         return false;
     }
@@ -401,14 +436,14 @@
                         ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
                         0   // unused
                     };
-                    dpy->streamConfigurations[id] = cfg;
+                    dpy->streamConfigurations.insert_or_assign(id, cfg);
                 }
 
                 curStream = curStream->NextSiblingElement("stream");
             }
         }
 
-        mDisplayInfo[id] = std::move(dpy);
+        mDisplayInfo.insert_or_assign(id, std::move(dpy));
         curDev = curDev->NextSiblingElement("device");
     }
 
@@ -457,16 +492,6 @@
 }
 
 
-void ConfigManager::addCameraDevices(const char *devices,
-                                     unique_ptr<CameraGroup> &aGroup) {
-    stringstream device_list(devices);
-    string token;
-    while (getline(device_list, token, ',')) {
-        aGroup->devices.emplace(token);
-    }
-}
-
-
 std::unique_ptr<ConfigManager> ConfigManager::Create(const char *path) {
     unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
 
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
index 0275f90..870af1c 100644
--- a/automotive/evs/1.1/default/ConfigManager.h
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -82,9 +82,6 @@
         unordered_map<CameraParam,
                       tuple<int32_t, int32_t, int32_t>> controls;
 
-        /* List of supported frame rates */
-        unordered_set<int32_t> frameRates;
-
         /*
          * List of supported output stream configurations; each array stores
          * format, width, height, and direction values in the order.
@@ -102,21 +99,15 @@
         camera_metadata_t *characteristics;
     };
 
-    class CameraGroup {
+    class CameraGroupInfo : public CameraInfo {
     public:
-        CameraGroup() {}
+        CameraGroupInfo() {}
 
         /* ID of member camera devices */
         unordered_set<string> devices;
 
         /* The capture operation of member camera devices are synchronized */
         bool synchronized = false;
-
-        /*
-         * List of stream configurations that are supposed by all camera devices
-         * in this group.
-         */
-        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
     };
 
     class SystemInfo {
@@ -165,11 +156,11 @@
     /*
      * Return a list of cameras
      *
-     * @return CameraGroup
+     * @return CameraGroupInfo
      *         A pointer to a camera group identified by a given id.
      */
-    unique_ptr<CameraGroup>& getCameraGroup(const string& gid) {
-        return mCameraGroups[gid];
+    unique_ptr<CameraGroupInfo>& getCameraGroupInfo(const string& gid) {
+        return mCameraGroupInfos[gid];
     }
 
 
@@ -203,8 +194,8 @@
     /* Internal data structure for camera device information */
     unordered_map<string, unique_ptr<DisplayInfo>> mDisplayInfo;
 
-    /* Camera groups are stored in <groud id, CameraGroup> hash map */
-    unordered_map<string, unique_ptr<CameraGroup>> mCameraGroups;
+    /* Camera groups are stored in <groud id, CameraGroupInfo> hash map */
+    unordered_map<string, unique_ptr<CameraGroupInfo>> mCameraGroupInfos;
 
     /*
      * Camera positions are stored in <position, camera id set> hash map.
@@ -253,16 +244,19 @@
     /*
      * read camera device information
      *
-     * @param  aDeviceElem
+     * @param  aCamera
+     *         A pointer to CameraInfo that will be completed by this
+     *         method.
+     *         aDeviceElem
      *         A pointer to "device" XML element that contains camera module
      *         capability info and its characteristics.
      *
-     * @return unique_ptr<CameraInfo>
-     *         A pointer to CameraInfo class that contains camera module
-     *         capability and characteristics.  Please note that this transfers
-     *         the ownership of created CameraInfo to the caller.
+     * @return bool
+     *         Return false upon any failure in reading and processing camera
+     *         device information.
      */
-    unique_ptr<CameraInfo> readCameraDeviceInfo(const XMLElement *aDeviceElem);
+    bool readCameraDeviceInfo(CameraInfo *aCamera,
+                              const XMLElement *aDeviceElem);
 
     /*
      * read camera metadata
@@ -280,7 +274,7 @@
      *         Number of camera metadata entries
      */
     size_t readCameraCapabilities(const XMLElement * const aCapElem,
-                                  unique_ptr<CameraInfo> &aCamera,
+                                  CameraInfo *aCamera,
                                   size_t &dataSize);
 
     /*
@@ -298,7 +292,7 @@
      *         Number of camera metadata entries
      */
     size_t readCameraMetadata(const XMLElement * const aParamElem,
-                              unique_ptr<CameraInfo> &aCamera,
+                              CameraInfo *aCamera,
                               size_t &dataSize);
 
     /*
@@ -316,21 +310,9 @@
      *         or its size is not large enough to add all found camera metadata
      *         entries.
      */
-    bool constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+    bool constructCameraMetadata(CameraInfo *aCamera,
                                  const size_t totalEntries,
                                  const size_t totalDataSize);
-
-    /*
-     * parse a comma-separated list of camera devices and add them to
-     * CameraGroup.
-     *
-     * @param  devices
-     *         A comma-separated list of camera device identifiers.
-     * @param  aGroup
-     *         Camera group which cameras will be added to.
-     */
-    void addCameraDevices(const char *devices,
-                          unique_ptr<CameraGroup> &aGroup);
 };
 #endif // CONFIG_MANAGER_H
 
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
index 8206daa..d10f236 100644
--- a/automotive/evs/1.1/default/ConfigManagerUtil.cpp
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
@@ -90,6 +90,30 @@
         aTag =  ANDROID_LENS_POSE_ROTATION;
     } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) {
         aTag =  ANDROID_LENS_POSE_TRANSLATION;
+    } else if (!strcmp(name, "REQUEST_AVAILABLE_CAPABILITIES")) {
+        aTag =  ANDROID_REQUEST_AVAILABLE_CAPABILITIES;
+    } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA_PHYSICAL_IDS")) {
+        aTag =  ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS;
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+
+bool ConfigManagerUtil::convertToCameraCapability(
+    const char *name,
+    camera_metadata_enum_android_request_available_capabilities_t &cap) {
+
+    if (!strcmp(name, "DEPTH_OUTPUT")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT;
+    } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA;
+    } else if (!strcmp(name, "MONOCHROME")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME;
+    } else if (!strcmp(name, "SECURE_IMAGE_DATA")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA;
     } else {
         return false;
     }
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h
index 8c89ae7..1710cac 100644
--- a/automotive/evs/1.1/default/ConfigManagerUtil.h
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.h
@@ -55,6 +55,14 @@
      */
     static string trimString(const string &src,
                              const string &ws = " \n\r\t\f\v");
+
+    /**
+     * Convert a given string to corresponding camera capabilities
+     */
+    static bool convertToCameraCapability(
+        const char *name,
+        camera_metadata_enum_android_request_available_capabilities_t &cap);
+
 };
 
 #endif // CONFIG_MANAGER_UTIL_H
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
index 5ba753d..b7e4efa 100644
--- a/automotive/evs/1.1/default/EvsCamera.cpp
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -21,7 +21,7 @@
 
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
-
+#include <utils/SystemClock.h>
 
 namespace android {
 namespace hardware {
@@ -240,9 +240,23 @@
 }
 
 
-Return<EvsResult> EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc)  {
+Return<void> EvsCamera::getPhysicalCameraInfo(const hidl_string& id,
+                                              getCameraInfo_1_1_cb _hidl_cb) {
+    ALOGD("%s", __FUNCTION__);
+
+    // This works exactly same as getCameraInfo_1_1() in default implementation.
+    (void)id;
+    _hidl_cb(mDescription);
+    return Void();
+}
+
+
+Return<EvsResult> EvsCamera::doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers)  {
     std::lock_guard <std::mutex> lock(mAccessLock);
-    returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle);
+
+    for (auto&& buffer : buffers) {
+        returnBuffer(buffer.bufferId, buffer.buffer.nativeHandle);
+    }
 
     return EvsResult::OK;
 }
@@ -490,12 +504,17 @@
             newBuffer.buffer.nativeHandle = mBuffers[idx].handle;
             newBuffer.pixelSize = sizeof(uint32_t);
             newBuffer.bufferId = idx;
+            newBuffer.deviceId = mDescription.v1.cameraId;
+            newBuffer.timestamp = elapsedRealtimeNano();
 
             // Write test data into the image buffer
             fillTestFrame(newBuffer);
 
             // Issue the (asynchronous) callback to the client -- can't be holding the lock
-            auto result = mStream->deliverFrame_1_1(newBuffer);
+            hidl_vec<BufferDesc_1_1> frames;
+            frames.resize(1);
+            frames[0] = newBuffer;
+            auto result = mStream->deliverFrame_1_1(frames);
             if (result.isOk()) {
                 ALOGD("Delivered %p as id %d",
                       newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId);
@@ -527,7 +546,7 @@
     }
 
     // If we've been asked to stop, send an event to signal the actual end of stream
-    EvsEvent event;
+    EvsEventDesc event;
     event.aType = EvsEventType::STREAM_STOPPED;
     auto result = mStream->notify(event);
     if (!result.isOk()) {
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
index c15b4b1..72a1b57 100644
--- a/automotive/evs/1.1/default/EvsCamera.h
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -62,9 +62,11 @@
 
     // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
     Return<void>      getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb)  override;
+    Return<void>      getPhysicalCameraInfo(const hidl_string& id,
+                                            getPhysicalCameraInfo_cb _hidl_cb)  override;
     Return<EvsResult> pauseVideoStream() override;
     Return<EvsResult> resumeVideoStream() override;
-    Return<EvsResult> doneWithFrame_1_1(const BufferDesc_1_1& buffer) override;
+    Return<EvsResult> doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
     Return<EvsResult> setMaster() override;
     Return<EvsResult> forceMaster(const sp<IEvsDisplay>& display) override;
     Return<EvsResult> unsetMaster() override;
diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
index 692102e..a79e7c2 100644
--- a/automotive/evs/1.1/default/resources/evs_default_configuration.xml
+++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
@@ -28,8 +28,31 @@
         <num_cameras value='1'/>
     </system>
 
-    <!-- camera device information -->
+    <!-- camera information -->
     <camera>
+        <!-- camera group starts -->
+        <group id='group1' synchronized='APPROXIMATE'>
+            <caps>
+                <stream id='0' width='640'  height='360'  format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <parameter
+                    name='REQUEST_AVAILABLE_CAPABILITIES'
+                    type='enum'
+                    size='1'
+                    value='LOGICAL_MULTI_CAMERA'
+                />
+                <parameter
+                    name='LOGICAL_MULTI_CAMERA_PHYSICAL_IDS'
+                    type='byte[]'
+                    size='1'
+                    value='/dev/video1'
+                />
+            </characteristics>
+        </group>
+
         <!-- camera device starts -->
         <device id='/dev/video1' position='rear'>
             <caps>
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
index dcb2abb..f88d223 100644
--- a/automotive/evs/1.1/types.hal
+++ b/automotive/evs/1.1/types.hal
@@ -61,6 +61,14 @@
      * Opaque value from driver
      */
     uint32_t bufferId;
+    /**
+     * Unique identifier of the physical camera device that produces this buffer.
+     */
+    string deviceId;
+    /**
+     * Time that this buffer is being filled.
+     */
+    int64_t timestamp;
 };
 
 /**
@@ -97,12 +105,16 @@
 /**
  * Structure that describes informative events occurred during EVS is streaming
  */
-struct EvsEvent {
+struct EvsEventDesc {
     /**
      * Type of an informative event
      */
     EvsEventType aType;
     /**
+     * Device identifier
+     */
+    string deviceId;
+    /**
      * Possible additional information
      */
     uint32_t[4] payload;
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
index 6d53652..ebf488a 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -80,7 +80,7 @@
     asyncStopStream();
 
     // Wait until the stream has actually stopped
-    std::unique_lock<std::mutex> lock(mLock);
+    std::unique_lock<std::mutex> lock(mEventLock);
     if (mRunning) {
         mEventSignal.wait(lock, [this]() { return !mRunning; });
     }
@@ -88,7 +88,7 @@
 
 
 bool FrameHandler::returnHeldBuffer() {
-    std::unique_lock<std::mutex> lock(mLock);
+    std::lock_guard<std::mutex> lock(mLock);
 
     // Return the oldest buffer we're holding
     if (mHeldBuffers.empty()) {
@@ -96,16 +96,16 @@
         return false;
     }
 
-    BufferDesc_1_1 buffer = mHeldBuffers.front();
+    hidl_vec<BufferDesc_1_1> buffers = mHeldBuffers.front();
     mHeldBuffers.pop();
-    mCamera->doneWithFrame_1_1(buffer);
+    mCamera->doneWithFrame_1_1(buffers);
 
     return true;
 }
 
 
 bool FrameHandler::isRunning() {
-    std::unique_lock<std::mutex> lock(mLock);
+    std::lock_guard<std::mutex> lock(mLock);
     return mRunning;
 }
 
@@ -120,7 +120,7 @@
 
 
 void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) {
-    std::unique_lock<std::mutex> lock(mLock);
+    std::lock_guard<std::mutex> lock(mLock);
 
     if (received) {
         *received = mFramesReceived;
@@ -138,11 +138,17 @@
 }
 
 
-Return<void> FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) {
+Return<void> FrameHandler::deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
+    mLock.lock();
+    // For VTS tests, FrameHandler uses a single frame among delivered frames.
+    auto bufferIdx = mFramesDisplayed % buffers.size();
+    auto buffer = buffers[bufferIdx];
+    mLock.unlock();
+
     const AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&buffer.buffer.description);
     ALOGD("Received a frame from the camera (%p)",
-          bufDesc.buffer.nativeHandle.getNativeHandle());
+          buffer.buffer.nativeHandle.getNativeHandle());
 
     // Store a dimension of a received frame.
     mFrameWidth = pDesc->width;
@@ -150,6 +156,7 @@
 
     // If we were given an opened display at construction time, then send the received
     // image back down the camera.
+    bool displayed = false;
     if (mDisplay.get()) {
         // Get the output buffer we'll use to display the imagery
         BufferDesc_1_0 tgtBuffer = {};
@@ -163,7 +170,7 @@
             ALOGE("Didn't get requested output buffer -- skipping this frame.");
         } else {
             // Copy the contents of the of buffer.memHandle into tgtBuffer
-            copyBufferContents(tgtBuffer, bufDesc);
+            copyBufferContents(tgtBuffer, buffer);
 
             // Send the target buffer back for display
             Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
@@ -179,40 +186,42 @@
             } else {
                 // Everything looks good!
                 // Keep track so tests or watch dogs can monitor progress
-                mLock.lock();
-                mFramesDisplayed++;
-                mLock.unlock();
+                displayed = true;
             }
         }
     }
 
+    mLock.lock();
+    // increases counters
+    ++mFramesReceived;
+    mFramesDisplayed += (int)displayed;
+    mLock.unlock();
+    mFrameSignal.notify_all();
 
     switch (mReturnMode) {
     case eAutoReturn:
         // Send the camera buffer back now that the client has seen it
         ALOGD("Calling doneWithFrame");
-        mCamera->doneWithFrame_1_1(bufDesc);
+        mCamera->doneWithFrame_1_1(buffers);
         break;
     case eNoAutoReturn:
-        // Hang onto the buffer handle for now -- the client will return it explicitly later
-        mHeldBuffers.push(bufDesc);
+        // Hang onto the buffer handles for now -- the client will return it explicitly later
+        mHeldBuffers.push(buffers);
+        break;
     }
 
-    mLock.lock();
-    ++mFramesReceived;
-    mLock.unlock();
-    mFrameSignal.notify_all();
-
     ALOGD("Frame handling complete");
 
     return Void();
 }
 
 
-Return<void> FrameHandler::notify(const EvsEvent& event) {
+Return<void> FrameHandler::notify(const EvsEventDesc& event) {
     // Local flag we use to keep track of when the stream is stopping
-    mLock.lock();
-    mLatestEventDesc = event;
+    std::unique_lock<std::mutex> lock(mEventLock);
+    mLatestEventDesc.aType = event.aType;
+    mLatestEventDesc.payload[0] = event.payload[0];
+    mLatestEventDesc.payload[1] = event.payload[1];
     if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) {
         // Signal that the last frame has been received and the stream is stopped
         mRunning = false;
@@ -222,8 +231,8 @@
     } else {
         ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
     }
-    mLock.unlock();
-    mEventSignal.notify_all();
+    lock.unlock();
+    mEventSignal.notify_one();
 
     return Void();
 }
@@ -342,25 +351,34 @@
     }
 }
 
-bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent,
-                                EvsEvent &event) {
+bool FrameHandler::waitForEvent(const EvsEventDesc& aTargetEvent,
+                                      EvsEventDesc& aReceivedEvent,
+                                      bool ignorePayload) {
     // Wait until we get an expected parameter change event.
-    std::unique_lock<std::mutex> lock(mLock);
+    std::unique_lock<std::mutex> lock(mEventLock);
     auto now = std::chrono::system_clock::now();
-    bool result = mEventSignal.wait_until(lock, now + 5s,
-        [this, aTargetEvent, &event](){
-            bool flag = mLatestEventDesc.aType == aTargetEvent;
-            if (flag) {
-                event.aType = mLatestEventDesc.aType;
-                event.payload[0] = mLatestEventDesc.payload[0];
-                event.payload[1] = mLatestEventDesc.payload[1];
+    bool found = false;
+    while (!found) {
+        bool result = mEventSignal.wait_until(lock, now + 5s,
+            [this, aTargetEvent, ignorePayload, &aReceivedEvent, &found](){
+                found = (mLatestEventDesc.aType == aTargetEvent.aType) &&
+                        (ignorePayload || (mLatestEventDesc.payload[0] == aTargetEvent.payload[0] &&
+                                           mLatestEventDesc.payload[1] == aTargetEvent.payload[1]));
+
+                aReceivedEvent.aType = mLatestEventDesc.aType;
+                aReceivedEvent.payload[0] = mLatestEventDesc.payload[0];
+                aReceivedEvent.payload[1] = mLatestEventDesc.payload[1];
+                return found;
             }
+        );
 
-            return flag;
+        if (!result) {
+            ALOGW("A timer is expired before a target event has happened.");
+            break;
         }
-    );
+    }
 
-    return !result;
+    return found;
 }
 
 const char *FrameHandler::eventToString(const EvsEventType aType) {
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
index e5f1b8f..21e85fe 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.h
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -73,8 +73,9 @@
     bool isRunning();
 
     void waitForFrameCount(unsigned frameCount);
-    bool waitForEvent(const EvsEventType aTargetEvent,
-                            EvsEvent &eventDesc);
+    bool waitForEvent(const EvsEventDesc& aTargetEvent,
+                            EvsEventDesc& aReceivedEvent,
+                            bool ignorePayload = false);
     void getFramesCounters(unsigned* received, unsigned* displayed);
     void getFrameDimension(unsigned* width, unsigned* height);
 
@@ -83,8 +84,8 @@
     Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
 
     // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
-    Return<void> deliverFrame_1_1(const BufferDesc_1_1& buffer) override;
-    Return<void> notify(const EvsEvent& event) override;
+    Return<void> deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
+    Return<void> notify(const EvsEventDesc& event) override;
 
     // Local implementation details
     bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer);
@@ -99,17 +100,18 @@
     // Since we get frames delivered to us asynchronously via the IEvsCameraStream interface,
     // we need to protect all member variables that may be modified while we're streaming
     // (ie: those below)
-    std::mutex                  mLock;
-    std::condition_variable     mEventSignal;
-    std::condition_variable     mFrameSignal;
+    std::mutex                            mLock;
+    std::mutex                            mEventLock;
+    std::condition_variable               mEventSignal;
+    std::condition_variable               mFrameSignal;
+    std::queue<hidl_vec<BufferDesc_1_1>>  mHeldBuffers;
 
-    std::queue<BufferDesc_1_1>  mHeldBuffers;
     bool                        mRunning = false;
     unsigned                    mFramesReceived = 0;    // Simple counter -- rolls over eventually!
     unsigned                    mFramesDisplayed = 0;   // Simple counter -- rolls over eventually!
     unsigned                    mFrameWidth = 0;
     unsigned                    mFrameHeight = 0;
-    EvsEvent                    mLatestEventDesc;
+    EvsEventDesc                mLatestEventDesc;
 };
 
 
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 1d3fd87..4fc4e4c 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -41,6 +41,8 @@
 #include <cstdio>
 #include <cstring>
 #include <cstdlib>
+#include <thread>
+#include <unordered_set>
 
 #include <hidl/HidlTransportSupport.h>
 #include <hwbinder/ProcessState.h>
@@ -67,6 +69,7 @@
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::sp;
+using ::android::wp;
 using ::android::hardware::camera::device::V3_2::Stream;
 using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
 using ::android::hardware::automotive::evs::V1_0::DisplayState;
@@ -117,7 +120,15 @@
         mIsHwModule = !service_name.compare(kEnumeratorName);
     }
 
-    virtual void TearDown() override {}
+    virtual void TearDown() override {
+        // Attempt to close any active camera
+        for (auto &&c : activeCameras) {
+            sp<IEvsCamera_1_1> cam = c.promote();
+            if (cam != nullptr) {
+                pEnumerator->closeCamera(cam);
+            }
+        }
+    }
 
 protected:
     void loadCameraList() {
@@ -141,10 +152,90 @@
         ASSERT_GE(cameraInfo.size(), 1u);
     }
 
-    sp<IEvsEnumerator>        pEnumerator;    // Every test needs access to the service
-    std::vector <CameraDesc>  cameraInfo;     // Empty unless/until loadCameraList() is called
-    bool                      mIsHwModule;    // boolean to tell current module under testing
-                                              // is HW module implementation.
+    bool isLogicalCamera(const camera_metadata_t *metadata) {
+        if (metadata == nullptr) {
+            // A logical camera device must have a valid camera metadata.
+            return false;
+        }
+
+        // Looking for LOGICAL_MULTI_CAMERA capability from metadata.
+        camera_metadata_ro_entry_t entry;
+        int rc = find_camera_metadata_ro_entry(metadata,
+                                               ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                               &entry);
+        if (0 != rc) {
+            // No capabilities are found.
+            return false;
+        }
+
+        for (size_t i = 0; i < entry.count; ++i) {
+            uint8_t cap = entry.data.u8[i];
+            if (cap == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    std::unordered_set<std::string> getPhysicalCameraIds(const std::string& id,
+                                                         bool& flag) {
+        std::unordered_set<std::string> physicalCameras;
+
+        auto it = cameraInfo.begin();
+        while (it != cameraInfo.end()) {
+            if (it->v1.cameraId == id) {
+                break;
+            }
+            ++it;
+        }
+
+        if (it == cameraInfo.end()) {
+            // Unknown camera is requested.  Return an empty list.
+            return physicalCameras;
+        }
+
+        const camera_metadata_t *metadata =
+            reinterpret_cast<camera_metadata_t *>(&it->metadata[0]);
+        flag = isLogicalCamera(metadata);
+        if (!flag) {
+            // EVS assumes that the device w/o a valid metadata is a physical
+            // device.
+            ALOGI("%s is not a logical camera device.", id.c_str());
+            physicalCameras.emplace(id);
+            return physicalCameras;
+        }
+
+        // Look for physical camera identifiers
+        camera_metadata_ro_entry entry;
+        int rc = find_camera_metadata_ro_entry(metadata,
+                                               ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
+                                               &entry);
+        ALOGE_IF(rc, "No physical camera ID is found for a logical camera device");
+
+        const uint8_t *ids = entry.data.u8;
+        size_t start = 0;
+        for (size_t i = 0; i < entry.count; ++i) {
+            if (ids[i] == '\0') {
+                if (start != i) {
+                    std::string id(reinterpret_cast<const char *>(ids + start));
+                    physicalCameras.emplace(id);
+                }
+                start = i + 1;
+            }
+        }
+
+        ALOGI("%s consists of %d physical camera devices.", id.c_str(), (int)physicalCameras.size());
+        return physicalCameras;
+    }
+
+
+    sp<IEvsEnumerator>              pEnumerator;   // Every test needs access to the service
+    std::vector<CameraDesc>         cameraInfo;    // Empty unless/until loadCameraList() is called
+    bool                            mIsHwModule;   // boolean to tell current module under testing
+                                                   // is HW module implementation.
+    std::deque<wp<IEvsCamera_1_1>>  activeCameras; // A list of active camera handles that are
+                                                   // needed to be cleaned up.
 };
 
 
@@ -168,12 +259,32 @@
 
     // Open and close each camera twice
     for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            continue;
+        }
+
         for (int pass = 0; pass < 2; pass++) {
+            activeCameras.clear();
             sp<IEvsCamera_1_1> pCam =
                 IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
                 .withDefault(nullptr);
             ASSERT_NE(pCam, nullptr);
 
+            for (auto&& devName : devices) {
+                bool matched = false;
+                pCam->getPhysicalCameraInfo(devName,
+                                            [&devName, &matched](const CameraDesc& info) {
+                                                matched = devName == info.v1.cameraId;
+                                            });
+                ASSERT_TRUE(matched);
+            }
+
+            // Store a camera handle for a clean-up
+            activeCameras.push_back(pCam);
+
             // Verify that this camera self-identifies correctly
             pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
                                         ALOGD("Found camera %s", desc.v1.cameraId.c_str());
@@ -206,11 +317,22 @@
 
     // Open and close each camera twice
     for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            continue;
+        }
+
+        activeCameras.clear();
         sp<IEvsCamera_1_1> pCam =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
         // Verify that this camera self-identifies correctly
         pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
                                     ALOGD("Found camera %s", desc.v1.cameraId.c_str());
@@ -221,9 +343,13 @@
         sp<IEvsCamera_1_1> pCam2 =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
-        ASSERT_NE(pCam, pCam2);
         ASSERT_NE(pCam2, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam2);
+
+        ASSERT_NE(pCam, pCam2);
+
         Return<EvsResult> result = pCam->setMaxFramesInFlight(2);
         if (mIsHwModule) {
             // Verify that the old camera rejects calls via HW module.
@@ -268,11 +394,22 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            continue;
+        }
+
+        activeCameras.clear();
         sp<IEvsCamera_1_1> pCam =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
         // Set up a frame receiver object which will fire up its own thread
         sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
                                                          nullptr,
@@ -280,6 +417,7 @@
 
         // Start the camera's video stream
         nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
+
         bool startResult = frameHandler->startStream();
         ASSERT_TRUE(startResult);
 
@@ -287,9 +425,17 @@
         frameHandler->waitForFrameCount(1);
         nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
         nsecs_t timeToFirstFrame = systemTime(SYSTEM_TIME_MONOTONIC) - start;
-        EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame), kMaxStreamStartMilliseconds);
-        printf("Measured time to first frame %0.2f ms\n", timeToFirstFrame * kNanoToMilliseconds);
-        ALOGI("Measured time to first frame %0.2f ms", timeToFirstFrame * kNanoToMilliseconds);
+
+        // Extra delays are expected when we attempt to start a video stream on
+        // the logical camera device.  The amount of delay is expected the
+        // number of physical camera devices multiplied by
+        // kMaxStreamStartMilliseconds at most.
+        EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame),
+                  kMaxStreamStartMilliseconds * devices.size());
+        printf("%s: Measured time to first frame %0.2f ms\n",
+               cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
+        ALOGI("%s: Measured time to first frame %0.2f ms",
+              cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
 
         // Check aspect ratio
         unsigned width = 0, height = 0;
@@ -299,6 +445,13 @@
         // Wait a bit, then ensure we get at least the required minimum number of frames
         sleep(5);
         nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        // Even when the camera pointer goes out of scope, the FrameHandler object will
+        // keep the stream alive unless we tell it to shutdown.
+        // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+        // we have to break that cycle in order for either of them to get cleaned up.
+        frameHandler->shutdown();
+
         unsigned framesReceived = 0;
         frameHandler->getFramesCounters(&framesReceived, nullptr);
         framesReceived = framesReceived - 1;    // Back out the first frame we already waited for
@@ -308,12 +461,6 @@
         ALOGI("Measured camera rate %3.2f fps", framesPerSecond);
         EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond);
 
-        // Even when the camera pointer goes out of scope, the FrameHandler object will
-        // keep the stream alive unless we tell it to shutdown.
-        // Also note that the FrameHandle and the Camera have a mutual circular reference, so
-        // we have to break that cycle in order for either of them to get cleaned up.
-        frameHandler->shutdown();
-
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam);
     }
@@ -340,12 +487,22 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            continue;
+        }
 
+        activeCameras.clear();
         sp<IEvsCamera_1_1> pCam =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
         // Ask for a crazy number of buffers in flight to ensure it errors correctly
         Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
         EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
@@ -366,7 +523,7 @@
 
         // Check that the video stream stalls once we've gotten exactly the number of buffers
         // we requested since we told the frameHandler not to return them.
-        sleep(2);   // 1 second should be enough for at least 5 frames to be delivered worst case
+        sleep(1);   // 1 second should be enough for at least 5 frames to be delivered worst case
         unsigned framesReceived = 0;
         frameHandler->getFramesCounters(&framesReceived, nullptr);
         ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
@@ -416,11 +573,22 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            continue;
+        }
+
+        activeCameras.clear();
         sp<IEvsCamera_1_1> pCam =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
         // Set up a frame receiver object which will fire up its own thread.
         sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
                                                          pDisplay,
@@ -484,17 +652,24 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        activeCameras.clear();
         // Create two camera clients.
         sp<IEvsCamera_1_1> pCam0 =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam0, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam0);
+
         sp<IEvsCamera_1_1> pCam1 =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam1, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam1);
+
         // Set up per-client frame receiver objects which will fire up its own thread
         sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
                                                           nullptr,
@@ -554,6 +729,11 @@
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam0);
         pEnumerator->closeCamera(pCam1);
+
+        // TODO(b/145459970, b/145457727): below sleep() is added to ensure the
+        // destruction of active camera objects; this may be related with two
+        // issues.
+        sleep(1);
     }
 }
 
@@ -575,12 +755,25 @@
     // Test each reported camera
     Return<EvsResult> result = EvsResult::OK;
     for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (isLogicalCam) {
+            // TODO(b/145465724): Support camera parameter programming on
+            // logical devices.
+            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            continue;
+        }
+
+        activeCameras.clear();
         // Create a camera client
         sp<IEvsCamera_1_1> pCam =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
+        // Store a camera
+        activeCameras.push_back(pCam);
+
         // Get the parameter list
         std::vector<CameraParam> cmds;
         pCam->getParameterList([&cmds](hidl_vec<CameraParam> cmdList) {
@@ -626,48 +819,54 @@
             EvsResult result = EvsResult::OK;
             if (cmd == CameraParam::ABSOLUTE_FOCUS) {
                 // Try to turn off auto-focus
-                int32_t val1 = 0;
-                pCam->getIntParameter(CameraParam::AUTO_FOCUS,
-                                   [&result, &val1](auto status, auto value) {
+                std::vector<int32_t> values;
+                pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &values](auto status, auto effectiveValues) {
                                        result = status;
                                        if (status == EvsResult::OK) {
-                                          val1 = value;
+                                          for (auto &&v : effectiveValues) {
+                                              values.push_back(v);
+                                          }
                                        }
                                    });
-                if (val1 != 0) {
-                    pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
-                                       [&result, &val1](auto status, auto effectiveValue) {
-                                           result = status;
-                                           val1 = effectiveValue;
-                                       });
-                    ASSERT_EQ(EvsResult::OK, result);
-                    ASSERT_EQ(val1, 0);
+                ASSERT_EQ(EvsResult::OK, result);
+                for (auto &&v : values) {
+                    ASSERT_EQ(v, 0);
                 }
             }
 
             // Try to program a parameter with a random value [minVal, maxVal]
             int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
-            int32_t val1 = 0;
+            std::vector<int32_t> values;
 
             // Rounding down
             val0 = val0 - (val0 % step);
             pCam->setIntParameter(cmd, val0,
-                               [&result, &val1](auto status, auto effectiveValue) {
+                               [&result, &values](auto status, auto effectiveValues) {
                                    result = status;
-                                   val1 = effectiveValue;
+                                   if (status == EvsResult::OK) {
+                                      for (auto &&v : effectiveValues) {
+                                          values.push_back(v);
+                                      }
+                                   }
                                });
 
             ASSERT_EQ(EvsResult::OK, result);
 
+            values.clear();
             pCam->getIntParameter(cmd,
-                               [&result, &val1](auto status, auto value) {
+                               [&result, &values](auto status, auto readValues) {
                                    result = status;
                                    if (status == EvsResult::OK) {
-                                      val1 = value;
+                                      for (auto &&v : readValues) {
+                                          values.push_back(v);
+                                      }
                                    }
                                });
             ASSERT_EQ(EvsResult::OK, result);
-            ASSERT_EQ(val0, val1) << "Values are not matched.";
+            for (auto &&v : values) {
+                ASSERT_EQ(val0, v) << "Values are not matched.";
+            }
         }
 
         result = pCam->unsetMaster();
@@ -704,16 +903,33 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (isLogicalCam) {
+            // TODO(b/145465724): Support camera parameter programming on
+            // logical devices.
+            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            continue;
+        }
+
+        activeCameras.clear();
         // Create two camera clients.
         sp<IEvsCamera_1_1> pCamMaster =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCamMaster, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCamMaster);
+
         sp<IEvsCamera_1_1> pCamNonMaster =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCamNonMaster, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCamNonMaster);
+
         // Set up per-client frame receiver objects which will fire up its own thread
         sp<FrameHandler> frameHandlerMaster =
             new FrameHandler(pCamMaster, cam,
@@ -750,13 +966,45 @@
 
         // Non-master client expects to receive a master role relesed
         // notification.
-        EvsEvent aNotification = {};
+        EvsEventDesc aTargetEvent  = {};
+        EvsEventDesc aNotification = {};
+
+        bool listening = false;
+        std::mutex eventLock;
+        std::condition_variable eventCond;
+        std::thread listener = std::thread(
+            [&aNotification, &frameHandlerNonMaster, &listening, &eventCond]() {
+                // Notify that a listening thread is running.
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+                if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+                    ALOGW("A timer is expired before a target event is fired.");
+                }
+
+            }
+        );
+
+        // Wait until a listening thread starts.
+        std::unique_lock<std::mutex> lock(eventLock);
+        auto timer = std::chrono::system_clock::now();
+        while (!listening) {
+            timer += 1s;
+            eventCond.wait_until(lock, timer);
+        }
+        lock.unlock();
 
         // Release a master role.
         pCamMaster->unsetMaster();
 
-        // Verify a change notification.
-        frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+        // Join a listening thread.
+        if (listener.joinable()) {
+            listener.join();
+        }
+
+        // Verify change notifications.
         ASSERT_EQ(EvsEventType::MASTER_RELEASED,
                   static_cast<EvsEventType>(aNotification.aType));
 
@@ -768,23 +1016,49 @@
         result = pCamMaster->setMaster();
         ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
 
+        listening = false;
+        listener = std::thread(
+            [&aNotification, &frameHandlerMaster, &listening, &eventCond]() {
+                // Notify that a listening thread is running.
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+                if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+                    ALOGW("A timer is expired before a target event is fired.");
+                }
+
+            }
+        );
+
+        // Wait until a listening thread starts.
+        timer = std::chrono::system_clock::now();
+        lock.lock();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
         // Closing current master client.
         frameHandlerNonMaster->shutdown();
 
-        // Verify a change notification.
-        frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+        // Join a listening thread.
+        if (listener.joinable()) {
+            listener.join();
+        }
+
+        // Verify change notifications.
         ASSERT_EQ(EvsEventType::MASTER_RELEASED,
                   static_cast<EvsEventType>(aNotification.aType));
 
-        // Closing another stream.
+        // Closing streams.
         frameHandlerMaster->shutdown();
 
         // Explicitly release the camera
         pEnumerator->closeCamera(pCamMaster);
         pEnumerator->closeCamera(pCamNonMaster);
     }
-
-
 }
 
 
@@ -810,16 +1084,33 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (isLogicalCam) {
+            // TODO(b/145465724): Support camera parameter programming on
+            // logical devices.
+            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            continue;
+        }
+
+        activeCameras.clear();
         // Create two camera clients.
         sp<IEvsCamera_1_1> pCamMaster =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCamMaster, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCamMaster);
+
         sp<IEvsCamera_1_1> pCamNonMaster =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCamNonMaster, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCamNonMaster);
+
         // Get the parameter list
         std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
         pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
@@ -879,7 +1170,9 @@
         frameHandlerNonMaster->waitForFrameCount(1);
 
         int32_t val0 = 0;
-        int32_t val1 = 0;
+        std::vector<int32_t> values;
+        EvsEventDesc aNotification0 = {};
+        EvsEventDesc aNotification1 = {};
         for (auto &cmd : camMasterCmds) {
             // Get a valid parameter value range
             int32_t minVal, maxVal, step;
@@ -895,60 +1188,143 @@
             EvsResult result = EvsResult::OK;
             if (cmd == CameraParam::ABSOLUTE_FOCUS) {
                 // Try to turn off auto-focus
-                int32_t val1 = 1;
+                values.clear();
                 pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
-                                   [&result, &val1](auto status, auto effectiveValue) {
+                                   [&result, &values](auto status, auto effectiveValues) {
                                        result = status;
-                                       val1 = effectiveValue;
+                                       if (status == EvsResult::OK) {
+                                          for (auto &&v : effectiveValues) {
+                                              values.push_back(v);
+                                          }
+                                       }
                                    });
                 ASSERT_EQ(EvsResult::OK, result);
-                ASSERT_EQ(val1, 0);
+                for (auto &&v : values) {
+                    ASSERT_EQ(v, 0);
+                }
             }
 
-            // Try to program a parameter
+            // Calculate a parameter value to program.
             val0 = minVal + (std::rand() % (maxVal - minVal));
-
-            // Rounding down
             val0 = val0 - (val0 % step);
+
+            // Prepare and start event listeners.
+            bool listening0 = false;
+            bool listening1 = false;
+            std::condition_variable eventCond;
+            std::thread listener0 = std::thread(
+                [cmd, val0,
+                 &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+                    listening0 = true;
+                    if (listening1) {
+                        eventCond.notify_all();
+                    }
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                    aTargetEvent.payload[1] = val0;
+                    if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+                        ALOGW("A timer is expired before a target event is fired.");
+                    }
+                }
+            );
+            std::thread listener1 = std::thread(
+                [cmd, val0,
+                 &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+                    listening1 = true;
+                    if (listening0) {
+                        eventCond.notify_all();
+                    }
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                    aTargetEvent.payload[1] = val0;
+                    if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+                        ALOGW("A timer is expired before a target event is fired.");
+                    }
+                }
+            );
+
+            // Wait until a listening thread starts.
+            std::mutex eventLock;
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening0 || !listening1) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to program a parameter
+            values.clear();
             pCamMaster->setIntParameter(cmd, val0,
-                                     [&result, &val1](auto status, auto effectiveValue) {
-                                         result = status;
-                                         val1 = effectiveValue;
-                                     });
-            ASSERT_EQ(EvsResult::OK, result);
-
-            // Wait a moment
-            sleep(1);
-
-            // Non-master client expects to receive a parameter change notification
-            // whenever a master client adjusts it.
-            EvsEvent aNotification = {};
-
-            pCamMaster->getIntParameter(cmd,
-                                     [&result, &val1](auto status, auto value) {
+                                     [&result, &values](auto status, auto effectiveValues) {
                                          result = status;
                                          if (status == EvsResult::OK) {
-                                            val1 = value;
+                                            for (auto &&v : effectiveValues) {
+                                                values.push_back(v);
+                                            }
+                                         }
+                                     });
+
+            ASSERT_EQ(EvsResult::OK, result);
+            for (auto &&v : values) {
+                ASSERT_EQ(val0, v) << "Values are not matched.";
+            }
+
+            // Join a listening thread.
+            if (listener0.joinable()) {
+                listener0.join();
+            }
+            if (listener1.joinable()) {
+                listener1.join();
+            }
+
+            // Verify a change notification
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification0.aType));
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification1.aType));
+            ASSERT_EQ(cmd,
+                      static_cast<CameraParam>(aNotification0.payload[0]));
+            ASSERT_EQ(cmd,
+                      static_cast<CameraParam>(aNotification1.payload[0]));
+            for (auto &&v : values) {
+                ASSERT_EQ(v,
+                          static_cast<int32_t>(aNotification0.payload[1]));
+                ASSERT_EQ(v,
+                          static_cast<int32_t>(aNotification1.payload[1]));
+            }
+
+            // Clients expects to receive a parameter change notification
+            // whenever a master client adjusts it.
+            values.clear();
+            pCamMaster->getIntParameter(cmd,
+                                     [&result, &values](auto status, auto readValues) {
+                                         result = status;
+                                         if (status == EvsResult::OK) {
+                                            for (auto &&v : readValues) {
+                                                values.push_back(v);
+                                            }
                                          }
                                      });
             ASSERT_EQ(EvsResult::OK, result);
-            ASSERT_EQ(val0, val1) << "Values are not matched.";
-
-            // Verify a change notification
-            frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
-            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
-                      static_cast<EvsEventType>(aNotification.aType));
-            ASSERT_EQ(cmd,
-                      static_cast<CameraParam>(aNotification.payload[0]));
-            ASSERT_EQ(val1,
-                      static_cast<int32_t>(aNotification.payload[1]));
+            for (auto &&v : values) {
+                ASSERT_EQ(val0, v) << "Values are not matched.";
+            }
         }
 
         // Try to adjust a parameter via non-master client
+        values.clear();
         pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
-                                    [&result, &val1](auto status, auto effectiveValue) {
+                                    [&result, &values](auto status, auto effectiveValues) {
                                         result = status;
-                                        val1 = effectiveValue;
+                                        if (status == EvsResult::OK) {
+                                            for (auto &&v : effectiveValues) {
+                                                values.push_back(v);
+                                            }
+                                        }
                                     });
         ASSERT_EQ(EvsResult::INVALID_ARG, result);
 
@@ -957,14 +1333,48 @@
         ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
 
         // Master client retires from a master role
+        bool listening = false;
+        std::condition_variable eventCond;
+        std::thread listener = std::thread(
+            [&aNotification0, &frameHandlerNonMaster, &listening, &eventCond]() {
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+                if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) {
+                    ALOGW("A timer is expired before a target event is fired.");
+                }
+            }
+        );
+
+        std::mutex eventLock;
+        auto timer = std::chrono::system_clock::now();
+        unique_lock<std::mutex> lock(eventLock);
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
         result = pCamMaster->unsetMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
+        if (listener.joinable()) {
+            listener.join();
+        }
+        ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+                  static_cast<EvsEventType>(aNotification0.aType));
+
         // Try to adjust a parameter after being retired
+        values.clear();
         pCamMaster->setIntParameter(camMasterCmds[0], val0,
-                                 [&result, &val1](auto status, auto effectiveValue) {
+                                 [&result, &values](auto status, auto effectiveValues) {
                                      result = status;
-                                     val1 = effectiveValue;
+                                     if (status == EvsResult::OK) {
+                                        for (auto &&v : effectiveValues) {
+                                            values.push_back(v);
+                                        }
+                                     }
                                  });
         ASSERT_EQ(EvsResult::INVALID_ARG, result);
 
@@ -986,55 +1396,128 @@
             );
 
             EvsResult result = EvsResult::OK;
+            values.clear();
             if (cmd == CameraParam::ABSOLUTE_FOCUS) {
                 // Try to turn off auto-focus
-                int32_t val1 = 1;
+                values.clear();
                 pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
-                                   [&result, &val1](auto status, auto effectiveValue) {
+                                   [&result, &values](auto status, auto effectiveValues) {
                                        result = status;
-                                       val1 = effectiveValue;
+                                       if (status == EvsResult::OK) {
+                                          for (auto &&v : effectiveValues) {
+                                              values.push_back(v);
+                                          }
+                                       }
                                    });
                 ASSERT_EQ(EvsResult::OK, result);
-                ASSERT_EQ(val1, 0);
+                for (auto &&v : values) {
+                    ASSERT_EQ(v, 0);
+                }
             }
 
-            // Try to program a parameter
+            // Calculate a parameter value to program.  This is being rounding down.
             val0 = minVal + (std::rand() % (maxVal - minVal));
-
-            // Rounding down
             val0 = val0 - (val0 % step);
+
+            // Prepare and start event listeners.
+            bool listening0 = false;
+            bool listening1 = false;
+            std::condition_variable eventCond;
+            std::thread listener0 = std::thread(
+                [&cmd, &val0, &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+                    listening0 = true;
+                    if (listening1) {
+                        eventCond.notify_all();
+                    }
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                    aTargetEvent.payload[1] = val0;
+                    if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+                        ALOGW("A timer is expired before a target event is fired.");
+                    }
+                }
+            );
+            std::thread listener1 = std::thread(
+                [&cmd, &val0, &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+                    listening1 = true;
+                    if (listening0) {
+                        eventCond.notify_all();
+                    }
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                    aTargetEvent.payload[1] = val0;
+                    if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+                        ALOGW("A timer is expired before a target event is fired.");
+                    }
+                }
+            );
+
+            // Wait until a listening thread starts.
+            std::mutex eventLock;
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening0 || !listening1) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to program a parameter
+            values.clear();
             pCamNonMaster->setIntParameter(cmd, val0,
-                                        [&result, &val1](auto status, auto effectiveValue) {
-                                            result = status;
-                                            val1 = effectiveValue;
-                                        });
-            ASSERT_EQ(EvsResult::OK, result);
-
-            // Wait a moment
-            sleep(1);
-
-            // Non-master client expects to receive a parameter change notification
-            // whenever a master client adjusts it.
-            EvsEvent aNotification = {};
-
-            pCamNonMaster->getIntParameter(cmd,
-                                        [&result, &val1](auto status, auto value) {
+                                        [&result, &values](auto status, auto effectiveValues) {
                                             result = status;
                                             if (status == EvsResult::OK) {
-                                               val1 = value;
+                                                for (auto &&v : effectiveValues) {
+                                                    values.push_back(v);
+                                                }
                                             }
                                         });
             ASSERT_EQ(EvsResult::OK, result);
-            ASSERT_EQ(val0, val1) << "Values are not matched.";
+
+            // Clients expects to receive a parameter change notification
+            // whenever a master client adjusts it.
+            values.clear();
+            pCamNonMaster->getIntParameter(cmd,
+                                        [&result, &values](auto status, auto readValues) {
+                                            result = status;
+                                            if (status == EvsResult::OK) {
+                                                for (auto &&v : readValues) {
+                                                    values.push_back(v);
+                                                }
+                                            }
+                                        });
+            ASSERT_EQ(EvsResult::OK, result);
+            for (auto &&v : values) {
+                ASSERT_EQ(val0, v) << "Values are not matched.";
+            }
+
+            // Join a listening thread.
+            if (listener0.joinable()) {
+                listener0.join();
+            }
+            if (listener1.joinable()) {
+                listener1.join();
+            }
 
             // Verify a change notification
-            frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
             ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
-                      static_cast<EvsEventType>(aNotification.aType));
+                      static_cast<EvsEventType>(aNotification0.aType));
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification1.aType));
             ASSERT_EQ(cmd,
-                      static_cast<CameraParam>(aNotification.payload[0]));
-            ASSERT_EQ(val1,
-                      static_cast<int32_t>(aNotification.payload[1]));
+                      static_cast<CameraParam>(aNotification0.payload[0]));
+            ASSERT_EQ(cmd,
+                      static_cast<CameraParam>(aNotification1.payload[0]));
+            for (auto &&v : values) {
+                ASSERT_EQ(v,
+                          static_cast<int32_t>(aNotification0.payload[1]));
+                ASSERT_EQ(v,
+                          static_cast<int32_t>(aNotification1.payload[1]));
+            }
         }
 
         // New master retires from a master role
@@ -1078,17 +1561,25 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        activeCameras.clear();
+
         // Create two clients
         sp<IEvsCamera_1_1> pCam0 =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam0, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam0);
+
         sp<IEvsCamera_1_1> pCam1 =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam1, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam1);
+
         // Get the parameter list; this test will use the first command in both
         // lists.
         std::vector<CameraParam> cam0Cmds, cam1Cmds;
@@ -1144,108 +1635,260 @@
             }
         );
 
-        if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
-            // Try to turn off auto-focus
-            int32_t val1 = 0;
-            pCam1->getIntParameter(CameraParam::AUTO_FOCUS,
-                               [&result, &val1](auto status, auto value) {
-                                   result = status;
-                                   if (status == EvsResult::OK) {
-                                      val1 = value;
-                                   }
-                               });
-            if (val1 != 0) {
-                pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
-                                   [&result, &val1](auto status, auto effectiveValue) {
-                                       result = status;
-                                       val1 = effectiveValue;
-                                   });
-                ASSERT_EQ(EvsResult::OK, result);
-                ASSERT_EQ(val1, 0);
-            }
-        }
-
-        // Try to program a parameter with a random value [minVal, maxVal]
-        int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
-        int32_t val1 = 0;
-
-        // Rounding down
-        val0 = val0 - (val0 % step);
-
+        // Client1 becomes a master
         result = pCam1->setMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
+        std::vector<int32_t> values;
+        EvsEventDesc aTargetEvent  = {};
+        EvsEventDesc aNotification = {};
+        bool listening = false;
+        std::mutex eventLock;
+        std::condition_variable eventCond;
+        if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+            std::thread listener = std::thread(
+                [&frameHandler0, &aNotification, &listening, &eventCond] {
+                    listening = true;
+                    eventCond.notify_all();
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+                    aTargetEvent.payload[1] = 0;
+                    if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+                        ALOGW("A timer is expired before a target event is fired.");
+                    }
+                }
+            );
+
+            // Wait until a lister starts.
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to turn off auto-focus
+            pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                               [&result, &values](auto status, auto effectiveValues) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      for (auto &&v : effectiveValues) {
+                                          values.push_back(v);
+                                      }
+                                   }
+                               });
+            ASSERT_EQ(EvsResult::OK, result);
+            for (auto &&v : values) {
+                ASSERT_EQ(v, 0);
+            }
+
+            // Join a listener
+            if (listener.joinable()) {
+                listener.join();
+            }
+
+            // Make sure AUTO_FOCUS is off.
+            ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                      EvsEventType::PARAMETER_CHANGED);
+        }
+
+        // Try to program a parameter with a random value [minVal, maxVal] after
+        // rounding it down.
+        int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+        val0 = val0 - (val0 % step);
+
+        std::thread listener = std::thread(
+            [&frameHandler1, &aNotification, &listening, &eventCond, &cam1Cmds, val0] {
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                aTargetEvent.payload[0] = static_cast<uint32_t>(cam1Cmds[0]);
+                aTargetEvent.payload[1] = val0;
+                if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+                    ALOGW("A timer is expired before a target event is fired.");
+                }
+            }
+        );
+
+        // Wait until a lister starts.
+        listening = false;
+        std::unique_lock<std::mutex> lock(eventLock);
+        auto timer = std::chrono::system_clock::now();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        values.clear();
         pCam1->setIntParameter(cam1Cmds[0], val0,
-                            [&result, &val1](auto status, auto effectiveValue) {
+                            [&result, &values](auto status, auto effectiveValues) {
                                 result = status;
-                                val1 = effectiveValue;
+                                if (status == EvsResult::OK) {
+                                    for (auto &&v : effectiveValues) {
+                                        values.push_back(v);
+                                    }
+                                }
                             });
         ASSERT_EQ(EvsResult::OK, result);
+        for (auto &&v : values) {
+            ASSERT_EQ(val0, v);
+        }
+
+        // Join a listener
+        if (listener.joinable()) {
+            listener.join();
+        }
 
         // Verify a change notification
-        EvsEvent aNotification = {};
-        bool timeout =
-            frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
-        ASSERT_FALSE(timeout) << "Expected event does not arrive";
         ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
                   EvsEventType::PARAMETER_CHANGED);
         ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
                   cam1Cmds[0]);
-        ASSERT_EQ(val1,
-                  static_cast<int32_t>(aNotification.payload[1]));
+        for (auto &&v : values) {
+            ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        listener = std::thread(
+            [&frameHandler1, &aNotification, &listening, &eventCond] {
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+                if (!frameHandler1->waitForEvent(aTargetEvent, aNotification, true)) {
+                    ALOGW("A timer is expired before a target event is fired.");
+                }
+            }
+        );
+
+        // Wait until a lister starts.
+        listening = false;
+        lock.lock();
+        timer = std::chrono::system_clock::now();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
 
         // Client 0 steals a master role
         ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
 
-        frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+        // Join a listener
+        if (listener.joinable()) {
+            listener.join();
+        }
+
         ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
                   EvsEventType::MASTER_RELEASED);
 
         // Client 0 programs a parameter
         val0 = minVal + (std::rand() % (maxVal - minVal));
-        val1 = 0;
 
         // Rounding down
         val0 = val0 - (val0 % step);
 
         if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+            std::thread listener = std::thread(
+                [&frameHandler1, &aNotification, &listening, &eventCond] {
+                    listening = true;
+                    eventCond.notify_all();
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+                    aTargetEvent.payload[1] = 0;
+                    if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+                        ALOGW("A timer is expired before a target event is fired.");
+                    }
+                }
+            );
+
+            // Wait until a lister starts.
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
             // Try to turn off auto-focus
-            int32_t val1 = 0;
-            pCam0->getIntParameter(CameraParam::AUTO_FOCUS,
-                               [&result, &val1](auto status, auto value) {
+            values.clear();
+            pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                               [&result, &values](auto status, auto effectiveValues) {
                                    result = status;
                                    if (status == EvsResult::OK) {
-                                      val1 = value;
+                                      for (auto &&v : effectiveValues) {
+                                          values.push_back(v);
+                                      }
                                    }
                                });
-            if (val1 != 0) {
-                pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
-                                   [&result, &val1](auto status, auto effectiveValue) {
-                                       result = status;
-                                       val1 = effectiveValue;
-                                   });
-                ASSERT_EQ(EvsResult::OK, result);
-                ASSERT_EQ(val1, 0);
+            ASSERT_EQ(EvsResult::OK, result);
+            for (auto &&v : values) {
+                ASSERT_EQ(v, 0);
             }
+
+            // Join a listener
+            if (listener.joinable()) {
+                listener.join();
+            }
+
+            // Make sure AUTO_FOCUS is off.
+            ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                      EvsEventType::PARAMETER_CHANGED);
         }
 
+        listener = std::thread(
+            [&frameHandler0, &aNotification, &listening, &eventCond, &cam0Cmds, val0] {
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                aTargetEvent.payload[0] = static_cast<uint32_t>(cam0Cmds[0]);
+                aTargetEvent.payload[1] = val0;
+                if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+                    ALOGW("A timer is expired before a target event is fired.");
+                }
+            }
+        );
+
+        // Wait until a lister starts.
+        listening = false;
+        timer = std::chrono::system_clock::now();
+        lock.lock();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        values.clear();
         pCam0->setIntParameter(cam0Cmds[0], val0,
-                            [&result, &val1](auto status, auto effectiveValue) {
+                            [&result, &values](auto status, auto effectiveValues) {
                                 result = status;
-                                val1 = effectiveValue;
+                                if (status == EvsResult::OK) {
+                                    for (auto &&v : effectiveValues) {
+                                        values.push_back(v);
+                                    }
+                                }
                             });
         ASSERT_EQ(EvsResult::OK, result);
 
+        // Join a listener
+        if (listener.joinable()) {
+            listener.join();
+        }
         // Verify a change notification
-        timeout =
-            frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
-        ASSERT_FALSE(timeout) << "Expected event does not arrive";
         ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
                   EvsEventType::PARAMETER_CHANGED);
         ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
                   cam0Cmds[0]);
-        ASSERT_EQ(val1,
-                  static_cast<int32_t>(aNotification.payload[1]));
+        for (auto &&v : values) {
+            ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+        }
 
         // Turn off the display (yes, before the stream stops -- it should be handled)
         pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
@@ -1282,6 +1925,7 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        activeCameras.clear();
         // choose a configuration that has a frame rate faster than minReqFps.
         Stream targetCfg = {};
         const int32_t minReqFps = 15;
@@ -1324,6 +1968,9 @@
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
         // Set up a frame receiver object which will fire up its own thread.
         sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
                                                          pDisplay,
@@ -1383,6 +2030,7 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        activeCameras.clear();
         // choose a configuration that has a frame rate faster than minReqFps.
         Stream targetCfg = {};
         const int32_t minReqFps = 15;
@@ -1427,6 +2075,9 @@
             .withDefault(nullptr);
         ASSERT_NE(pCam0, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam0);
+
         // Try to create the second camera client with different stream
         // configuration.
         int32_t id = targetCfg.id;
@@ -1436,6 +2087,9 @@
             .withDefault(nullptr);
         ASSERT_EQ(pCam1, nullptr);
 
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam0);
+
         // Try again with same stream configuration.
         targetCfg.id = id;
         pCam1 =
@@ -1506,6 +2160,30 @@
 }
 
 
+/*
+ * LogicalCameraMetadata:
+ * Opens logical camera reported by the enumerator and validate its metadata by
+ * checking its capability and locating supporting physical camera device
+ * identifiers.
+ */
+TEST_F(EvsHidlTest, LogicalCameraMetadata) {
+    ALOGI("Starting LogicalCameraMetadata test");
+
+    // Get the camera list
+    loadCameraList();
+
+    // Open and close each camera twice
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (isLogicalCam) {
+            ASSERT_GE(devices.size(), 1) <<
+                "Logical camera device must have at least one physical camera device ID in its metadata.";
+        }
+    }
+}
+
+
 int main(int argc, char** argv) {
     ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
diff --git a/automotive/occupant_awareness/aidl/Android.bp b/automotive/occupant_awareness/aidl/Android.bp
index 6e9e8aa..face235 100644
--- a/automotive/occupant_awareness/aidl/Android.bp
+++ b/automotive/occupant_awareness/aidl/Android.bp
@@ -7,7 +7,12 @@
     stability: "vintf",
     backend: {
         java: {
-            enabled: false,
+            platform_apis: true,
         },
-    }
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
 }
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 6f2d292..f55e799 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -1,5 +1,5 @@
 aidl_interface {
-    name: "vintf-common",
+    name: "android.hardware.common",
     host_supported: true,
     vendor_available: true,
     vndk: {
diff --git a/current.txt b/current.txt
index 921a103..3f169db 100644
--- a/current.txt
+++ b/current.txt
@@ -588,11 +588,11 @@
 cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
 b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
 eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
-f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types
+8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types
 5f6d3097ba84cb63c430787123f4de1b31c11f90b531b98eae9a8623a5ae962a android.hardware.neuralnetworks@1.1::types
 fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice
 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel
-2d5483fbf59d5fd2de94665a6df05da5c3d09de67561d0db5e9f09e59e9aea46 android.hardware.neuralnetworks@1.2::types
+7f7ef383268c95a1b8fe4e55c662bc806bb0ac11a154f6b049a113a44b0f024f 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
@@ -648,22 +648,22 @@
 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice
 258825966435b3ed08832055bb736d81516013e405f161d9ccde9a90cfcdde83 android.hardware.neuralnetworks@1.3::IPreparedModel
 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types
+618a628f8c94d6f6e4cb401b69fa50ccb8b82191ea434e3a071252289b4f312c android.hardware.neuralnetworks@1.3::types
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
-36b3acf78ac4ecf8156be8741c1d8332cdce7a1ebf4dfa1562952f14a94e6c87 android.hardware.wifi.hostapd@1.2::IHostapd
-2defa258951e25a132aaeb36e3febe6f41bf9c6dbb1b1ebdf0b41708ab4e107e android.hardware.wifi.hostapd@1.2::types
+514dc8b810658c45d7b0d34132b708cee2658ecedd9c7efc57d0d666ef182484 android.hardware.wifi.hostapd@1.2::IHostapd
+11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types
 a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
 c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
 342a8e12db4dca643f2755eb4167e8f103d96502053a25a1f51f42107a4530f1 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
-5477f8bafb29548875622fa83f1c0a29cee641acee613315eb747731001f4aff android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
+8835e9799cddf7c239f60beff467cbdf164331f70a8b6c06ed78982d7810d835 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
 91015479f5a0fba9872e98d3cca4680995de64f42ae71461b4b7e5acc5a196ab android.hardware.wifi.supplicant@1.3::types
-d9044563a5ac5a17a239303b8dec1e51167761ac46e965f61e31654cc034d31b android.hardware.radio@1.5::types
-afa2d6cf4c0ba4b8482d5bcc097594ad5bc49be0bf3003034f75955cdaf66045 android.hardware.radio@1.5::IRadio
+2c0587a1e83facba604949c31163486f21eb5b47a29c8f29119a47d3bd052103 android.hardware.radio@1.5::types
+b5cfa87882b416105fe01e8a40a856d36c93d64f1103d77e12b1281cea13b0bd android.hardware.radio@1.5::IRadio
 bc59237dbd93949238081f762710552e76670cb648c0e198138551460ac54b1e android.hardware.radio@1.5::IRadioIndication
-f4888f9676890b43a459c6380f335fea7a6ad32ed3bafafeb018a88d6c0be8a4 android.hardware.radio@1.5::IRadioResponse
+ef10e15cdbe8ba63925302a95962d5679bbda6a4351400cc23e1589ca0e9f94b android.hardware.radio@1.5::IRadioResponse
 55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types
 b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
 7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse
-c411dc16855fcb786cd5e08fe2889acbd72fd54217bd27fe0373813de230ce5f android.hardware.soundtrigger@2.3::types
-5abad7b54d3400fab633cb7a36ffc1747e037bf805d3d9e3517cb6aabf26b002 android.hardware.soundtrigger@2.3::ISoundTriggerHw
+b46d358537168c478762c3d34d5fe1555a3fcd89cd1f43621350ada395e6f795 android.hardware.soundtrigger@2.3::types
+15924fbf38b3c282299a37e48c72405c97e322f844f815081db6acbca22d4165 android.hardware.soundtrigger@2.3::ISoundTriggerHw
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index 8ddc380..2db3607 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -152,6 +152,7 @@
                 return Void();
             }
 
+            base = static_cast<uint8_t *>(static_cast<void *>(destBase->getPointer()));
             destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
         } else if (destination.type == BufferType::NATIVE_HANDLE) {
             if (!secure) {
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index fcd4efc..601cabc 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -1,5 +1,5 @@
 aidl_interface {
-    name: "vintf-graphics-common",
+    name: "android.hardware.graphics.common",
     host_supported: true,
     vendor_available: true,
     vndk: {
@@ -11,7 +11,7 @@
     ],
     stability: "vintf",
     imports: [
-        "vintf-common"
+        "android.hardware.common",
     ],
     backend: {
         java: {
diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
index ebac2e0..64ed4f3 100644
--- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
+++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
@@ -403,6 +403,11 @@
     }
 
    protected:
+     template <typename T>
+     void beginCommand(T command, uint16_t length) {
+         beginCommandBase(static_cast<IComposerClient::Command>(command), length);
+     }
+
     void setClientTargetInternal(uint32_t slot, const native_handle_t* target, int acquireFence,
                                  int32_t dataspace,
                                  const std::vector<IComposerClient::Rect>& damage) {
@@ -429,7 +434,7 @@
         endCommand();
     }
 
-    void beginCommand(IComposerClient::Command command, uint16_t length) {
+    void beginCommandBase(IComposerClient::Command command, uint16_t length) {
         if (mCommandEnd) {
             LOG_FATAL("endCommand was not called before command 0x%x", command);
         }
diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
index 35162a6..00f427a 100644
--- a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
+++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
@@ -76,15 +76,14 @@
 
     static constexpr uint16_t kSetLayerFloatColorLength = 4;
     void setLayerFloatColor(IComposerClient::FloatColor color) {
-        beginCommand_2_2(IComposerClient::Command::SET_LAYER_FLOAT_COLOR,
-                         kSetLayerFloatColorLength);
+        beginCommand(IComposerClient::Command::SET_LAYER_FLOAT_COLOR, kSetLayerFloatColorLength);
         writeFloatColor(color);
         endCommand();
     }
 
     void setLayerPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
-        beginCommand_2_2(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
-                         metadataVec.size() * 2);
+        beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
+                     metadataVec.size() * 2);
         for (const auto& metadata : metadataVec) {
             writeSigned(static_cast<int32_t>(metadata.key));
             writeFloat(metadata.value);
@@ -99,12 +98,6 @@
         writeFloat(color.b);
         writeFloat(color.a);
     }
-
-  private:
-    void beginCommand_2_2(IComposerClient::Command command, uint16_t length) {
-        V2_1::CommandWriterBase::beginCommand(
-                static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
-    }
 };
 
 // This class helps parse a command queue.  Note that all sizes/lengths are in
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
index 3dfda19..afc22d8 100644
--- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -46,8 +46,8 @@
 class CommandWriterBase : public V2_2::CommandWriterBase {
    public:
     void setLayerPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
-        beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
-                         metadataVec.size() * 2);
+        beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
+                     metadataVec.size() * 2);
         for (const auto& metadata : metadataVec) {
             writeSigned(static_cast<int32_t>(metadata.key));
             writeFloat(metadata.value);
@@ -69,8 +69,8 @@
 
     static constexpr uint16_t kSetLayerColorTransformLength = 16;
     void setLayerColorTransform(const float* matrix) {
-        beginCommand_2_3(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM,
-                         kSetLayerColorTransformLength);
+        beginCommand(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM,
+                     kSetLayerColorTransformLength);
         for (int i = 0; i < 16; i++) {
             writeFloat(matrix[i]);
         }
@@ -109,7 +109,7 @@
         // Blobs are written as:
         // {numElements, key1, size1, blob1, key2, size2, blob2, key3, size3...}
         uint16_t length = static_cast<uint16_t>(commandLength);
-        beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length);
+        beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length);
         write(static_cast<uint32_t>(metadata.size()));
         for (auto metadataBlob : metadata) {
             writeSigned(static_cast<int32_t>(metadataBlob.key));
@@ -126,12 +126,6 @@
         mDataWritten += numElements;
         mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0;
     }
-
-  private:
-    void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
-        V2_1::CommandWriterBase::beginCommand(
-                static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
-    }
 };
 
 // This class helps parse a command queue.  Note that all sizes/lengths are in
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
index d3b29bb..e0e1394 100644
--- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
@@ -294,9 +294,6 @@
             (brightness < 0.0f && brightness != -1.0f)) {
             return Error::BAD_PARAMETER;
         }
-        if (!mDispatch.setDisplayBrightness) {
-            return Error::UNSUPPORTED;
-        }
         int32_t error = mDispatch.setDisplayBrightness(mDevice, display, brightness);
         return static_cast<Error>(error);
     }
@@ -307,6 +304,13 @@
             return false;
         }
 
+        if (!BaseType2_1::initDispatch(HWC2_FUNCTION_GET_DISPLAY_CAPABILITIES,
+                                       &mDispatch.getDisplayCapabilities) ||
+            !BaseType2_1::initDispatch(HWC2_FUNCTION_SET_DISPLAY_BRIGHTNESS,
+                                       &mDispatch.setDisplayBrightness)) {
+            return false;
+        }
+
         this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
                                    &mDispatch.getDisplayIdentificationData);
         this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
@@ -317,14 +321,10 @@
                                    &mDispatch.setDisplayedContentSamplingEnabled);
         this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLE,
                                    &mDispatch.getDisplayedContentSample);
-        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CAPABILITIES,
-                                   &mDispatch.getDisplayCapabilities);
         this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_PER_FRAME_METADATA_BLOBS,
                                    &mDispatch.setLayerPerFrameMetadataBlobs);
         this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_BRIGHTNESS_SUPPORT,
                                    &mDispatch.getDisplayBrightnessSupport);
-        this->initOptionalDispatch(HWC2_FUNCTION_SET_DISPLAY_BRIGHTNESS,
-                                   &mDispatch.setDisplayBrightness);
         return true;
     }
 
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
index a27582a..9e7684d 100644
--- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -59,9 +59,6 @@
                 mDevice, HWC2_CALLBACK_REFRESH, this,
                 reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
         BaseType2_1::mDispatch.registerCallback(
-                mDevice, HWC2_CALLBACK_VSYNC, this,
-                reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
-        BaseType2_1::mDispatch.registerCallback(
                 mDevice, HWC2_CALLBACK_VSYNC_2_4, this,
                 reinterpret_cast<hwc2_function_pointer_t>(vsync_2_4_Hook));
 
@@ -80,7 +77,6 @@
         // which is likely incorrect
         BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, nullptr);
         BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, nullptr);
-        BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, nullptr);
         BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, nullptr);
         BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED,
                                                 this, nullptr);
@@ -224,12 +220,15 @@
             return false;
         }
 
+        if (!BaseType2_1::initDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD,
+                                       &mDispatch.getDisplayVsyncPeriod) ||
+            !BaseType2_1::initDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS,
+                                       &mDispatch.setActiveConfigWithConstraints)) {
+            return false;
+        }
+
         this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CONNECTION_TYPE,
                                    &mDispatch.getDisplayConnectionType);
-        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD,
-                                   &mDispatch.getDisplayVsyncPeriod);
-        this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS,
-                                   &mDispatch.setActiveConfigWithConstraints);
         this->initOptionalDispatch(HWC2_FUNCTION_SET_AUTO_LOW_LATENCY_MODE,
                                    &mDispatch.setAutoLowLatencyMode);
         this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_CONTENT_TYPES,
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index 926cf31..3542a6e 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -19,10 +19,10 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
     static_libs: [
+        "android.hardware.graphics.common-ndk_platform",
         "android.hardware.graphics.mapper@4.0-vts",
         "libgralloctypes",
         "libsync",
-        "vintf-graphics-common-ndk_platform",
     ],
     shared_libs: [
         "android.hardware.graphics.allocator@4.0",
@@ -34,5 +34,8 @@
     header_libs: [
         "libsystem_headers",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/health/2.1/README.md b/health/2.1/README.md
index 5a19d7b..bfcf13b 100644
--- a/health/2.1/README.md
+++ b/health/2.1/README.md
@@ -99,6 +99,11 @@
 
 For example (replace `<device>` with the device name):
 ```
+# device/<manufacturer>/<device>/sepolicy/vendor/file_contexts
+# Required for charger to open passthrough implementation. Replace <device> with the proper device
+# name. File name must be consistent with `stem` of the implementation module.
+/vendor/lib(64)?/hw/android\.hardware\.health@2\.0-impl-2\.1-<device>\.so u:object_r:same_process_hal_file:s0
+
 # device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
 # Add device specific permissions to hal_health_default domain, especially
 # if a device-specific libhealthd is used and/or device-specific storage related
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 07409f6..7241984 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -201,22 +201,6 @@
     CheckedDeleteKey(&key_blob_);
 }
 
-void KeymasterHidlTest::CheckCreationDateTime(
-        const AuthorizationSet& sw_enforced,
-        std::chrono::time_point<std::chrono::system_clock> creation) {
-    for (int i = 0; i < sw_enforced.size(); i++) {
-        if (sw_enforced[i].tag == TAG_CREATION_DATETIME) {
-            std::chrono::time_point<std::chrono::system_clock> now =
-                    std::chrono::system_clock::now();
-            std::chrono::time_point<std::chrono::system_clock> reported_time{
-                    std::chrono::milliseconds(sw_enforced[i].f.dateTime)};
-            // The test is flaky for EC keys, so a buffer time of 120 seconds will be added.
-            EXPECT_LE(creation - std::chrono::seconds(120), reported_time);
-            EXPECT_LE(reported_time, now + std::chrono::seconds(1));
-        }
-    }
-}
-
 void KeymasterHidlTest::CheckGetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
                                                 const HidlBuf& app_data,
                                                 KeyCharacteristics* key_characteristics) {
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index adceead..4bd8b26 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -113,9 +113,6 @@
     void CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob = false);
     void CheckedDeleteKey();
 
-    static void CheckCreationDateTime(const AuthorizationSet& sw_enforced,
-                                      std::chrono::time_point<std::chrono::system_clock> creation);
-
     void CheckGetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
                                  const HidlBuf& app_data, KeyCharacteristics* key_characteristics);
     ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
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 f78eb43..66132ad 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -320,8 +320,7 @@
 bool verify_attestation_record(const string& challenge, const string& app_id,
                                AuthorizationSet expected_sw_enforced,
                                AuthorizationSet expected_hw_enforced, SecurityLevel security_level,
-                               const hidl_vec<uint8_t>& attestation_cert,
-                               std::chrono::time_point<std::chrono::system_clock> creation_time) {
+                               const hidl_vec<uint8_t>& attestation_cert) {
     X509_Ptr cert(parse_cert_blob(attestation_cert));
     EXPECT_TRUE(!!cert.get());
     if (!cert.get()) return false;
@@ -405,8 +404,6 @@
     EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
     EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
 
-    KeymasterHidlTest::CheckCreationDateTime(att_sw_enforced, creation_time);
-
     if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
         // For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
         EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
@@ -559,24 +556,6 @@
 }
 
 /*
- * NewKeyGenerationTest.RsaCheckCreationDateTime
- *
- * Verifies that creation date time is correct.
- */
-TEST_P(NewKeyGenerationTest, RsaCheckCreationDateTime) {
-    KeyCharacteristics key_characteristics;
-    auto creation_time = std::chrono::system_clock::now();
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                 .RsaSigningKey(2048, 3)
-                                                 .Digest(Digest::NONE)
-                                                 .Padding(PaddingMode::NONE)));
-    GetCharacteristics(key_blob_, &key_characteristics);
-    AuthorizationSet sw_enforced = key_characteristics.softwareEnforced;
-    CheckCreationDateTime(sw_enforced, creation_time);
-}
-
-/*
  * NewKeyGenerationTest.NoInvalidRsaSizes
  *
  * Verifies that keymaster cannot generate any RSA key sizes that are designated as invalid.
@@ -641,23 +620,6 @@
 }
 
 /*
- * NewKeyGenerationTest.EcCheckCreationDateTime
- *
- * Verifies that creation date time is correct.
- */
-TEST_P(NewKeyGenerationTest, EcCheckCreationDateTime) {
-    KeyCharacteristics key_characteristics;
-    auto creation_time = std::chrono::system_clock::now();
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                 .EcdsaSigningKey(256)
-                                                 .Digest(Digest::NONE)));
-    GetCharacteristics(key_blob_, &key_characteristics);
-    AuthorizationSet sw_enforced = key_characteristics.softwareEnforced;
-    CheckCreationDateTime(sw_enforced, creation_time);
-}
-
-/*
  * NewKeyGenerationTest.EcdsaDefaultSize
  *
  * Verifies that failing to specify a key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
@@ -2645,8 +2607,10 @@
                                    .Padding(PaddingMode::NONE));
     ASSERT_EQ(ErrorCode::OK, err) << "Got " << err;
 
-    err = Begin(KeyPurpose::DECRYPT,
-                AuthorizationSetBuilder().BlockMode(BlockMode::GCM).Padding(PaddingMode::NONE));
+    err = Begin(KeyPurpose::DECRYPT, AuthorizationSetBuilder()
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MAC_LENGTH, 128));
     EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
 
     CheckedDeleteKey();
@@ -2659,8 +2623,10 @@
                                                  .Authorization(TAG_MIN_MAC_LENGTH, 128)
                                                  .Padding(PaddingMode::NONE)));
 
-    err = Begin(KeyPurpose::ENCRYPT,
-                AuthorizationSetBuilder().BlockMode(BlockMode::GCM).Padding(PaddingMode::NONE));
+    err = Begin(KeyPurpose::ENCRYPT, AuthorizationSetBuilder()
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MAC_LENGTH, 128));
     EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
 }
 
@@ -4238,7 +4204,6 @@
  * Verifies that attesting to RSA keys works and generates the expected output.
  */
 TEST_P(AttestationTest, RsaAttestation) {
-    auto creation_time = std::chrono::system_clock::now();
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(2048, 65537)
@@ -4263,7 +4228,7 @@
     EXPECT_TRUE(verify_attestation_record("challenge", "foo",                     //
                                           key_characteristics_.softwareEnforced,  //
                                           key_characteristics_.hardwareEnforced,  //
-                                          SecLevel(), cert_chain[0], creation_time));
+                                          SecLevel(), cert_chain[0]));
 }
 
 /*
@@ -4292,7 +4257,6 @@
  * Verifies that attesting to EC keys works and generates the expected output.
  */
 TEST_P(AttestationTest, EcAttestation) {
-    auto creation_time = std::chrono::system_clock::now();
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .EcdsaSigningKey(EcCurve::P_256)
@@ -4314,7 +4278,7 @@
     EXPECT_TRUE(verify_attestation_record("challenge", "foo",                     //
                                           key_characteristics_.softwareEnforced,  //
                                           key_characteristics_.hardwareEnforced,  //
-                                          SecLevel(), cert_chain[0], creation_time));
+                                          SecLevel(), cert_chain[0]));
 }
 
 /*
@@ -4347,7 +4311,6 @@
 TEST_P(AttestationTest, AttestationApplicationIDLengthProperlyEncoded) {
     std::vector<uint32_t> app_id_lengths{143, 258};
     for (uint32_t length : app_id_lengths) {
-        auto creation_time = std::chrono::system_clock::now();
         ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                      .Authorization(TAG_NO_AUTH_REQUIRED)
                                                      .EcdsaSigningKey(EcCurve::P_256)
@@ -4365,7 +4328,7 @@
         EXPECT_TRUE(verify_attestation_record("challenge", app_id,                    //
                                               key_characteristics_.softwareEnforced,  //
                                               key_characteristics_.hardwareEnforced,  //
-                                              SecLevel(), cert_chain[0], creation_time));
+                                              SecLevel(), cert_chain[0]));
         CheckedDeleteKey();
     }
 }
diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal
index ba9d068..1175a30 100644
--- a/neuralnetworks/1.0/types.hal
+++ b/neuralnetworks/1.0/types.hal
@@ -261,8 +261,8 @@
      *      filter.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
      *      tensor of type {@link OperandType::TENSOR_FLOAT32}
-     *      the bias must be of the same
-     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias must be of the same type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
      *      of 0 and bias_scale == input_scale * filter_scale.
      * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -290,7 +290,8 @@
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
      *      tensor of type {@link OperandType::TENSOR_FLOAT32}
      *      the bias must be of the same
-     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
      *      of 0 and bias_scale == input_scale * filter_scale.
      * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
@@ -355,8 +356,8 @@
      *      specifying the filter.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
      *      tensor of type {@link OperandType::TENSOR_FLOAT32}
-     *      the bias must be of the same
-     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias must be of the same type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
      *      of 0 and bias_scale == input_scale * filter_scale.
      * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -384,8 +385,8 @@
      *      specifying the filter.
      * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
      *      tensor of type {@link OperandType::TENSOR_FLOAT32}
-     *      the bias must be of the same
-     *      type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+     *      the bias must be of the same type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
      *      of 0 and bias_scale == input_scale * filter_scale.
      * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
@@ -492,8 +493,6 @@
      *
      * Supported value tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_INT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      *
      * Supported value tensor rank: from 2
      *
@@ -556,10 +555,10 @@
      *      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.
+     *      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.
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index b111d96..e867120 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -375,8 +375,8 @@
      *      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},
+     *      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},
@@ -425,7 +425,8 @@
      * * 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},
+     *      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},
@@ -523,8 +524,8 @@
      *      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},
+     *      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},
@@ -569,8 +570,8 @@
      *      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},
+     *      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},
@@ -705,8 +706,8 @@
      *
      * Supported value tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_INT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_INT32} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
      *
      * Supported value tensor rank: from 2
      *
@@ -772,10 +773,10 @@
      *      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.
+     *      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.
@@ -2659,7 +2660,8 @@
      *      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.
+     *      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.
@@ -2686,6 +2688,7 @@
      *      [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},
+     *      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
@@ -2703,7 +2706,7 @@
     BOX_WITH_NMS_LIMIT = 44,
 
     /**
-     * Casts a tensor to a new type.
+     * Casts a tensor to a type.
      *
      * This operation ignores the scale and zeroPoint of quanized tensors,
      * e.g. it treats a {@link OperandType::TENSOR_QUANT8_ASYMM} input
@@ -3141,8 +3144,8 @@
      *      {@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},
+     *      {@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
@@ -3181,7 +3184,8 @@
      * * 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},
+     *      {@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
@@ -3661,21 +3665,24 @@
      * 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.
+     *      the scales and zeroPoint can be different from input0 scale and zeroPoint.
      */
     PRELU = 71,
 
     /**
      * Quantizes the input tensor.
      *
-     * The formula is:
+     * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM} output tensor is:
      *
      *     output = max(0, min(255, round(input / scale) + zeroPoint)
      *
-     * Supported tensor {@link OperandType}:
+     * Supported input tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      *
+     * Supported output tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *
      * Supported tensor rank: from 1
      *
      * Inputs:
@@ -4325,15 +4332,15 @@
      *      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].
+     *      {@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 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
@@ -4363,14 +4370,14 @@
      * * 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].
+     *      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 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
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 84c4813..74c259c 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -110,6 +110,7 @@
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
      *
      * Supported tensor rank: up to 4
      *
@@ -123,11 +124,13 @@
      * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
      *      {@link FusedActivationFunc} values. Specifies the activation to
      *      invoke on the result.
+     *      For a {@link OperandType::TENSOR_INT32} tensor,
+     *      the {@link FusedActivationFunc} must be "NONE".
      *
      * 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,
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
      */
     ADD = @1.2::OperationType:ADD,
@@ -293,6 +296,18 @@
      * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
      * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
      *
+     * Available since HAL version 1.3:
+     * * Quantized signed (since HAL version 1.3):
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} 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
@@ -313,8 +328,9 @@
      *      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},
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
      *      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},
@@ -363,7 +379,9 @@
      * * 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},
+     *      type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
      *      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},
@@ -443,6 +461,18 @@
      * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
      * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
      *
+     * Available since HAL version 1.3:
+     * * Quantized signed (since HAL version 1.3):
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} 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
@@ -461,8 +491,9 @@
      *      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},
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
      *      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},
@@ -507,8 +538,9 @@
      *      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},
+     *      or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
      *      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},
@@ -569,6 +601,7 @@
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
@@ -589,7 +622,8 @@
      * 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,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     DEPTH_TO_SPACE = @1.2::OperationType:DEPTH_TO_SPACE,
@@ -605,6 +639,7 @@
      * * {@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)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported output tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
@@ -642,9 +677,11 @@
      * and an error must be reported.
      *
      * Supported value tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.3)
      * * {@link OperandType::TENSOR_FLOAT32}
-     * * {@link OperandType::TENSOR_INT32}
-     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_INT32} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported value tensor rank: from 2
      *
@@ -658,7 +695,8 @@
      * * 0: A n-D tensor with the same rank and shape as the Values
      *      tensor, except for the first dimension which has the same size
      *      as Lookups' only dimension.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input1.
      */
     EMBEDDING_LOOKUP = @1.2::OperationType:EMBEDDING_LOOKUP,
@@ -693,6 +731,7 @@
      * * {@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.
      *
@@ -710,10 +749,11 @@
      *      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.
+     *      also be of {@link OperandType::TENSOR_FLOAT32}.
+     *      For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      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.
@@ -798,6 +838,7 @@
      * * {@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
      * Tensors with rank less than 4 are only supported since HAL version 1.2.
@@ -814,6 +855,8 @@
      * * 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.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      the scale must be 1.f / 128 and the zeroPoint must be 0.
      */
     L2_NORMALIZATION = @1.2::OperationType:L2_NORMALIZATION,
 
@@ -1507,6 +1550,7 @@
      * * {@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: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
@@ -1549,7 +1593,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, new_height, new_width, depth].
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     RESIZE_BILINEAR = @1.2::OperationType:RESIZE_BILINEAR,
@@ -1624,6 +1669,7 @@
      * * {@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.
      * Tensors with rank other than 2 or 4 are only supported since HAL version 1.2.
@@ -1632,9 +1678,10 @@
      * * 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}.
+     *      beta. If input0 is of {@link OperandType::TENSOR_FLOAT32},
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} or
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, 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,
@@ -1647,6 +1694,8 @@
      * * 0: The output tensor of same shape as input0.
      *      For {@link OperandType::TENSOR_QUANT8_ASYMM},
      *      the scale must be 1.f / 256 and the zeroPoint must be 0.
+     *      For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      the scale must be 1.f / 256 and the zeroPoint must be -128.
      */
     SOFTMAX = @1.2::OperationType:SOFTMAX,
 
@@ -1668,6 +1717,7 @@
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
@@ -1688,7 +1738,8 @@
      * 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,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     SPACE_TO_DEPTH = @1.2::OperationType:SPACE_TO_DEPTH,
@@ -1812,6 +1863,7 @@
      * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
@@ -1830,7 +1882,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     BATCH_TO_SPACE_ND = @1.2::OperationType:BATCH_TO_SPACE_ND,
@@ -1925,6 +1978,7 @@
      * * {@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)
      *   (full support since HAL version 1.2, see the output section)
      *
      * Supported tensor rank: up to 4
@@ -1947,7 +2001,8 @@
      *      of the padding:
      *          output0.dimension[i] =
      *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      *
      *      NOTE: Before HAL version 1.2, the pad value for
@@ -1971,6 +2026,7 @@
      * * {@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)
      *   (full support since HAL version 1.2, see the output section)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
@@ -1998,7 +2054,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      *
      *      NOTE: Before HAL version 1.2, the pad value for
@@ -2151,6 +2208,7 @@
      * * {@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
      *
@@ -2162,7 +2220,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     TRANSPOSE = @1.2::OperationType:TRANSPOSE,
@@ -2192,6 +2251,7 @@
      * * {@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
      *
@@ -2216,6 +2276,7 @@
      * * {@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
      *
@@ -2257,7 +2318,8 @@
      *      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
+     *      of {@link OperandType::TENSOR_QUANT8_ASYMM} or
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}. 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
@@ -2612,6 +2674,7 @@
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Inputs:
      * * 0: A 2-D Tensor of shape [num_rois, num_classes], specifying the score
@@ -2623,7 +2686,11 @@
      *      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.
+     *      scale of 0.125.
+     *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM},
+     *      with zeroPoint of -128 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.
@@ -2650,6 +2717,8 @@
      *      [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},
+     *      guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      or {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
      *      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
@@ -2667,7 +2736,7 @@
     BOX_WITH_NMS_LIMIT = @1.2::OperationType:BOX_WITH_NMS_LIMIT,
 
     /**
-     * Casts a tensor to a new type.
+     * Casts a tensor to a type.
      *
      * This operation ignores the scale and zeroPoint of quanized tensors,
      * e.g. it treats a {@link OperandType::TENSOR_QUANT8_ASYMM} input
@@ -2678,6 +2747,14 @@
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_INT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * Since HAL version 1.3, casting tensors of the following
+     * {@link OperandType} to the same {@link OperandType} is supported:
+     * * {@link OperandType::TENSOR_BOOL8}
+     * * {@link OperandType::TENSOR_INT32}
+     * * {@link OperandType::TENSOR_QUANT16_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT16_SYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+     * * {@link OperandType::TENSOR_QUANT8_SYMM}
      *
      * Supported tensor rank: from 1
      *
@@ -2708,6 +2785,7 @@
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: up to 4
      *
@@ -2722,7 +2800,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} and same shape as input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     CHANNEL_SHUFFLE = @1.2::OperationType:CHANNEL_SHUFFLE,
@@ -2816,6 +2895,7 @@
      * * {@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
      *
@@ -2861,6 +2941,7 @@
      * * {@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
      *
@@ -2872,7 +2953,8 @@
      * Outputs:
      * * 0: An (n + 1)-D tensor with the same {@link OperandType} and data as
      *      input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     EXPAND_DIMS = @1.2::OperationType:EXPAND_DIMS,
@@ -2896,6 +2978,7 @@
      * * {@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
      *
@@ -2910,7 +2993,8 @@
      *
      * Outputs:
      * * 0: An (n + k - 1)-D tensor with the same {@link OperandType} as input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     GATHER = @1.2::OperationType:GATHER,
@@ -2931,6 +3015,7 @@
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Inputs:
      * * 0: A 4-D Tensor specifying the score of each anchor at each
@@ -2948,11 +3033,13 @@
      *      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_QUANT8_ASYMM} or
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, 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
+     *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM} or
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, this
      *      tensor should be of {@link OperandType::TENSOR_QUANT16_SYMM}, with
      *      scale of 0.125.
      * * 4: An {@link OperandType::FLOAT32} scalar, specifying the ratio
@@ -2979,7 +3066,8 @@
      *      [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
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} or
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, 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
@@ -3002,6 +3090,7 @@
      * * {@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
      *
@@ -3025,6 +3114,7 @@
      * * {@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
      *
@@ -3081,12 +3171,23 @@
      * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
      * * * input.scale * filter.scale).
      *
+     * * Quantized signed (since HAL version 1.3):
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} 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]).
      *
+     * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} 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
@@ -3105,8 +3206,9 @@
      *      {@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},
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
      *      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
@@ -3145,7 +3247,9 @@
      * * 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},
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
      *      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
@@ -3170,7 +3274,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth_out].
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      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.
      */
     GROUPED_CONV_2D = @1.2::OperationType:GROUPED_CONV_2D,
@@ -3190,6 +3295,7 @@
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
@@ -3206,13 +3312,18 @@
      *      {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should
      *      be of {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint
      *      of 0 and scale of 0.125.
+     *      For input0 of type
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, this tensor
+     *      should be of {@link OperandType::TENSOR_QUANT16_ASYMM}, with
+     *      zeroPoint of -128 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,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} or
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} 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
@@ -3283,6 +3394,7 @@
      * * {@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
      *
@@ -3307,6 +3419,7 @@
      * * {@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
      *
@@ -3434,6 +3547,7 @@
      * * {@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.
      *
@@ -3446,7 +3560,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      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.
      */
     MAXIMUM = @1.2::OperationType:MAXIMUM,
@@ -3459,6 +3574,7 @@
      * * {@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.
      *
@@ -3471,7 +3587,8 @@
      *
      * Outputs:
      * * 0: A tensor of the same {@link OperandType} as input0.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      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.
      */
     MINIMUM = @1.2::OperationType:MINIMUM,
@@ -3503,6 +3620,7 @@
      * * {@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
      *
@@ -3526,6 +3644,7 @@
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: up to 4
      *
@@ -3543,7 +3662,8 @@
      *      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},
+     *      For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
      *      the pad value must be of {@link OperandType::INT32}. The
      *      scale and zeroPoint are assumed to be the same as in input0.
      *
@@ -3555,7 +3675,8 @@
      *      of the padding:
      *          output0.dimension[i] =
      *              padding[i, 0] + input0.dimension[i] + padding[i, 1]
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     PAD_V2 = @1.2::OperationType:PAD_V2,
@@ -3614,6 +3735,7 @@
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: from 1
      *
@@ -3624,22 +3746,32 @@
      *
      * 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.
+     *      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.
      */
     PRELU = @1.2::OperationType:PRELU,
 
     /**
      * Quantizes the input tensor.
      *
-     * The formula is:
+     * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM} output tensor is:
      *
      *     output = max(0, min(255, round(input / scale) + zeroPoint)
      *
-     * Supported tensor {@link OperandType}:
+     * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} output
+     * tensor is:
+     *
+     *     output = max(-128, min(127, round(input / scale) + zeroPoint)
+     *
+     * Supported input tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      *
+     * Supported output tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     *
      * Supported tensor rank: from 1
      *
      * Inputs:
@@ -3647,7 +3779,8 @@
      *
      * Outputs:
      * * 0: The output tensor of same shape as input0, but with
-     *      {@link OperandType::TENSOR_QUANT8_ASYMM}.
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM} or.
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}.
      */
     QUANTIZE = @1.2::OperationType:QUANTIZE,
 
@@ -3955,6 +4088,7 @@
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
@@ -3993,7 +4127,8 @@
      * 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,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint can be different from the input0 scale and zeroPoint.
      */
     ROI_ALIGN = @1.2::OperationType:ROI_ALIGN,
@@ -4014,6 +4149,7 @@
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
@@ -4024,7 +4160,8 @@
      * * 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},
+     *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      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
@@ -4044,7 +4181,8 @@
      * 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,
+     *      For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     ROI_POOLING = @1.2::OperationType:ROI_POOLING,
@@ -4133,6 +4271,7 @@
      * * {@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
      *
@@ -4145,7 +4284,8 @@
      *
      * Outputs:
      * * 0: An n-D tensor of the same type as the input containing the slice.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      its scale and zeroPoint has to be same as the input0 scale and zeroPoint.
      */
     SLICE = @1.2::OperationType:SLICE,
@@ -4158,6 +4298,7 @@
      * * {@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
      *
@@ -4170,7 +4311,8 @@
      *
      * Outputs:
      * * 0 ~ (num_splits - 1): Resulting subtensors.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     SPLIT = @1.2::OperationType:SPLIT,
@@ -4206,6 +4348,7 @@
      * * {@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
      *
@@ -4216,7 +4359,8 @@
      *
      * Outputs:
      * * 0: A tiled tensor of the same {@link OperandType} and rank as `input`.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     TILE = @1.2::OperationType:TILE,
@@ -4232,6 +4376,7 @@
      * * {@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
      *
@@ -4243,7 +4388,8 @@
      * 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,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      * * 1: An n-D tensor of type {@link OperandType::TENSOR_INT32}
      *      containing the indices of values within the last dimension of input.
@@ -4278,6 +4424,18 @@
      * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
      * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
      *
+     * Available since HAL version 1.3:
+     * * Quantized signed (since HAL version 1.3):
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+     * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+     * * * input.scale * filter.scale).
+     *
+     * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+     * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} 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
@@ -4295,15 +4453,16 @@
      *      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].
+     *      {@link OperandType::TENSOR_FLOAT16}, the bias must be of the
+     *      same type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      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
@@ -4333,14 +4492,15 @@
      * * 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].
+     *      same type.
+     *      For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+     *      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
@@ -4359,7 +4519,8 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth_out].
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      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.
      */
     TRANSPOSE_CONV_2D = @1.2::OperationType:TRANSPOSE_CONV_2D,
@@ -4539,6 +4700,7 @@
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
      * With the default data layout NHWC, the data is stored in the order of:
@@ -4578,12 +4740,142 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, new_height, new_width, depth].
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint must be the same as input0.
      */
     RESIZE_NEAREST_NEIGHBOR = @1.2::OperationType:RESIZE_NEAREST_NEIGHBOR,
 
     /**
+     * Quantized version of {@link OperationType:LSTM}.
+     *
+     * The input and the output use asymmetric quantized types, while the rest
+     * use symmetric ones.
+     *
+     * Inputs:
+     * * 0: The input to the LSTM cell.
+     *      Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+     *      Shape: [batchSize, inputSize]
+     * * 1: The input-to-input weights. Optional.
+     *      Type: {@link OperandType::TENSOR_QUANT8_SYMM}
+     *      Shape: [numUnits, inputSize]
+     * * 2: The input-to-forget weights.
+     *      Type: {@link OperandType::TENSOR_QUANT8_SYMM}
+     *      Shape: [numUnits, inputSize]
+     * * 3: The input-to-cell weights.
+     *      Type: {@link OperandType::TENSOR_QUANT8_SYMM}
+     *      Shape: [numUnits, inputSize]
+     * * 4: The input-to-output weights.
+     *      Type: {@link OperandType::TENSOR_QUANT8_SYMM}
+     *      Shape: [numUnits, inputSize]
+     * * 5: The recurrent-to-input weights. Optional.
+     *      Type: {@link OperandType::TENSOR_QUANT8_SYMM}
+     *      Shape: [numUnits, outputSize]
+     * * 6: The recurrent-to-forget weights.
+     *      Type: {@link OperandType::TENSOR_QUANT8_SYMM}
+     *      Shape: [numUnits, outputSize]
+     * * 7: The recurrent-to-cell weights.
+     *      Type: {@link OperandType::TENSOR_QUANT8_SYMM}
+     *      Shape: [numUnits, outputSize]
+     * * 8: The recurrent-to-output weights.
+     *      Type: {@link OperandType::TENSOR_QUANT8_SYMM}
+     *      Shape: [numUnits, outputSize]
+     * * 9: The cell-to-input weights (for peephole). Optional.
+     *      Type: {@link OperandType::TENSOR_QUANT16_SYMM}
+     *      Shape: [numUnits]
+     * * 10: The cell-to-forget weights (for peephole). Optional.
+     *       Type: {@link OperandType::TENSOR_QUANT16_SYMM}
+     *       Shape: [numUnits]
+     * * 11: The cell-to-output weights (for peephole). Optional.
+     *       Type: {@link OperandType::TENSOR_QUANT16_SYMM}
+     *       Shape: [numUnits]
+     * * 12: The input gate bias. Quantized with scale being the
+     *       product of input and weights scales and zeroPoint equal to 0.
+     *       Optional.
+     *       Type: {@link OperandType::TENSOR_INT32}
+     *       Shape: [numUnits]
+     * * 13: The forget gate bias. Quantized with scale being the
+     *       product of input and weights scales and zeroPoint equal to 0.
+     *       Type: {@link OperandType::TENSOR_INT32}
+     *       Shape: [numUnits]
+     * * 14: The cell bias. Quantized with scale being the
+     *       product of input and weights scales and zeroPoint equal to 0.
+     *       Type: {@link OperandType::TENSOR_INT32}
+     *       Shape: [numUnits]
+     * * 15: The output gate bias. Quantized with scale being the
+     *       product of input and weights scales and zeroPoint equal to 0.
+     *       Type: {@link OperandType::TENSOR_INT32}
+     *       Shape: [numUnits]
+     * * 16: The projection weights. Optional.
+     *       Type: {@link OperandType::TENSOR_QUANT8_SYMM}
+     *       Shape: [outputSize, numUnits]
+     * * 17: The projection bias. Quantized with scale being the
+     *       product of input and weights scales and zeroPoint equal to 0.
+     *       Optional.
+     *       Type: {@link OperandType::TENSOR_INT32}
+     *       Shape: [outputSize]
+     * * 18: The output from the previous time step.
+     *       Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+     *       Shape: [batchSize, outputSize]
+     * * 19: The cell state from the previous time step.
+     *       Type: {@link OperandType::TENSOR_QUANT16_SYMM}
+     *       Shape: [batchSize, numUnits]
+     * * 20: The input layer normalization weights. Used to rescale
+     *       normalized inputs to activation at input gate. Optional.
+     *       Type: {@link OperandType::TENSOR_QUANT16_SYMM}
+     *       Shape: [numUnits]
+     * * 21: The forget layer normalization weights. Used to
+     *       rescale normalized inputs to activation at forget gate. Optional.
+     *       Type: {@link OperandType::TENSOR_QUANT16_SYMM}
+     *       Shape: [numUnits]
+     * * 22: The cell layer normalization weights. Used to rescale
+     *       normalized inputs to activation at cell gate. Optional.
+     *       Type: {@link OperandType::TENSOR_QUANT16_SYMM}
+     *       Shape: [numUnits]
+     * * 23: The output layer normalization weights. Used to
+     *       rescale normalized inputs to activation at output gate. Optional.
+     *       Type: {@link OperandType::TENSOR_QUANT16_SYMM}
+     *       Shape: [numUnits]
+     * * 24: The cell clip. If provided the cell state is clipped
+     *       by this value prior to the cell output activation. Optional.
+     *       Type: {@link OperandType::FLOAT32}.
+     * * 25: The projection clip. If provided and projection is enabled,
+     *       this is used for clipping the projected values. Optional.
+     *       Type: {@link OperandType::FLOAT32}.
+     * * 26: The scale of the intermediate result of matmul,
+     *       i.e. input to layer normalization, at input gate.
+     *       Type: {@link OperandType::FLOAT32}.
+     * * 27: The scale of the intermediate result of matmul,
+     *       i.e. input to layer normalization, at forget gate.
+     *       Type: {@link OperandType::FLOAT32}.
+     * * 28: The scale of the intermediate result of matmul,
+     *       i.e. input to layer normalization, at cell gate.
+     *       Type: {@link OperandType::FLOAT32}.
+     * * 29: The scale of the intermediate result of matmul,
+     *       i.e. input to layer normalization, at output gate.
+     *       Type: {@link OperandType::FLOAT32}.
+     * * 30: The zero point of the hidden state, i.e. input to
+     *       projection.
+     *       Type: {@link OperandType::INT32}.
+     * * 31: The scale of the hidden state, i.e. input to
+     *       projection.
+     *       Type: {@link OperandType::FLOAT32}.
+     *
+     * Outputs:
+     * * 0: The output state (out).
+     *      Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+     *      Shape: [batchSize, outputSize]
+     * * 1: The cell state (out).
+     *      Type: {@link OperandType::TENSOR_QUANT16_SYMM}
+     *      Shape: [batchSize, numUnits]
+     * * 2: The output. This is effectively the same as the current
+     *      "output state (out)" value.
+     *      Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+     *      Shape: [batchSize, outputSize]
+     */
+    QUANTIZED_LSTM = 95,
+
+    /**
      * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
      * OEM operation and data types.
      *
@@ -4605,7 +4897,7 @@
 enum OperationTypeRange : uint32_t {
     BASE_MIN        = 0,
     FUNDAMENTAL_MIN = 0,
-    FUNDAMENTAL_MAX = 94,
+    FUNDAMENTAL_MAX = 95,
     OEM_MIN         = 10000,
     OEM_MAX         = 10000,
     BASE_MAX        = 0xFFFF,
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index be894f2..eced063 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -452,7 +452,7 @@
             EvaluatePreparedModel(preparedModel, testModel, TestKind::DYNAMIC_SHAPE);
         } break;
         case TestKind::QUANTIZATION_COUPLING: {
-            ASSERT_TRUE(testModel.hasQuant8AsymmOperands());
+            ASSERT_TRUE(testModel.hasQuant8CoupledOperands());
             createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ false);
             TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel);
             sp<IPreparedModel> preparedCoupledModel;
@@ -500,7 +500,7 @@
 class DynamicOutputShapeTest : public GeneratedTest {};
 
 // Tag for the dynamic output shape tests
-class DISABLED_QuantizationCouplingTest : public GeneratedTest {};
+class QuantizationCouplingTest : public GeneratedTest {};
 
 TEST_P(GeneratedTest, Test) {
     Execute(kDevice, kTestModel, /*testKind=*/TestKind::GENERAL);
@@ -510,7 +510,7 @@
     Execute(kDevice, kTestModel, /*testKind=*/TestKind::DYNAMIC_SHAPE);
 }
 
-TEST_P(DISABLED_QuantizationCouplingTest, Test) {
+TEST_P(QuantizationCouplingTest, Test) {
     Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING);
 }
 
@@ -520,8 +520,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;
+INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) {
+    return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1;
 });
 
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 65880b7..8395111 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::OperationTypeRange;
 using V1_2::SymmPerChannelQuantParams;
 using HidlToken =
         hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
@@ -330,6 +329,8 @@
         // - DEPTHWISE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
         // - GROUPED_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
         // - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
+        // - AXIS_ALIGNED_BBOX_TRANSFORM bounding boxes (arg 1) can be of
+        //     TENSOR_QUANT8_ASYMM or TENSOR_QUANT8_ASYMM_SIGNED.
         switch (operation.type) {
             case OperationType::LSH_PROJECTION: {
                 if (operand == operation.inputs[1]) {
@@ -385,6 +386,13 @@
                     return true;
                 }
             } break;
+            case OperationType::AXIS_ALIGNED_BBOX_TRANSFORM: {
+                if (operand == operation.inputs[1] &&
+                    (type == OperandType::TENSOR_QUANT8_ASYMM ||
+                     type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)) {
+                    return true;
+                }
+            } break;
             default:
                 break;
         }
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index fafc6e2..d0c5b0d 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -21,6 +21,7 @@
 import @1.4::DataProfileInfo;
 import @1.5::AccessNetwork;
 import @1.5::DataProfileInfo;
+import @1.5::IndicationFilter;
 import @1.5::LinkAddress;
 import @1.5::NetworkScanRequest;
 import @1.5::RadioAccessSpecifier;
@@ -219,4 +220,19 @@
      */
     oneway setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
             bool preferredForEmergencyCall);
+
+    /**
+     * Sets the indication filter.
+     *
+     * Prevents the reporting of specified unsolicited indications from the radio. This is used
+     * for power saving in instances when those indications are not needed. If unset, defaults to
+     * @1.2::IndicationFilter:ALL.
+     *
+     * @param serial Serial number of request.
+     * @param indicationFilter 32-bit bitmap of IndicationFilter. Bits set to 1 indicate the
+     *     indications are enabled. See @1.5::IndicationFilter for the definition of each bit.
+     *
+     * Response callback is IRadioResponse.setIndicationFilterResponse()
+     */
+    oneway setIndicationFilter_1_5(int32_t serial, bitfield<IndicationFilter> indicationFilter);
 };
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index 968948b..f1b7e71 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -145,4 +145,16 @@
      *   RadioError:INVALID_ARGUMENTS
      */
     oneway setRadioPowerResponse_1_5(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:SYSTEM_ERR
+     */
+    oneway setIndicationFilterResponse_1_5(RadioResponseInfo info);
 };
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 7d6ec41..12c27d0 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -27,6 +27,7 @@
 import @1.2::CellIdentityWcdma;
 import @1.2::CellIdentityTdscdma;
 import @1.2::CellIdentityLte;
+import @1.2::IndicationFilter;
 import @1.2::NetworkScanRequest;
 import @1.4::AccessNetwork;
 import @1.4::ApnTypes;
@@ -424,3 +425,8 @@
     CellIdentityLte lte;
     CellIdentityNr nr;
 };
+
+enum IndicationFilter : @1.2::IndicationFilter {
+    /** Control the unsolicited sending of registration failure reports via onRegistrationFailed */
+    REGISTRATION_FAILURE = 1 << 5,
+};
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 49a315d..c3c9f54 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
@@ -551,6 +551,8 @@
     Return<void> setDataProfileResponse_1_5(const RadioResponseInfo& info);
 
     Return<void> setRadioPowerResponse_1_5(const RadioResponseInfo& info);
+
+    Return<void> setIndicationFilterResponse_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 a0b3d5f..877945f 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -953,4 +953,10 @@
     rspInfo = info;
     parent_v1_5.notify(info.serial);
     return Void();
-}
\ No newline at end of file
+}
+
+Return<void> RadioResponse_v1_5::setIndicationFilterResponse_1_5(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp
index 7bc8d6f..0742939 100644
--- a/rebootescrow/aidl/Android.bp
+++ b/rebootescrow/aidl/Android.bp
@@ -1,5 +1,5 @@
 aidl_interface {
-    name: "vintf-rebootescrow",
+    name: "android.hardware.rebootescrow",
     vendor_available: true,
     srcs: [
         "android/hardware/rebootescrow/IRebootEscrow.aidl",
diff --git a/rebootescrow/aidl/default/Android.bp b/rebootescrow/aidl/default/Android.bp
index c8cbf48..b77272f 100644
--- a/rebootescrow/aidl/default/Android.bp
+++ b/rebootescrow/aidl/default/Android.bp
@@ -20,7 +20,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "vintf-rebootescrow-ndk_platform",
+        "android.hardware.rebootescrow-ndk_platform",
     ],
     export_include_dirs: ["include"],
     srcs: [
@@ -47,7 +47,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "vintf-rebootescrow-ndk_platform",
+        "android.hardware.rebootescrow-ndk_platform",
     ],
     static_libs: [
         "libhadamardutils",
diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp
index 8ee77e1..d2422b9 100644
--- a/rebootescrow/aidl/default/HadamardUtils.cpp
+++ b/rebootescrow/aidl/default/HadamardUtils.cpp
@@ -26,14 +26,18 @@
 namespace rebootescrow {
 namespace hadamard {
 
-static inline void or_bit(std::vector<uint8_t>* input, size_t bit, uint8_t val) {
-    (*input)[bit >> 3] |= (val & 1u) << (bit & 7);
-}
-
 static inline uint8_t read_bit(const std::vector<uint8_t>& input, size_t bit) {
     return (input[bit >> 3] >> (bit & 7)) & 1u;
 }
 
+// Use a simple LCG which is easy to run in reverse.
+// https://www.johndcook.com/blog/2017/07/05/simple-random-number-generator/
+constexpr uint64_t RNG_MODULUS = 0x7fffffff;
+constexpr uint64_t RNG_MUL = 742938285;
+constexpr uint64_t RNG_SEED = 20170705;
+constexpr uint64_t RNG_INV_MUL = 1413043504;   // (mul * inv_mul) % modulus == 1
+constexpr uint64_t RNG_INV_SEED = 1173538311;  // (seed * mul**65534) % modulus
+
 // Apply an error correcting encoding.
 //
 // The error correcting code used is an augmented Hadamard code with
@@ -45,21 +49,45 @@
 // codewords. Thus if a single 512-byte DRAM line is lost, instead of losing
 // 2^11 bits from the encoding of a single code word, we lose 2^7 bits
 // from the encoding of each of the 16 codewords.
+// In addition we apply a Fisher-Yates shuffle to the bytes of the encoding;
+// Hadamard encoding recovers much better from random errors than systematic
+// ones, and this ensures that errors will be random.
 std::vector<uint8_t> EncodeKey(const std::vector<uint8_t>& input) {
     CHECK_EQ(input.size(), KEY_SIZE_IN_BYTES);
     std::vector<uint8_t> result(OUTPUT_SIZE_BYTES, 0);
     static_assert(OUTPUT_SIZE_BYTES == 64 * 1024);
-    for (size_t i = 0; i < KEY_CODEWORDS; i++) {
-        uint16_t word = input[i * 2 + 1] << 8 | input[i * 2];
-        for (size_t j = 0; j < ENCODE_LENGTH; j++) {
-            uint16_t wi = word & (j + ENCODE_LENGTH);
-            // Sum all the bits in the word and check its parity.
-            wi ^= wi >> 8u;
-            wi ^= wi >> 4u;
-            wi ^= wi >> 2u;
-            wi ^= wi >> 1u;
-            or_bit(&result, (j * KEY_CODEWORDS) + i, wi & 1);
+    // Transpose the key so that each row contains one bit from each codeword
+    uint16_t wordmatrix[CODEWORD_BITS];
+    for (size_t i = 0; i < CODEWORD_BITS; i++) {
+        uint16_t word = 0;
+        for (size_t j = 0; j < KEY_CODEWORDS; j++) {
+            word |= read_bit(input, i + j * CODEWORD_BITS) << j;
         }
+        wordmatrix[i] = word;
+    }
+    // Fill in the encodings in Gray code order for speed.
+    uint16_t val = wordmatrix[CODEWORD_BITS - 1];
+    size_t ix = 0;
+    for (size_t i = 0; i < ENCODE_LENGTH; i++) {
+        for (size_t b = 0; b < CODEWORD_BITS; b++) {
+            if (i & (1 << b)) {
+                ix ^= (1 << b);
+                val ^= wordmatrix[b];
+                break;
+            }
+        }
+        result[ix * KEY_CODEWORD_BYTES] = val & 0xffu;
+        result[ix * KEY_CODEWORD_BYTES + 1] = val >> 8u;
+    }
+    // Apply the inverse shuffle here; we apply the forward shuffle in decoding.
+    uint64_t rng_state = RNG_INV_SEED;
+    for (size_t i = OUTPUT_SIZE_BYTES - 1; i > 0; i--) {
+        auto j = rng_state % (i + 1);
+        auto t = result[i];
+        result[i] = result[j];
+        result[j] = t;
+        rng_state *= RNG_INV_MUL;
+        rng_state %= RNG_MODULUS;
     }
     return result;
 }
@@ -106,8 +134,19 @@
     return winner;
 }
 
-std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& encoded) {
-    CHECK_EQ(OUTPUT_SIZE_BYTES, encoded.size());
+std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& shuffled) {
+    CHECK_EQ(OUTPUT_SIZE_BYTES, shuffled.size());
+    // Apply the forward Fisher-Yates shuffle.
+    std::vector<uint8_t> encoded(OUTPUT_SIZE_BYTES, 0);
+    encoded[0] = shuffled[0];
+    uint64_t rng_state = RNG_SEED;
+    for (size_t i = 1; i < OUTPUT_SIZE_BYTES; i++) {
+        auto j = rng_state % (i + 1);
+        encoded[i] = encoded[j];
+        encoded[j] = shuffled[i];
+        rng_state *= RNG_MUL;
+        rng_state %= RNG_MODULUS;
+    }
     std::vector<uint8_t> result(KEY_SIZE_IN_BYTES, 0);
     for (size_t i = 0; i < KEY_CODEWORDS; i++) {
         uint16_t val = DecodeWord(i, encoded);
diff --git a/rebootescrow/aidl/default/HadamardUtils.h b/rebootescrow/aidl/default/HadamardUtils.h
index 85e635f..e04f7d5 100644
--- a/rebootescrow/aidl/default/HadamardUtils.h
+++ b/rebootescrow/aidl/default/HadamardUtils.h
@@ -31,9 +31,10 @@
 constexpr auto CODEWORD_BITS = CODEWORD_BYTES * BYTE_LENGTH;
 constexpr uint32_t CODE_K = CODEWORD_BITS - 1;
 constexpr uint32_t ENCODE_LENGTH = 1u << CODE_K;
-constexpr auto KEY_CODEWORDS = 16u;
+constexpr auto KEY_CODEWORD_BYTES = 2u;  // uint16_t (after transpose)
+constexpr auto KEY_CODEWORDS = KEY_CODEWORD_BYTES * BYTE_LENGTH;
 constexpr auto KEY_SIZE_IN_BYTES = KEY_CODEWORDS * CODEWORD_BYTES;
-constexpr auto OUTPUT_SIZE_BYTES = KEY_CODEWORDS * ENCODE_LENGTH / BYTE_LENGTH;
+constexpr auto OUTPUT_SIZE_BYTES = ENCODE_LENGTH * KEY_CODEWORD_BYTES;
 
 // Encodes a key that has a size of KEY_SIZE_IN_BYTES. Returns a byte array representation of the
 // encoded bitset. So a 32 bytes key will expand to 16*(2^15) bits = 64KiB.
diff --git a/rebootescrow/aidl/default/OWNERS b/rebootescrow/aidl/default/OWNERS
new file mode 100644
index 0000000..c5288d6
--- /dev/null
+++ b/rebootescrow/aidl/default/OWNERS
@@ -0,0 +1,2 @@
+kroot@google.com
+paulcrowley@google.com
diff --git a/rebootescrow/aidl/vts/OWNERS b/rebootescrow/aidl/vts/OWNERS
new file mode 100644
index 0000000..c5288d6
--- /dev/null
+++ b/rebootescrow/aidl/vts/OWNERS
@@ -0,0 +1,2 @@
+kroot@google.com
+paulcrowley@google.com
diff --git a/rebootescrow/aidl/vts/functional/Android.bp b/rebootescrow/aidl/vts/functional/Android.bp
index dadf250..5d51a53 100644
--- a/rebootescrow/aidl/vts/functional/Android.bp
+++ b/rebootescrow/aidl/vts/functional/Android.bp
@@ -25,7 +25,7 @@
         "libbinder",
     ],
     static_libs: [
-        "vintf-rebootescrow-cpp",
+        "android.hardware.rebootescrow-cpp",
     ],
     test_suites: [
         "vts-core",
diff --git a/soundtrigger/2.3/ISoundTriggerHw.hal b/soundtrigger/2.3/ISoundTriggerHw.hal
index 207b9b7..23aa36e 100644
--- a/soundtrigger/2.3/ISoundTriggerHw.hal
+++ b/soundtrigger/2.3/ISoundTriggerHw.hal
@@ -26,6 +26,18 @@
 interface ISoundTriggerHw extends @2.2::ISoundTriggerHw {
 
     /**
+     * Retrieve extended implementation properties.
+     * The returned properties includes what is returned from the
+     * getProperties along with expanded implementation details.
+     *
+     * @return retval Operation completion status: 0 in case of success,
+     *                -ENODEV in case of initialization error.
+     * @return properties A Properties structure containing implementation
+     *                    description and capabilities.
+     */
+    getProperties_2_3() generates (int32_t retval, Properties properties);
+
+    /**
      * Set a model specific parameter with the given value. This parameter
      * will keep its value for the duration the model is loaded regardless of starting and stopping
      * recognition. Once the model is unloaded, the value will be lost.
diff --git a/soundtrigger/2.3/default/SoundTriggerHw.cpp b/soundtrigger/2.3/default/SoundTriggerHw.cpp
index 4a39ab5..9fd8fe0 100644
--- a/soundtrigger/2.3/default/SoundTriggerHw.cpp
+++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp
@@ -89,7 +89,7 @@
     ALOGV("getProperties() mHwDevice %p", mHwDevice);
     int ret;
     struct sound_trigger_properties halProperties;
-    ISoundTriggerHw::Properties properties;
+    V2_0::ISoundTriggerHw::Properties properties;
 
     if (mHwDevice == NULL) {
         ret = -ENODEV;
@@ -333,7 +333,7 @@
 }
 
 void SoundTriggerHw::convertPropertiesFromHal(
-        ISoundTriggerHw::Properties* properties,
+        V2_0::ISoundTriggerHw::Properties* properties,
         const struct sound_trigger_properties* halProperties) {
     properties->implementor = halProperties->implementor;
     properties->description = halProperties->description;
@@ -350,6 +350,16 @@
     properties->powerConsumptionMw = halProperties->power_consumption_mw;
 }
 
+void SoundTriggerHw::convertPropertiesFromHal(
+        V2_3::Properties* properties, const struct sound_trigger_properties_header* header) {
+    if (header->version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_3) {
+        const struct sound_trigger_properties_extended_1_3* halProperties =
+                (const struct sound_trigger_properties_extended_1_3*)header;
+        convertPropertiesFromHal(&properties->base, &halProperties->base);
+        properties->supportedModelArch = halProperties->supported_model_arch;
+    }
+}
+
 void SoundTriggerHw::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
                                                const ISoundTriggerHw::Phrase* triggerPhrase) {
     halTriggerPhrase->id = triggerPhrase->id;
@@ -708,6 +718,29 @@
 
 // Begin V2_3 implementation
 
+Return<void> SoundTriggerHw::getProperties_2_3(ISoundTriggerHw::getProperties_2_3_cb _hidl_cb) {
+    ALOGV("getProperties_2_3() mHwDevice %p", mHwDevice);
+    int ret = 0;
+    V2_3::Properties properties;
+    const struct sound_trigger_properties_header* header;
+
+    if (mHwDevice == NULL) {
+        ret = -ENODEV;
+        goto exit;
+    }
+
+    header = mHwDevice->get_properties_extended(mHwDevice);
+
+    convertPropertiesFromHal(&properties, header);
+
+    ALOGV("getProperties_2_3 implementor %s supportedModelArch %s",
+          properties.base.implementor.c_str(), properties.supportedModelArch.c_str());
+
+exit:
+    _hidl_cb(ret, properties);
+    return Void();
+}
+
 Return<int32_t> SoundTriggerHw::setParameter(V2_0::SoundModelHandle modelHandle,
                                              ModelParameter modelParam, int32_t value) {
     sp<SoundModelClient> client;
diff --git a/soundtrigger/2.3/default/SoundTriggerHw.h b/soundtrigger/2.3/default/SoundTriggerHw.h
index c82c9ea..078debb 100644
--- a/soundtrigger/2.3/default/SoundTriggerHw.h
+++ b/soundtrigger/2.3/default/SoundTriggerHw.h
@@ -85,6 +85,7 @@
     Return<int32_t> getModelState(int32_t modelHandle) override;
 
     // Methods from V2_3::ISoundTriggerHw follow.
+    Return<void> getProperties_2_3(getProperties_2_3_cb _hidl_cb) override;
     Return<int32_t> setParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam,
                                  int32_t value) override;
     Return<void> getParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam,
@@ -156,6 +157,8 @@
     void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid);
     void convertPropertiesFromHal(V2_0::ISoundTriggerHw::Properties* properties,
                                   const struct sound_trigger_properties* halProperties);
+    void convertPropertiesFromHal(V2_3::Properties* properties,
+                                  const struct sound_trigger_properties_header* header);
     static sound_trigger_model_parameter_t convertModelParameterToHal(ModelParameter param);
     void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
                                    const V2_0::ISoundTriggerHw::Phrase* triggerPhrase);
diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal
index c3a522b..6149126 100644
--- a/soundtrigger/2.3/types.hal
+++ b/soundtrigger/2.3/types.hal
@@ -17,6 +17,21 @@
 package android.hardware.soundtrigger@2.3;
 
 import android.hidl.safe_union@1.0::Monostate;
+import @2.0::ISoundTriggerHw.Properties;
+
+/**
+ * Extended implementation properties providing verbose implementation
+ * details.
+ */
+struct Properties {
+    @2.0::ISoundTriggerHw.Properties base;
+
+    /**
+     * String naming the architecture used for running the supported models.
+     * (eg. DSP architecture)
+     */
+    string supportedModelArch;
+};
 
 /**
  * Model specific parameters to be used with parameter set and get APIs
diff --git a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
index 202eb6c..ed38368 100644
--- a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
+++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
@@ -26,7 +26,9 @@
 
 using ::android::sp;
 using ::android::hardware::Return;
+using ::android::hardware::soundtrigger::V2_0::RecognitionMode;
 using ::android::hardware::soundtrigger::V2_3::ISoundTriggerHw;
+using ::android::hardware::soundtrigger::V2_3::Properties;
 
 /**
  * Test class holding the instance of the SoundTriggerHW service to test.
@@ -53,6 +55,32 @@
  */
 TEST_P(SoundTriggerHidlTest, ServiceIsInstantiated) {}
 
+/**
+ * Test ISoundTriggerHw::getProperties_2_3 method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the method returns no error
+ * - the implementation supports at least one sound model and one key phrase
+ * - the implementation supports at least VOICE_TRIGGER recognition mode
+ */
+TEST_P(SoundTriggerHidlTest, GetProperties_2_3) {
+    Properties halProperties;
+    Return<void> hidlReturn;
+    int ret = -ENODEV;
+
+    hidlReturn = soundtrigger->getProperties_2_3([&](int rc, auto res) {
+        ret = rc;
+        halProperties = res;
+    });
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_EQ(0, ret);
+    EXPECT_GT(halProperties.base.maxSoundModels, 0u);
+    EXPECT_GT(halProperties.base.maxKeyPhrases, 0u);
+    EXPECT_NE(0u, (halProperties.base.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER));
+}
+
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, SoundTriggerHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp
index ef9b39b..42e0a92 100644
--- a/tests/extension/vibrator/aidl/Android.bp
+++ b/tests/extension/vibrator/aidl/Android.bp
@@ -1,7 +1,7 @@
 aidl_interface {
     // This is an example test interface showing how to add functionality
     // with setExtension/getExtension
-    name: "test-vintf-vibrator-ext",
+    name: "test-android.hardware.vibrator-ext",
     vendor_available: true,
     srcs: [
         // Using android.hardware as the package because this is in
@@ -18,7 +18,7 @@
     // This happens to use types from a core interface, so we import it, but
     // this won't always be needed.
     imports: [
-        "vintf-vibrator",
+        "android.hardware.vibrator",
     ],
 
     backend: {
diff --git a/tests/extension/vibrator/aidl/client/Android.bp b/tests/extension/vibrator/aidl/client/Android.bp
index f7b71f7..c707dbe 100644
--- a/tests/extension/vibrator/aidl/client/Android.bp
+++ b/tests/extension/vibrator/aidl/client/Android.bp
@@ -1,26 +1,24 @@
-
 // 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",
+    name: "test-android.hardware.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",
+        // 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",
+        "libutils",
+        "android.hardware.vibrator-cpp",
+        "test-android.hardware.vibrator-ext-cpp",
 
-         "libbinder_ndk",
-         "vintf-vibrator-ndk_platform",
-         "test-vintf-vibrator-ext-ndk_platform",
+        "libbinder_ndk",
+        "android.hardware.vibrator-ndk_platform",
+        "test-android.hardware.vibrator-ext-ndk_platform",
     ],
 }
-
diff --git a/tests/extension/vibrator/aidl/default/Android.bp b/tests/extension/vibrator/aidl/default/Android.bp
index 9869657..7c8fe1f 100644
--- a/tests/extension/vibrator/aidl/default/Android.bp
+++ b/tests/extension/vibrator/aidl/default/Android.bp
@@ -19,7 +19,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "vintf-vibrator-ndk_platform",
-        "test-vintf-vibrator-ext-ndk_platform",
+        "android.hardware.vibrator-ndk_platform",
+        "test-android.hardware.vibrator-ext-ndk_platform",
     ],
 }
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index fa3c08b..d39439d 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -1307,18 +1307,15 @@
 @export
 enum FrontendEventType : uint32_t {
     /**
-     * If frontend locked the signal which is specified by tune method, HAL sends
-     * Locked event.
+     * The frontend has locked to the signal specified by the tune method.
      */
     LOCKED,
     /**
-     * If frontend can't locked the signal which is specified by tune method,
-     * HAL sends NO_SIGNAL event.
+     * The frontend is unable to lock to the signal specified by the tune method.
      */
     NO_SIGNAL,
     /**
-     * If frontend detect that the locked signal get lost, HAL sends LOST_LOCK
-     * event.
+     * The frontend has lost the lock to the signal specified by the tune method.
      */
     LOST_LOCK,
 };
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index 1eec1da..ae7f434 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -1,5 +1,5 @@
 aidl_interface {
-    name: "vintf-vibrator",
+    name: "android.hardware.vibrator",
     vendor_available: true,
     srcs: [
         "android/hardware/vibrator/*.aidl",
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index dc8867f..9e6d9cf 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -4,13 +4,13 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "vintf-vibrator-ndk_platform",
+        "android.hardware.vibrator-ndk_platform",
     ],
     export_include_dirs: ["include"],
     srcs: ["Vibrator.cpp"],
     visibility: [
-         ":__subpackages__",
-         "//hardware/interfaces/tests/extension/vibrator:__subpackages__",
+        ":__subpackages__",
+        "//hardware/interfaces/tests/extension/vibrator:__subpackages__",
     ],
 }
 
@@ -23,7 +23,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "vintf-vibrator-ndk_platform",
+        "android.hardware.vibrator-ndk_platform",
     ],
     static_libs: [
         "libvibratorexampleimpl",
diff --git a/vibrator/aidl/vts/Android.bp b/vibrator/aidl/vts/Android.bp
index 20d53c7..a01e432 100644
--- a/vibrator/aidl/vts/Android.bp
+++ b/vibrator/aidl/vts/Android.bp
@@ -9,7 +9,7 @@
         "libbinder",
     ],
     static_libs: [
-        "vintf-vibrator-cpp",
+        "android.hardware.vibrator-cpp",
     ],
     test_suites: [
         "vts-core",
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 8be8a0c..3599b94 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
@@ -38,6 +38,9 @@
 class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_ap_iface_ = getWifiApIface(GetInstanceName());
         ASSERT_NE(nullptr, wifi_ap_iface_.get());
     }
@@ -95,4 +98,4 @@
     PerInstance, WifiApIfaceHidlTest,
     testing::ValuesIn(
         android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
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 33817d5..5a2c6a7 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
@@ -41,6 +41,9 @@
 class WifiChipHidlApTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_chip_ = getWifiChip(GetInstanceName());
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
@@ -177,4 +180,4 @@
     PerInstance, WifiChipHidlApTest,
     testing::ValuesIn(
         android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
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 95f223d..c95f4d2 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
@@ -41,6 +41,9 @@
 class WifiChipHidlNanTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_chip_ = getWifiChip(GetInstanceName());
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
@@ -178,4 +181,4 @@
     PerInstance, WifiChipHidlNanTest,
     testing::ValuesIn(
         android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
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 62874ef..f332001 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -73,6 +73,9 @@
 class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_chip_ = getWifiChip(GetInstanceName());
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
index 512701a..f3c82da 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
@@ -32,7 +32,10 @@
  */
 class WifiHidlTest : public ::testing::TestWithParam<std::string> {
    public:
-    virtual void SetUp() override {}
+    virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+    }
 
     virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
@@ -53,4 +56,4 @@
     PerInstance, WifiHidlTest,
     testing::ValuesIn(
         android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
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 422e3f6..47a1938 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
@@ -44,6 +44,9 @@
 class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
         iwifiNanIface = getWifiNanIface(GetInstanceName());
         ASSERT_NE(nullptr, iwifiNanIface.get());
         ASSERT_EQ(WifiStatusCode::SUCCESS,
@@ -506,4 +509,4 @@
     PerInstance, WifiNanIfaceHidlTest,
     testing::ValuesIn(
         android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
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 8f33271..fd175f5 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
@@ -33,7 +33,10 @@
  */
 class WifiP2pIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
-    virtual void SetUp() override {}
+    virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+    }
 
     virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
@@ -55,4 +58,4 @@
     PerInstance, WifiP2pIfaceHidlTest,
     testing::ValuesIn(
         android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
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 6c01995..1eb9c99 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
@@ -37,7 +37,10 @@
  */
 class WifiRttControllerHidlTest : public ::testing::TestWithParam<std::string> {
    public:
-    virtual void SetUp() override {}
+    virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+    }
 
     virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
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 30b6fba..7db0526 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
@@ -47,6 +47,9 @@
 class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_sta_iface_ = getWifiStaIface(GetInstanceName());
         ASSERT_NE(nullptr, wifi_sta_iface_.get());
     }
@@ -299,4 +302,4 @@
     PerInstance, WifiStaIfaceHidlTest,
     testing::ValuesIn(
         android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
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 08de240..4b94acb 100644
--- a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
@@ -49,6 +49,9 @@
 class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
@@ -115,4 +118,4 @@
     PerInstance, WifiChipHidlTest,
     testing::ValuesIn(
         android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
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 93aa0f3..b04acad 100644
--- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
@@ -55,8 +55,11 @@
 class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-    wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
-    ASSERT_NE(nullptr, wifi_chip_.get());
+      // Make sure test starts with a clean state
+      stopWifi(GetInstanceName());
+
+      wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
+      ASSERT_NE(nullptr, wifi_chip_.get());
   }
 
   virtual void TearDown() override { stopWifi(GetInstanceName()); }
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 d5d87ce..6e55664 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
@@ -50,6 +50,9 @@
 class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
         iwifiNanIface = getWifiNanIface_1_2(GetInstanceName());
         ASSERT_NE(nullptr, iwifiNanIface.get());
         ASSERT_EQ(WifiStatusCode::SUCCESS,
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 1b907b2..066dcaa 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
@@ -39,6 +39,9 @@
 class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_sta_iface_ =
             IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_sta_iface_.get());
@@ -118,4 +121,4 @@
     PerInstance, WifiStaIfaceHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
         ::android::hardware::wifi::V1_2::IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
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 db93967..e99b34a 100644
--- a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
@@ -44,6 +44,9 @@
 class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
@@ -126,4 +129,4 @@
     PerInstance, WifiChipHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
         ::android::hardware::wifi::V1_3::IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
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 c5acc3c..41d4ebb 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
@@ -40,6 +40,9 @@
 class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_sta_iface_ =
             IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_sta_iface_.get());
@@ -105,4 +108,4 @@
     PerInstance, WifiStaIfaceHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
         ::android::hardware::wifi::V1_3::IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
index ae3c447..6f088d7 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -824,6 +824,13 @@
                                                     mode);
 }
 
+wifi_error WifiLegacyHal::setThermalMitigationMode(
+    const std::string& iface_name, wifi_thermal_mode mode,
+    uint32_t completion_window) {
+    return global_func_table_.wifi_set_thermal_mitigation_mode(
+        getIfaceHandle(iface_name), mode, completion_window);
+}
+
 std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
     const std::string& iface_name) {
     uint32_t supported_feature_flags;
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h
index 7f16c30..74cc84b 100644
--- a/wifi/1.4/default/wifi_legacy_hal.h
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -259,6 +259,9 @@
     virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
     wifi_error setLatencyMode(const std::string& iface_name,
                               wifi_latency_mode mode);
+    wifi_error setThermalMitigationMode(const std::string& iface_name,
+                                        wifi_thermal_mode mode,
+                                        uint32_t completion_window);
     // Logger/debug functions.
     std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(
         const std::string& iface_name);
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
index 27afa1f..bbe470e 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
@@ -138,6 +138,7 @@
     populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
     populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
     populateStubFor(&hal_fn->wifi_set_latency_mode);
+    populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
     return true;
 }
 }  // namespace legacy_hal
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 017ecb6..3507d30 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
@@ -38,6 +38,9 @@
 class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_ap_iface_ =
             IWifiApIface::castFrom(getWifiApIface(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_ap_iface_.get());
@@ -80,4 +83,4 @@
     PerInstance, WifiApIfaceHidlTest,
     testing::ValuesIn(
         android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
-    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
index 8ca5214..7896067 100644
--- a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
@@ -47,6 +47,9 @@
 class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
         wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
diff --git a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
index 245e906..688faf1 100644
--- a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -51,6 +51,9 @@
 class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
         iwifiNanIface = getWifiNanIface_1_4(GetInstanceName());
         ASSERT_NE(nullptr, iwifiNanIface.get());
         ASSERT_EQ(WifiStatusCode::SUCCESS,
diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal
index 1bac1e7..5e6d80a 100644
--- a/wifi/hostapd/1.2/IHostapd.hal
+++ b/wifi/hostapd/1.2/IHostapd.hal
@@ -21,6 +21,7 @@
 import HostapdStatus;
 import MacAddress;
 import Ieee80211ReasonCode;
+import DebugLevel;
 
 /**
  * Top-level object for managing SoftAPs.
@@ -56,12 +57,58 @@
          * used with HE.
          */
         bool enable80211AX;
+
         /**
          * Whether 6GHz band enabled or not on softAp.
          * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
          * used.
          */
         bool enable6GhzBand;
+
+        /**
+         * Whether HE single user beamformer in enabled or not on softAp.
+         * Note: this is only applicable if 802.11ax is supported for softAp
+         */
+        bool enableHeSingleUserBeamformer;
+
+        /**
+         * Whether HE single user beamformee is enabled or not on softAp.
+         * Note: this is only applicable if 802.11ax is supported for softAp
+         */
+        bool enableHeSingleUserBeamformee;
+
+        /**
+         * Whether HE multiple user beamformer is enabled or not on softAp.
+         * Note: this is only applicable if 802.11ax is supported for softAp
+         */
+        bool enableHeMultiUserBeamformer;
+
+        /**
+         * Used BSS Color for softAp running in 802.11ax mode
+         * Note: this is only applicable if 802.11ax is supported for softAp
+         */
+        uint32_t heBssColor;
+
+        /**
+         * Whether HE Target Wait Time (TWT) is enabled or not on softAp.
+         * Note: this is only applicable if 802.11ax is supported for softAp
+         */
+        bool enableHeTargetWakeTime;
+    };
+
+    /**
+     * Parameters to specify the channel frequency range for ACS.
+     */
+    struct AcsFrequencyRange {
+        /**
+         * Channel Frequency (in MHz) at the start of the range.
+         */
+        uint32_t start;
+
+        /**
+         * Channel Frequency (in MHz) at the end of the range.
+         */
+        uint32_t end;
     };
 
     /**
@@ -72,6 +119,15 @@
          * Band to use for the SoftAp operations.
          */
         bitfield<BandMask> bandMask;
+
+        /**
+         * This option can be used to specify the channel frequencies (in MHz) selected by ACS.
+         * If this is an empty list, all channels allowed in selected HW mode
+         * are specified implicitly.
+         * Note: channels may be overridden by firmware.
+         * Note: this option is ignored if ACS is disabled.
+         */
+        vec<AcsFrequencyRange> acsChannelFreqRangesMhz;
     };
 
     /**
@@ -82,9 +138,15 @@
          * Baseline information as defined in HAL 1.1.
          */
         @1.1::IHostapd.IfaceParams V1_1;
-        /** Additional Hw mode params for the interface */
+
+        /**
+         * Additional Hw mode params for the interface
+         */
         HwModeParams hwModeParams;
-        /** Additional Channel params for the interface */
+
+        /**
+         * Additional Channel params for the interface
+         */
         ChannelParams channelParams;
     };
 
@@ -104,7 +166,7 @@
      *         |HostapdStatusCode.FAILURE_IFACE_EXISTS|
      */
     addAccessPoint_1_2(IfaceParams ifaceParams, NetworkParams nwParams)
-        generates(HostapdStatus status);
+        generates (HostapdStatus status);
 
     /**
      * force one of the hotspot clients disconnect..
@@ -120,4 +182,17 @@
      */
     forceClientDisconnect(string ifaceName, MacAddress clientAddress,
         Ieee80211ReasonCode reasonCode) generates (HostapdStatus status);
+
+    /**
+     * Set debug parameters for the hostapd.
+     *
+     * @param level Debug logging level for the hostapd.
+     *        (one of |DebugLevel| values).
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |HostapdStatusCode.SUCCESS|,
+     *         |HostapdStatusCode.FAILURE_UNKNOWN|
+     */
+    setDebugParams(DebugLevel level)
+        generates (HostapdStatus status);
 };
diff --git a/wifi/hostapd/1.2/types.hal b/wifi/hostapd/1.2/types.hal
index 06e890b..54e6529 100644
--- a/wifi/hostapd/1.2/types.hal
+++ b/wifi/hostapd/1.2/types.hal
@@ -53,3 +53,17 @@
      */
     string debugMessage;
 };
+
+/**
+ * Debug levels for the hostapd.
+ * Only log messages with a level greater than the set level
+ * (via |setDebugParams|) will be logged.
+ */
+enum DebugLevel : uint32_t {
+    EXCESSIVE = 0,
+    MSGDUMP = 1,
+    DEBUG = 2,
+    INFO = 3,
+    WARNING = 4,
+    ERROR = 5
+};
diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
index b092d00..94cbb42 100644
--- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -31,6 +31,7 @@
 using ::android::hardware::hidl_string;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
+using ::android::hardware::wifi::hostapd::V1_2::DebugLevel;
 using ::android::hardware::wifi::hostapd::V1_2::HostapdStatusCode;
 using ::android::hardware::wifi::hostapd::V1_2::Ieee80211ReasonCode;
 using ::android::hardware::wifi::hostapd::V1_2::IHostapd;
@@ -108,28 +109,26 @@
         return iface_params_1_2;
     }
 
-    IHostapd::IfaceParams getIfaceParamsWithAcsAndChannelRange() {
+    IHostapd::IfaceParams getIfaceParamsWithAcsAndFreqRange() {
         IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs();
-        ::android::hardware::wifi::hostapd::V1_1::IHostapd::ChannelParams
-            channelParams;
-        ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange
-            acsChannelRange;
-        acsChannelRange.start = 1;
-        acsChannelRange.end = 11;
-        std::vector<
-            ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange>
-            vec_acsChannelRange;
-        vec_acsChannelRange.push_back(acsChannelRange);
-        channelParams.acsChannelRanges = vec_acsChannelRange;
-        iface_params_1_2.V1_1.channelParams = channelParams;
+        ::android::hardware::wifi::hostapd::V1_2::IHostapd::AcsFrequencyRange
+            acsFrequencyRange;
+        acsFrequencyRange.start = 2412;
+        acsFrequencyRange.end = 2462;
+        std::vector<::android::hardware::wifi::hostapd::V1_2::IHostapd::
+                        AcsFrequencyRange>
+            vec_acsFrequencyRange;
+        vec_acsFrequencyRange.push_back(acsFrequencyRange);
+        iface_params_1_2.channelParams.acsChannelFreqRangesMhz =
+            vec_acsFrequencyRange;
         return iface_params_1_2;
     }
 
-    IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidChannelRange() {
+    IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidFreqRange() {
         IHostapd::IfaceParams iface_params_1_2 =
-            getIfaceParamsWithAcsAndChannelRange();
-        iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].start = 222;
-        iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].end = 999;
+            getIfaceParamsWithAcsAndFreqRange();
+        iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].start = 222;
+        iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].end = 999;
         return iface_params_1_2;
     }
 
@@ -185,13 +184,13 @@
 }
 
 /**
- * Adds an access point with PSK network config, ACS enabled & channel Range.
+ * Adds an access point with PSK network config, ACS enabled & frequency Range.
  * Access point creation should pass.
  */
-TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) {
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndFreqRange) {
     auto status =
         HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                    getIfaceParamsWithAcsAndChannelRange(), getPskNwParams());
+                    getIfaceParamsWithAcsAndFreqRange(), getPskNwParams());
     // TODO: b/140172237, fix this in R
     // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
@@ -200,9 +199,9 @@
  * Adds an access point with invalid channel range.
  * Access point creation should fail.
  */
-TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidChannelRange) {
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidFreqRange) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                              getIfaceParamsWithAcsAndInvalidChannelRange(),
+                              getIfaceParamsWithAcsAndInvalidFreqRange(),
                               getPskNwParams());
     // TODO: b/140172237, fix this in R
     // EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
@@ -244,14 +243,15 @@
  * Access point creation & removal should pass.
  */
 TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) {
-    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                              getIfaceParamsWithAcs(), getPskNwParams());
+    auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                                  getIfaceParamsWithAcs(), getPskNwParams());
     // TODO: b/140172237, fix this in R
     /*
-    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
-    status =
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+    auto status =
         HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
-    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    EXPECT_EQ(android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
+    status.code);
     */
 }
 
@@ -319,6 +319,14 @@
     EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code);
 }
 
+/*
+ * SetDebugParams
+ */
+TEST_P(HostapdHidlTest, SetDebugParams) {
+    auto status = HIDL_INVOKE(hostapd_, setDebugParams, DebugLevel::EXCESSIVE);
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
 INSTANTIATE_TEST_CASE_P(
     PerInstance, HostapdHidlTest,
     testing::Combine(
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
index c18bffc..e579d24 100644
--- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
@@ -26,14 +26,14 @@
  */
 interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork {
     /**
-     * Possble mask of values for Proto param.
+     * Possible mask of values for Proto param.
      */
     enum ProtoMask : @1.0::ISupplicantStaNetwork.ProtoMask {
         WAPI = 1 << 2,
     };
 
     /**
-     * Possble mask of values for KeyMgmt param.
+     * Possible mask of values for KeyMgmt param.
      */
     enum KeyMgmtMask : @1.2::ISupplicantStaNetwork.KeyMgmtMask {
         /*
@@ -47,7 +47,7 @@
     };
 
     /**
-     * Possble mask of values for PairwiseCipher param.
+     * Possible mask of values for PairwiseCipher param.
      */
     enum PairwiseCipherMask : @1.2::ISupplicantStaNetwork.PairwiseCipherMask {
         /**
@@ -57,7 +57,7 @@
     };
 
     /**
-     * Possble mask of values for GroupCipher param.
+     * Possible mask of values for GroupCipher param.
      */
     enum GroupCipherMask : @1.2::ISupplicantStaNetwork.GroupCipherMask {
         /**
@@ -67,6 +67,13 @@
     };
 
     /**
+     * Possible mask of values for AuthAlg param.
+     */
+    enum AuthAlgMask : @1.0::ISupplicantStaNetwork.AuthAlgMask {
+        SAE = 1 << 4,
+    };
+
+    /**
      * Set OCSP (Online Certificate Status Protocol) type for this network.
      *
      * @param ocspType value to set.
@@ -236,4 +243,29 @@
      *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
      */
     setPmkCache(vec<uint8_t> serializedEntry) generates (SupplicantStatus status);
+
+    /**
+     * Set auth alg mask for the network.
+     *
+     * @param authAlgMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    setAuthAlg_1_3(bitfield<AuthAlgMask> authAlgMask) generates (SupplicantStatus status);
+
+    /**
+     * Get the auth alg mask set for the network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     * @return authAlgMask Combination of |AuthAlgMask| values.
+     */
+    getAuthAlg_1_3() generates (SupplicantStatus status, bitfield<AuthAlgMask> authAlgMask);
 };