Merge "Point directly to generated c sysprop_library"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 0524110..7db50d5 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -83,6 +83,10 @@
     ],
     stability: "vintf",
     backend: {
+        // The C++ backend is disabled transitively due to use of FMQ.
+        cpp: {
+            enabled: false,
+        },
         java: {
             platform_apis: true,
         },
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index f406cd8..802cb2f 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -282,6 +282,8 @@
      * @throws EX_ILLEGAL_ARGUMENT In the following cases:
      *                             - If the port config can not be found by the ID.
      *                             - If the port config is not of an output mix port.
+     *                             - If the offload info is not provided for an offload
+     *                               port configuration.
      * @throws EX_ILLEGAL_STATE In the following cases:
      *                          - If the port config already has a stream opened on it.
      *                          - If the limit on the open stream count for the port has
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 4728a89..ad1d9c7 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -13,6 +13,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
+        "libstagefright_foundation",
         "android.media.audio.common.types-V1-ndk",
         "android.hardware.audio.core-V1-ndk",
     ],
@@ -37,6 +38,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
+        "libstagefright_foundation",
         "android.media.audio.common.types-V1-ndk",
         "android.hardware.audio.core-V1-ndk",
     ],
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index 19d0b3c..f5d679b 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -20,6 +20,7 @@
 #include <aidl/android/media/audio/common/AudioFormatType.h>
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 
 #include "core-impl/Configuration.h"
 
@@ -42,16 +43,30 @@
 
 namespace aidl::android::hardware::audio::core::internal {
 
+static void fillProfile(AudioProfile* profile, const std::vector<int32_t>& channelLayouts,
+                        const std::vector<int32_t>& sampleRates) {
+    for (auto layout : channelLayouts) {
+        profile->channelMasks.push_back(
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout));
+    }
+    profile->sampleRates.insert(profile->sampleRates.end(), sampleRates.begin(), sampleRates.end());
+}
+
 static AudioProfile createProfile(PcmType pcmType, const std::vector<int32_t>& channelLayouts,
                                   const std::vector<int32_t>& sampleRates) {
     AudioProfile profile;
     profile.format.type = AudioFormatType::PCM;
     profile.format.pcm = pcmType;
-    for (auto layout : channelLayouts) {
-        profile.channelMasks.push_back(
-                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout));
-    }
-    profile.sampleRates.insert(profile.sampleRates.end(), sampleRates.begin(), sampleRates.end());
+    fillProfile(&profile, channelLayouts, sampleRates);
+    return profile;
+}
+
+static AudioProfile createProfile(const std::string& encodingType,
+                                  const std::vector<int32_t>& channelLayouts,
+                                  const std::vector<int32_t>& sampleRates) {
+    AudioProfile profile;
+    profile.format.encoding = encodingType;
+    fillProfile(&profile, channelLayouts, sampleRates);
     return profile;
 }
 
@@ -125,6 +140,8 @@
 //  * "primary output", PRIMARY, 1 max open, 1 max active stream
 //    - profile PCM 16-bit; MONO, STEREO; 44100, 48000
 //    - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+//  * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
+//    - profile MP3; MONO, STEREO; 44100, 48000
 //  * "loopback output", stream count unlimited
 //    - profile PCM 24-bit; STEREO; 48000
 //  * "primary input", 2 max open, 2 max active streams
@@ -136,8 +153,8 @@
 //    - profile PCM 24-bit; STEREO; 48000
 //
 // Routes:
-//  "primary out" -> "Null"
-//  "primary out" -> "USB Out"
+//  "primary out", "compressed offload" -> "Null"
+//  "primary out", "compressed offload" -> "USB Out"
 //  "loopback out" -> "Loopback Out"
 //  "Zero", "USB In" -> "primary input"
 //  "Loopback In" -> "loopback input"
@@ -183,6 +200,18 @@
                                       standardPcmAudioProfiles.end());
         c.ports.push_back(primaryOutMix);
 
+        AudioPort compressedOffloadOutMix =
+                createPort(c.nextPortId++, "compressed offload",
+                           1 << static_cast<int32_t>(AudioOutputFlags::DIRECT) |
+                                   1 << static_cast<int32_t>(AudioOutputFlags::COMPRESS_OFFLOAD) |
+                                   1 << static_cast<int32_t>(AudioOutputFlags::NON_BLOCKING),
+                           false, createPortMixExt(1, 1));
+        compressedOffloadOutMix.profiles.push_back(
+                createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG,
+                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+                              {44100, 48000}));
+        c.ports.push_back(compressedOffloadOutMix);
+
         AudioPort loopOutDevice = createPort(c.nextPortId++, "Loopback Out", 0, false,
                                              createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0));
         loopOutDevice.profiles.push_back(
@@ -244,8 +273,10 @@
         c.ports.push_back(usbInDevice);
         c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles;
 
-        c.routes.push_back(createRoute({primaryOutMix.id}, nullOutDevice.id));
-        c.routes.push_back(createRoute({primaryOutMix.id}, usbOutDevice.id));
+        c.routes.push_back(
+                createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, nullOutDevice.id));
+        c.routes.push_back(
+                createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, usbOutDevice.id));
         c.routes.push_back(createRoute({loopOutMix.id}, loopOutDevice.id));
         c.routes.push_back(createRoute({zeroInDevice.id, usbInDevice.id}, primaryInMix.id));
         c.routes.push_back(createRoute({loopInDevice.id}, loopInMix.id));
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 961ee84..5b4d48a 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -405,6 +405,14 @@
                    << " does not correspond to an output mix port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
+    if (portConfigIt->flags.has_value() &&
+        ((portConfigIt->flags.value().get<AudioIoFlags::Tag::output>() &
+          1 << static_cast<int32_t>(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0) &&
+        !in_offloadInfo.has_value()) {
+        LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+                   << " has COMPRESS_OFFLOAD flag set, requires offload info";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
     if (mStreams.count(in_portConfigId) != 0) {
         LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
                    << " already has a stream opened on it";
@@ -424,6 +432,7 @@
 }
 
 ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPatch* _aidl_return) {
+    LOG(DEBUG) << __func__ << ": requested patch " << in_requested.toString();
     if (in_requested.sourcePortConfigIds.empty()) {
         LOG(ERROR) << __func__ << ": requested patch has empty sources list";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index 0de6047..aeb9983 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -25,20 +25,22 @@
 using aidl::android::hardware::audio::core::Module;
 
 int main() {
+    // This is a debug implementation, always enable debug logging.
+    android::base::SetMinimumLogSeverity(::android::base::DEBUG);
     ABinderProcess_setThreadPoolMaxThreadCount(16);
 
-    // make the default config service
+    // Make the default config service
     auto config = ndk::SharedRefBase::make<Config>();
     const std::string configName = std::string() + Config::descriptor + "/default";
     binder_status_t status =
             AServiceManager_addService(config->asBinder().get(), configName.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(STATUS_OK, status);
 
-    // make the default module
+    // Make the default module
     auto moduleDefault = ndk::SharedRefBase::make<Module>();
     const std::string moduleDefaultName = std::string() + Module::descriptor + "/default";
     status = AServiceManager_addService(moduleDefault->asBinder().get(), moduleDefaultName.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(STATUS_OK, status);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index c160d1f..cd5915b 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -18,12 +18,12 @@
         "VtsHalAudioCoreTargetTest.cpp",
     ],
     shared_libs: [
-        "libbinder",
+        "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.audio.common-V1-cpp",
-        "android.hardware.audio.core-V1-cpp",
-        "android.media.audio.common.types-V1-cpp",
+        "android.hardware.audio.common-V1-ndk",
+        "android.hardware.audio.core-V1-ndk",
+        "android.media.audio.common.types-V1-ndk",
     ],
     test_suites: [
         "general-tests",
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 3f8d088..969b0e9 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -15,25 +15,50 @@
  */
 
 #include <algorithm>
+#include <chrono>
 
-#include <android/media/audio/common/AudioIoFlags.h>
-#include <android/media/audio/common/AudioOutputFlags.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
 
 #include "ModuleConfig.h"
 
 using namespace android;
+using namespace std::chrono_literals;
 
-using android::hardware::audio::core::IModule;
-using android::media::audio::common::AudioChannelLayout;
-using android::media::audio::common::AudioFormatDescription;
-using android::media::audio::common::AudioFormatType;
-using android::media::audio::common::AudioIoFlags;
-using android::media::audio::common::AudioOutputFlags;
-using android::media::audio::common::AudioPort;
-using android::media::audio::common::AudioPortConfig;
-using android::media::audio::common::AudioPortExt;
-using android::media::audio::common::AudioProfile;
-using android::media::audio::common::Int;
+using aidl::android::hardware::audio::core::IModule;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioEncapsulationMode;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Int;
+
+// static
+std::optional<AudioOffloadInfo> ModuleConfig::generateOffloadInfoIfNeeded(
+        const AudioPortConfig& portConfig) {
+    if (portConfig.flags.has_value() &&
+        portConfig.flags.value().getTag() == AudioIoFlags::Tag::output &&
+        (portConfig.flags.value().get<AudioIoFlags::Tag::output>() &
+         1 << static_cast<int>(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0) {
+        AudioOffloadInfo offloadInfo;
+        offloadInfo.base.sampleRate = portConfig.sampleRate.value().value;
+        offloadInfo.base.channelMask = portConfig.channelMask.value();
+        offloadInfo.base.format = portConfig.format.value();
+        offloadInfo.bitRatePerSecond = 256;                                // Arbitrary value.
+        offloadInfo.durationUs = std::chrono::microseconds(1min).count();  // Arbitrary value.
+        offloadInfo.usage = AudioUsage::MEDIA;
+        offloadInfo.encapsulationMode = AudioEncapsulationMode::NONE;
+        return offloadInfo;
+    }
+    return {};
+}
 
 template <typename T>
 auto findById(const std::vector<T>& v, int32_t id) {
@@ -251,23 +276,23 @@
     std::string result;
     result.append("Ports: ");
     result.append(android::internal::ToString(mPorts));
-    result.append("Initial configs: ");
+    result.append("\nInitial configs: ");
     result.append(android::internal::ToString(mInitialConfigs));
-    result.append("Attached sink device ports: ");
+    result.append("\nAttached sink device ports: ");
     result.append(android::internal::ToString(mAttachedSinkDevicePorts));
-    result.append("Attached source device ports: ");
+    result.append("\nAttached source device ports: ");
     result.append(android::internal::ToString(mAttachedSourceDevicePorts));
-    result.append("External device ports: ");
+    result.append("\nExternal device ports: ");
     result.append(android::internal::ToString(mExternalDevicePorts));
-    result.append("Routes: ");
+    result.append("\nRoutes: ");
     result.append(android::internal::ToString(mRoutes));
     return result;
 }
 
-static std::vector<AudioPortConfig> combineAudioConfigs(const AudioPort& port,
-                                                        const AudioProfile& profile) {
-    std::vector<AudioPortConfig> configs;
-    configs.reserve(profile.channelMasks.size() * profile.sampleRates.size());
+static size_t combineAudioConfigs(const AudioPort& port, const AudioProfile& profile,
+                                  std::vector<AudioPortConfig>* result) {
+    const size_t newConfigCount = profile.channelMasks.size() * profile.sampleRates.size();
+    result->reserve(result->capacity() + newConfigCount);
     for (auto channelMask : profile.channelMasks) {
         for (auto sampleRate : profile.sampleRates) {
             AudioPortConfig config{};
@@ -277,66 +302,32 @@
             config.sampleRate = sr;
             config.channelMask = channelMask;
             config.format = profile.format;
+            config.flags = port.flags;
             config.ext = port.ext;
-            configs.push_back(config);
+            result->push_back(std::move(config));
         }
     }
-    return configs;
+    return newConfigCount;
 }
 
-std::vector<AudioPortConfig> ModuleConfig::generateInputAudioMixPortConfigs(
-        const std::vector<AudioPort>& ports, bool singleProfile) const {
+static bool isDynamicProfile(const AudioProfile& profile) {
+    return (profile.format.type == AudioFormatType::DEFAULT && profile.format.encoding.empty()) ||
+           profile.sampleRates.empty() || profile.channelMasks.empty();
+}
+
+std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
+        const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
     std::vector<AudioPortConfig> result;
     for (const auto& mixPort : ports) {
-        if (getAttachedSourceDevicesPortsForMixPort(mixPort).empty()) {
-            continue;  // no attached devices
+        if (getAttachedDevicesPortsForMixPort(isInput, mixPort).empty()) {
+            continue;
         }
         for (const auto& profile : mixPort.profiles) {
-            if (profile.format.type == AudioFormatType::DEFAULT || profile.sampleRates.empty() ||
-                profile.channelMasks.empty()) {
-                continue;  // dynamic profile
-            }
-            auto configs = combineAudioConfigs(mixPort, profile);
-            for (auto& config : configs) {
-                config.flags = mixPort.flags;
-                result.push_back(config);
-                if (singleProfile) return result;
-            }
-        }
-    }
-    return result;
-}
-
-static std::tuple<AudioIoFlags, bool> generateOutFlags(const AudioPort& mixPort) {
-    static const AudioIoFlags offloadFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(
-            (1 << static_cast<int>(AudioOutputFlags::COMPRESS_OFFLOAD)) |
-            (1 << static_cast<int>(AudioOutputFlags::DIRECT)));
-    const bool isOffload = (mixPort.flags.get<AudioIoFlags::Tag::output>() &
-                            (1 << static_cast<int>(AudioOutputFlags::COMPRESS_OFFLOAD))) != 0;
-    return {isOffload ? offloadFlags : mixPort.flags, isOffload};
-}
-
-std::vector<AudioPortConfig> ModuleConfig::generateOutputAudioMixPortConfigs(
-        const std::vector<AudioPort>& ports, bool singleProfile) const {
-    std::vector<AudioPortConfig> result;
-    for (const auto& mixPort : ports) {
-        if (getAttachedSinkDevicesPortsForMixPort(mixPort).empty()) {
-            continue;  // no attached devices
-        }
-        auto [flags, isOffload] = generateOutFlags(mixPort);
-        (void)isOffload;
-        for (const auto& profile : mixPort.profiles) {
-            if (profile.format.type == AudioFormatType::DEFAULT) continue;
-            auto configs = combineAudioConfigs(mixPort, profile);
-            for (auto& config : configs) {
-                // Some combinations of flags declared in the config file require special
-                // treatment.
-                // if (isOffload) {
-                //     config.offloadInfo.info(generateOffloadInfo(config.base));
-                // }
-                config.flags = flags;
-                result.push_back(config);
-                if (singleProfile) return result;
+            if (isDynamicProfile(profile)) continue;
+            combineAudioConfigs(mixPort, profile, &result);
+            if (singleProfile && !result.empty()) {
+                result.resize(1);
+                return result;
             }
         }
     }
@@ -349,9 +340,11 @@
     for (const auto& devicePort : ports) {
         const size_t resultSizeBefore = result.size();
         for (const auto& profile : devicePort.profiles) {
-            auto configs = combineAudioConfigs(devicePort, profile);
-            result.insert(result.end(), configs.begin(), configs.end());
-            if (singleProfile && !result.empty()) return result;
+            combineAudioConfigs(devicePort, profile, &result);
+            if (singleProfile && !result.empty()) {
+                result.resize(1);
+                return result;
+            }
         }
         if (resultSizeBefore == result.size()) {
             std::copy_if(mInitialConfigs.begin(), mInitialConfigs.end(), std::back_inserter(result),
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index 0e2738b..df13430 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -21,95 +21,94 @@
 #include <utility>
 #include <vector>
 
-#include <android/hardware/audio/core/AudioRoute.h>
-#include <android/hardware/audio/core/IModule.h>
-#include <android/media/audio/common/AudioPort.h>
-#include <binder/Status.h>
+#include <aidl/android/hardware/audio/core/AudioRoute.h>
+#include <aidl/android/hardware/audio/core/IModule.h>
+#include <aidl/android/media/audio/common/AudioOffloadInfo.h>
+#include <aidl/android/media/audio/common/AudioPort.h>
 
 class ModuleConfig {
   public:
-    using SrcSinkPair = std::pair<android::media::audio::common::AudioPortConfig,
-                                  android::media::audio::common::AudioPortConfig>;
+    using SrcSinkPair = std::pair<aidl::android::media::audio::common::AudioPortConfig,
+                                  aidl::android::media::audio::common::AudioPortConfig>;
     using SrcSinkGroup =
-            std::pair<android::hardware::audio::core::AudioRoute, std::vector<SrcSinkPair>>;
+            std::pair<aidl::android::hardware::audio::core::AudioRoute, std::vector<SrcSinkPair>>;
 
-    explicit ModuleConfig(android::hardware::audio::core::IModule* module);
-    android::binder::Status getStatus() const { return mStatus; }
-    std::string getError() const { return mStatus.toString8().c_str(); }
+    static std::optional<aidl::android::media::audio::common::AudioOffloadInfo>
+    generateOffloadInfoIfNeeded(
+            const aidl::android::media::audio::common::AudioPortConfig& portConfig);
 
-    std::vector<android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
-    std::vector<android::media::audio::common::AudioPort> getExternalDevicePorts() const;
-    std::vector<android::media::audio::common::AudioPort> getInputMixPorts() const;
-    std::vector<android::media::audio::common::AudioPort> getOutputMixPorts() const;
-    std::vector<android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
+    explicit ModuleConfig(aidl::android::hardware::audio::core::IModule* module);
+    const ndk::ScopedAStatus& getStatus() const { return mStatus; }
+    std::string getError() const { return mStatus.getMessage(); }
+
+    std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getExternalDevicePorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getInputMixPorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getOutputMixPorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
         return isInput ? getInputMixPorts() : getOutputMixPorts();
     }
 
-    std::vector<android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
-            bool isInput, const android::media::audio::common::AudioPort& mixPort) const {
+    std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
+            bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
         return isInput ? getAttachedSourceDevicesPortsForMixPort(mixPort)
                        : getAttachedSinkDevicesPortsForMixPort(mixPort);
     }
-    std::vector<android::media::audio::common::AudioPort> getAttachedSinkDevicesPortsForMixPort(
-            const android::media::audio::common::AudioPort& mixPort) const;
-    std::vector<android::media::audio::common::AudioPort> getAttachedSourceDevicesPortsForMixPort(
-            const android::media::audio::common::AudioPort& mixPort) const;
-    std::optional<android::media::audio::common::AudioPort> getSourceMixPortForAttachedDevice()
-            const;
+    std::vector<aidl::android::media::audio::common::AudioPort>
+    getAttachedSinkDevicesPortsForMixPort(
+            const aidl::android::media::audio::common::AudioPort& mixPort) const;
+    std::vector<aidl::android::media::audio::common::AudioPort>
+    getAttachedSourceDevicesPortsForMixPort(
+            const aidl::android::media::audio::common::AudioPort& mixPort) const;
+    std::optional<aidl::android::media::audio::common::AudioPort>
+    getSourceMixPortForAttachedDevice() const;
 
     std::optional<SrcSinkPair> getNonRoutableSrcSinkPair(bool isInput) const;
     std::optional<SrcSinkPair> getRoutableSrcSinkPair(bool isInput) const;
     std::vector<SrcSinkGroup> getRoutableSrcSinkGroups(bool isInput) const;
 
-    std::vector<android::media::audio::common::AudioPortConfig>
+    std::vector<aidl::android::media::audio::common::AudioPortConfig>
     getPortConfigsForAttachedDevicePorts() const {
         return generateAudioDevicePortConfigs(getAttachedDevicePorts(), false);
     }
-    std::vector<android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts() const {
-        auto inputs = generateInputAudioMixPortConfigs(getInputMixPorts(), false);
-        auto outputs = generateOutputAudioMixPortConfigs(getOutputMixPorts(), false);
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts()
+            const {
+        auto inputs = generateAudioMixPortConfigs(getInputMixPorts(), true, false);
+        auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(), false, false);
         inputs.insert(inputs.end(), outputs.begin(), outputs.end());
         return inputs;
     }
-    std::vector<android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
             bool isInput) const {
-        return isInput ? generateInputAudioMixPortConfigs(getInputMixPorts(), false)
-                       : generateOutputAudioMixPortConfigs(getOutputMixPorts(), false);
+        return generateAudioMixPortConfigs(getMixPorts(isInput), isInput, false);
     }
-    std::vector<android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
-            bool isInput, const android::media::audio::common::AudioPort& port) const {
-        return isInput ? generateInputAudioMixPortConfigs({port}, false)
-                       : generateOutputAudioMixPortConfigs({port}, false);
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
+            bool isInput, const aidl::android::media::audio::common::AudioPort& port) const {
+        return generateAudioMixPortConfigs({port}, isInput, false);
     }
-    std::optional<android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
+    std::optional<aidl::android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
             bool isInput) const {
-        const auto config = isInput ? generateInputAudioMixPortConfigs(getInputMixPorts(), true)
-                                    : generateOutputAudioMixPortConfigs(getOutputMixPorts(), true);
-        // TODO: Avoid returning configs for offload since they require an extra
-        //       argument to openOutputStream.
+        const auto config = generateAudioMixPortConfigs(getMixPorts(isInput), isInput, true);
         if (!config.empty()) {
             return *config.begin();
-        } else {
-            return {};
         }
+        return {};
     }
-    std::optional<android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
-            bool isInput, const android::media::audio::common::AudioPort& port) const {
-        const auto config = isInput ? generateInputAudioMixPortConfigs({port}, true)
-                                    : generateOutputAudioMixPortConfigs({port}, true);
+    std::optional<aidl::android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
+            bool isInput, const aidl::android::media::audio::common::AudioPort& port) const {
+        const auto config = generateAudioMixPortConfigs({port}, isInput, true);
         if (!config.empty()) {
             return *config.begin();
-        } else {
-            return {};
         }
+        return {};
     }
 
-    std::vector<android::media::audio::common::AudioPortConfig> getPortConfigsForDevicePort(
-            const android::media::audio::common::AudioPort& port) const {
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForDevicePort(
+            const aidl::android::media::audio::common::AudioPort& port) const {
         return generateAudioDevicePortConfigs({port}, false);
     }
-    android::media::audio::common::AudioPortConfig getSingleConfigForDevicePort(
-            const android::media::audio::common::AudioPort& port) const {
+    aidl::android::media::audio::common::AudioPortConfig getSingleConfigForDevicePort(
+            const aidl::android::media::audio::common::AudioPort& port) const {
         const auto config = generateAudioDevicePortConfigs({port}, true);
         return *config.begin();
     }
@@ -117,26 +116,24 @@
     std::string toString() const;
 
   private:
-    std::vector<android::media::audio::common::AudioPortConfig> generateInputAudioMixPortConfigs(
-            const std::vector<android::media::audio::common::AudioPort>& ports,
-            bool singleProfile) const;
-    std::vector<android::media::audio::common::AudioPortConfig> generateOutputAudioMixPortConfigs(
-            const std::vector<android::media::audio::common::AudioPort>& ports,
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> generateAudioMixPortConfigs(
+            const std::vector<aidl::android::media::audio::common::AudioPort>& ports, bool isInput,
             bool singleProfile) const;
 
     // Unlike MixPorts, the generator for DevicePorts always returns a non-empty
     // vector for a non-empty input port list. If there are no profiles in the
     // port, its initial configs are looked up, if there are none,
     // then an empty config is used, assuming further negotiation via setAudioPortConfig.
-    std::vector<android::media::audio::common::AudioPortConfig> generateAudioDevicePortConfigs(
-            const std::vector<android::media::audio::common::AudioPort>& ports,
+    std::vector<aidl::android::media::audio::common::AudioPortConfig>
+    generateAudioDevicePortConfigs(
+            const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
             bool singleProfile) const;
 
-    android::binder::Status mStatus = android::binder::Status::ok();
-    std::vector<android::media::audio::common::AudioPort> mPorts;
-    std::vector<android::media::audio::common::AudioPortConfig> mInitialConfigs;
+    ndk::ScopedAStatus mStatus = ndk::ScopedAStatus::ok();
+    std::vector<aidl::android::media::audio::common::AudioPort> mPorts;
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> mInitialConfigs;
     std::set<int32_t> mAttachedSinkDevicePorts;
     std::set<int32_t> mAttachedSourceDevicePorts;
     std::set<int32_t> mExternalDevicePorts;
-    std::vector<android::hardware::audio::core::AudioRoute> mRoutes;
+    std::vector<aidl::android::hardware::audio::core::AudioRoute> mRoutes;
 };
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index 824ac8d..bb24365 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -27,41 +27,48 @@
 
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/core/IConfig.h>
+#include <aidl/android/hardware/audio/core/IModule.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
 #include <android-base/properties.h>
-#include <android/hardware/audio/core/IConfig.h>
-#include <android/hardware/audio/core/IModule.h>
-#include <android/media/audio/common/AudioIoFlags.h>
-#include <android/media/audio/common/AudioOutputFlags.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 
 #include "ModuleConfig.h"
 
 using namespace android;
-using android::binder::Status;
-using android::hardware::audio::common::PlaybackTrackMetadata;
-using android::hardware::audio::common::RecordTrackMetadata;
-using android::hardware::audio::common::SinkMetadata;
-using android::hardware::audio::common::SourceMetadata;
-using android::hardware::audio::core::AudioPatch;
-using android::hardware::audio::core::AudioRoute;
-using android::hardware::audio::core::IModule;
-using android::hardware::audio::core::IStreamIn;
-using android::hardware::audio::core::IStreamOut;
-using android::hardware::audio::core::ModuleDebug;
-using android::media::audio::common::AudioContentType;
-using android::media::audio::common::AudioDevice;
-using android::media::audio::common::AudioDeviceAddress;
-using android::media::audio::common::AudioDeviceType;
-using android::media::audio::common::AudioFormatType;
-using android::media::audio::common::AudioIoFlags;
-using android::media::audio::common::AudioOutputFlags;
-using android::media::audio::common::AudioPort;
-using android::media::audio::common::AudioPortConfig;
-using android::media::audio::common::AudioPortDeviceExt;
-using android::media::audio::common::AudioPortExt;
-using android::media::audio::common::AudioSource;
-using android::media::audio::common::AudioUsage;
+using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
+using aidl::android::hardware::audio::common::RecordTrackMetadata;
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::AudioPatch;
+using aidl::android::hardware::audio::core::AudioRoute;
+using aidl::android::hardware::audio::core::IModule;
+using aidl::android::hardware::audio::core::IStreamIn;
+using aidl::android::hardware::audio::core::IStreamOut;
+using aidl::android::hardware::audio::core::ModuleDebug;
+using aidl::android::media::audio::common::AudioContentType;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioUsage;
+using ndk::ScopedAStatus;
+
+namespace ndk {
+std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) {
+    str << status.getDescription();
+    return str;
+}
+}  // namespace ndk
 
 template <typename T>
 auto findById(std::vector<T>& v, int32_t id) {
@@ -85,16 +92,23 @@
     return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
 }
 
-struct AidlDeathRecipient : IBinder::DeathRecipient {
+struct AidlDeathRecipient {
+    const ndk::SpAIBinder binder;
+    const ndk::ScopedAIBinder_DeathRecipient recipient;
     std::mutex mutex;
     std::condition_variable condition;
     bool fired = false;
-    wp<IBinder> who;
 
-    void binderDied(const wp<IBinder>& who) override {
+    explicit AidlDeathRecipient(const ndk::SpAIBinder& binder)
+        : binder(binder), recipient(AIBinder_DeathRecipient_new(&binderDiedCallbackAidl)) {}
+
+    binder_status_t linkToDeath() {
+        return AIBinder_linkToDeath(binder.get(), recipient.get(), this);
+    }
+
+    void binderDied() {
         std::unique_lock<std::mutex> lock(mutex);
         fired = true;
-        this->who = who;
         condition.notify_one();
     };
 
@@ -103,6 +117,11 @@
         condition.wait_for(lock, std::chrono::milliseconds(timeoutMs), [this]() { return fired; });
         return fired;
     }
+
+    static void binderDiedCallbackAidl(void* cookie) {
+        AidlDeathRecipient* self = static_cast<AidlDeathRecipient*>(cookie);
+        self->binderDied();
+    }
 };
 
 template <typename T>
@@ -119,21 +138,27 @@
     return false;
 }
 
+// All 'With*' classes are move-only because they are associated with some
+// resource or state of a HAL module.
 class WithDebugFlags {
   public:
+    static WithDebugFlags createNested(const WithDebugFlags& parent) {
+        return WithDebugFlags(parent.mFlags);
+    }
+
     WithDebugFlags() {}
     explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
-    explicit WithDebugFlags(const WithDebugFlags& initial)
-        : mInitial(initial.mFlags), mFlags(initial.mFlags) {}
+    WithDebugFlags(const WithDebugFlags&) = delete;
+    WithDebugFlags& operator=(const WithDebugFlags&) = delete;
     ~WithDebugFlags() {
         if (mModule != nullptr) {
-            Status status = mModule->setModuleDebug(mInitial);
-            EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+            ScopedAStatus status = mModule->setModuleDebug(mInitial);
+            EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
         }
     }
     void SetUp(IModule* module) {
-        Status status = module->setModuleDebug(mFlags);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->setModuleDebug(mFlags);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     ModuleDebug& flags() { return mFlags; }
 
@@ -151,10 +176,12 @@
   public:
     WithAudioPortConfig() {}
     explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
+    WithAudioPortConfig(const WithAudioPortConfig&) = delete;
+    WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
     ~WithAudioPortConfig() {
         if (mModule != nullptr) {
-            Status status = mModule->resetAudioPortConfig(getId());
-            EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+            ScopedAStatus status = mModule->resetAudioPortConfig(getId());
+            EXPECT_EQ(EX_NONE, status.getExceptionCode())
                     << status << "; port config id " << getId();
         }
     }
@@ -174,8 +201,8 @@
         if (mInitialConfig.id == 0) {
             AudioPortConfig suggested;
             bool applied = false;
-            Status status = module->setAudioPortConfig(mInitialConfig, &suggested, &applied);
-            ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+            ScopedAStatus status = module->setAudioPortConfig(mInitialConfig, &suggested, &applied);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode())
                     << status << "; Config: " << mInitialConfig.toString();
             if (!applied && negotiate) {
                 mInitialConfig = suggested;
@@ -206,25 +233,26 @@
 
     void TearDown() override {
         if (module != nullptr) {
-            Status status = module->setModuleDebug(ModuleDebug{});
-            EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+            ScopedAStatus status = module->setModuleDebug(ModuleDebug{});
+            EXPECT_EQ(EX_NONE, status.getExceptionCode())
                     << status << " returned when resetting debug flags";
         }
     }
 
     void ConnectToService() {
-        module = android::waitForDeclaredService<IModule>(String16(GetParam().c_str()));
+        module = IModule::fromBinder(
+                ndk::SpAIBinder(AServiceManager_getService(GetParam().c_str())));
         ASSERT_NE(module, nullptr);
     }
 
     void RestartService() {
         ASSERT_NE(module, nullptr);
         moduleConfig.reset();
-        deathHandler = sp<AidlDeathRecipient>::make();
-        ASSERT_EQ(NO_ERROR, IModule::asBinder(module)->linkToDeath(deathHandler));
+        deathHandler.reset(new AidlDeathRecipient(module->asBinder()));
+        ASSERT_EQ(STATUS_OK, deathHandler->linkToDeath());
         ASSERT_TRUE(base::SetProperty("sys.audio.restart.hal", "1"));
         EXPECT_TRUE(deathHandler->waitForFired(3000));
-        deathHandler = nullptr;
+        deathHandler.reset();
         ASSERT_NO_FATAL_FAILURE(ConnectToService());
     }
 
@@ -235,8 +263,8 @@
             ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));  // calls setAudioPortConfig
             EXPECT_EQ(config.portId, portConfig.get().portId);
             std::vector<AudioPortConfig> retrievedPortConfigs;
-            Status status = module->getAudioPortConfigs(&retrievedPortConfigs);
-            ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+            ScopedAStatus status = module->getAudioPortConfigs(&retrievedPortConfigs);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
             const int32_t portConfigId = portConfig.getId();
             auto configIt = std::find_if(
                     retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
@@ -256,12 +284,12 @@
 
     template <typename Entity>
     void GetAllEntityIds(std::set<int32_t>* entityIds,
-                         Status (IModule::*getter)(std::vector<Entity>*),
+                         ScopedAStatus (IModule::*getter)(std::vector<Entity>*),
                          const std::string& errorMessage) {
         std::vector<Entity> entities;
         {
-            Status status = (module.get()->*getter)(&entities);
-            ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+            ScopedAStatus status = (module.get()->*getter)(&entities);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
         }
         std::transform(entities.begin(), entities.end(),
                        std::inserter(*entityIds, entityIds->begin()),
@@ -290,13 +318,13 @@
     void SetUpModuleConfig() {
         if (moduleConfig == nullptr) {
             moduleConfig = std::make_unique<ModuleConfig>(module.get());
-            ASSERT_EQ(Status::EX_NONE, moduleConfig->getStatus().exceptionCode())
+            ASSERT_EQ(EX_NONE, moduleConfig->getStatus().getExceptionCode())
                     << "ModuleConfig init error: " << moduleConfig->getError();
         }
     }
 
-    sp<IModule> module;
-    sp<AidlDeathRecipient> deathHandler;
+    std::shared_ptr<IModule> module;
+    std::unique_ptr<AidlDeathRecipient> deathHandler;
     std::unique_ptr<ModuleConfig> moduleConfig;
     WithDebugFlags debug;
 };
@@ -306,16 +334,18 @@
     explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
     WithDevicePortConnectedState(const AudioPort& id, const AudioDeviceAddress& address)
         : mIdAndData(setAudioPortAddress(id, address)) {}
+    WithDevicePortConnectedState(const WithDevicePortConnectedState&) = delete;
+    WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
     ~WithDevicePortConnectedState() {
         if (mModule != nullptr) {
-            Status status = mModule->disconnectExternalDevice(getId());
-            EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+            ScopedAStatus status = mModule->disconnectExternalDevice(getId());
+            EXPECT_EQ(EX_NONE, status.getExceptionCode())
                     << status << " returned when disconnecting device port ID " << getId();
         }
     }
     void SetUp(IModule* module) {
-        Status status = module->connectExternalDevice(mIdAndData, &mConnectedPort);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+        ScopedAStatus status = module->connectExternalDevice(mIdAndData, &mConnectedPort);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode())
                 << status << " returned when connecting device port ID & data "
                 << mIdAndData.toString();
         ASSERT_NE(mIdAndData.id, getId())
@@ -342,45 +372,54 @@
   public:
     WithStream() {}
     explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
+    WithStream(const WithStream&) = delete;
+    WithStream& operator=(const WithStream&) = delete;
     ~WithStream() {
         if (mStream != nullptr) {
-            Status status = mStream->close();
-            EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+            ScopedAStatus status = mStream->close();
+            EXPECT_EQ(EX_NONE, status.getExceptionCode())
                     << status << "; port config id " << getPortId();
         }
     }
     void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
-    Status SetUpNoChecks(IModule* module) { return SetUpNoChecks(module, mPortConfig.get()); }
-    Status SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig);
+    ScopedAStatus SetUpNoChecks(IModule* module) {
+        return SetUpNoChecks(module, mPortConfig.get());
+    }
+    ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig);
     void SetUp(IModule* module) {
         ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
-        Status status = SetUpNoChecks(module);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+        ScopedAStatus status = SetUpNoChecks(module);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode())
                 << status << "; port config id " << getPortId();
         ASSERT_NE(nullptr, mStream) << "; port config id " << getPortId();
     }
     Stream* get() const { return mStream.get(); }
+    std::shared_ptr<Stream> getSharedPointer() const { return mStream; }
     const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); }
     int32_t getPortId() const { return mPortConfig.getId(); }
 
   private:
     WithAudioPortConfig mPortConfig;
-    sp<Stream> mStream;
+    std::shared_ptr<Stream> mStream;
 };
 
-template <>
-Status WithStream<IStreamIn>::SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig) {
+SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) {
     RecordTrackMetadata trackMeta;
     trackMeta.source = AudioSource::MIC;
     trackMeta.gain = 1.0;
     trackMeta.channelMask = portConfig.channelMask.value();
     SinkMetadata metadata;
     metadata.tracks.push_back(trackMeta);
-    return module->openInputStream(portConfig.id, metadata, &mStream);
+    return metadata;
 }
 
 template <>
-Status WithStream<IStreamOut>::SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig) {
+ScopedAStatus WithStream<IStreamIn>::SetUpNoChecks(IModule* module,
+                                                   const AudioPortConfig& portConfig) {
+    return module->openInputStream(portConfig.id, GenerateSinkMetadata(portConfig), &mStream);
+}
+
+SourceMetadata GenerateSourceMetadata(const AudioPortConfig& portConfig) {
     PlaybackTrackMetadata trackMeta;
     trackMeta.usage = AudioUsage::MEDIA;
     trackMeta.contentType = AudioContentType::MUSIC;
@@ -388,7 +427,15 @@
     trackMeta.channelMask = portConfig.channelMask.value();
     SourceMetadata metadata;
     metadata.tracks.push_back(trackMeta);
-    return module->openOutputStream(portConfig.id, metadata, {}, &mStream);
+    return metadata;
+}
+
+template <>
+ScopedAStatus WithStream<IStreamOut>::SetUpNoChecks(IModule* module,
+                                                    const AudioPortConfig& portConfig) {
+    return module->openOutputStream(portConfig.id, GenerateSourceMetadata(portConfig),
+                                    ModuleConfig::generateOffloadInfoIfNeeded(portConfig),
+                                    &mStream);
 }
 
 class WithAudioPatch {
@@ -396,18 +443,19 @@
     WithAudioPatch() {}
     WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
         : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
+    WithAudioPatch(const WithAudioPatch&) = delete;
+    WithAudioPatch& operator=(const WithAudioPatch&) = delete;
     ~WithAudioPatch() {
         if (mModule != nullptr && mPatch.id != 0) {
-            Status status = mModule->resetAudioPatch(mPatch.id);
-            EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
-                    << status << "; patch id " << getId();
+            ScopedAStatus status = mModule->resetAudioPatch(mPatch.id);
+            EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << "; patch id " << getId();
         }
     }
     void SetUpPortConfigs(IModule* module) {
         ASSERT_NO_FATAL_FAILURE(mSrcPortConfig.SetUp(module));
         ASSERT_NO_FATAL_FAILURE(mSinkPortConfig.SetUp(module));
     }
-    Status SetUpNoChecks(IModule* module) {
+    ScopedAStatus SetUpNoChecks(IModule* module) {
         mModule = module;
         mPatch.sourcePortConfigIds = std::vector<int32_t>{mSrcPortConfig.getId()};
         mPatch.sinkPortConfigIds = std::vector<int32_t>{mSinkPortConfig.getId()};
@@ -415,8 +463,8 @@
     }
     void SetUp(IModule* module) {
         ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module));
-        Status status = SetUpNoChecks(module);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+        ScopedAStatus status = SetUpNoChecks(module);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode())
                 << status << "; source port config id " << mSrcPortConfig.getId()
                 << "; sink port config id " << mSinkPortConfig.getId();
     }
@@ -446,13 +494,13 @@
 TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
     std::vector<AudioPort> ports1;
     {
-        Status status = module->getAudioPorts(&ports1);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPorts(&ports1);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     std::vector<AudioPort> ports2;
     {
-        Status status = module->getAudioPorts(&ports2);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPorts(&ports2);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     ASSERT_EQ(ports1.size(), ports2.size())
             << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
@@ -464,13 +512,13 @@
 TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
     std::vector<AudioRoute> routes1;
     {
-        Status status = module->getAudioRoutes(&routes1);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioRoutes(&routes1);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     std::vector<AudioRoute> routes2;
     {
-        Status status = module->getAudioRoutes(&routes2);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioRoutes(&routes2);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     ASSERT_EQ(routes1.size(), routes2.size())
             << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
@@ -482,8 +530,8 @@
 TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
     std::vector<AudioRoute> routes;
     {
-        Status status = module->getAudioRoutes(&routes);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioRoutes(&routes);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     for (const auto& route : routes) {
         std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
@@ -500,8 +548,8 @@
     ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
     std::vector<AudioRoute> routes;
     {
-        Status status = module->getAudioRoutes(&routes);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioRoutes(&routes);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     for (const auto& route : routes) {
         EXPECT_EQ(1, portIds.count(route.sinkPortId))
@@ -520,8 +568,8 @@
     }
     for (const auto portId : portIds) {
         std::vector<AudioRoute> routes;
-        Status status = module->getAudioRoutesForAudioPort(portId, &routes);
-        EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioRoutesForAudioPort(portId, &routes);
+        EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
         for (const auto& r : routes) {
             if (r.sinkPortId != portId) {
                 const auto& srcs = r.sourcePortIds;
@@ -532,8 +580,8 @@
     }
     for (const auto portId : GetNonExistentIds(portIds)) {
         std::vector<AudioRoute> routes;
-        Status status = module->getAudioRoutesForAudioPort(portId, &routes);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->getAudioRoutesForAudioPort(portId, &routes);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port ID " << portId;
     }
 }
@@ -541,8 +589,8 @@
 TEST_P(AudioCoreModule, CheckDevicePorts) {
     std::vector<AudioPort> ports;
     {
-        Status status = module->getAudioPorts(&ports);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPorts(&ports);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     std::optional<int32_t> defaultOutput, defaultInput;
     std::set<AudioDevice> inputs, outputs;
@@ -590,8 +638,8 @@
 TEST_P(AudioCoreModule, CheckMixPorts) {
     std::vector<AudioPort> ports;
     {
-        Status status = module->getAudioPorts(&ports);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPorts(&ports);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     std::optional<int32_t> primaryMixPort;
     constexpr int primaryOutputFlag = 1 << static_cast<int>(AudioOutputFlags::PRIMARY);
@@ -619,18 +667,24 @@
     }
     for (const auto portId : portIds) {
         AudioPort port;
-        Status status = module->getAudioPort(portId, &port);
-        EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPort(portId, &port);
+        EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
         EXPECT_EQ(portId, port.id);
     }
     for (const auto portId : GetNonExistentIds(portIds)) {
         AudioPort port;
-        Status status = module->getAudioPort(portId, &port);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->getAudioPort(portId, &port);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port ID " << portId;
     }
 }
 
+TEST_P(AudioCoreModule, SetUpModuleConfig) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    // Send the module config to logcat to facilitate failures investigation.
+    LOG(INFO) << "SetUpModuleConfig: " << moduleConfig->toString();
+}
+
 // Verify that HAL module reports for a connected device port at least one non-dynamic profile,
 // that is, a profile with actual supported configuration.
 // Note: This test relies on simulation of external device connections by the HAL module.
@@ -653,8 +707,8 @@
                   portConnected.get().ext.get<AudioPortExt::Tag::device>().device);
         // Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port.
         AudioPort connectedPort;
-        Status status = module->getAudioPort(connectedPortId, &connectedPort);
-        EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+        ScopedAStatus status = module->getAudioPort(connectedPortId, &connectedPort);
+        EXPECT_EQ(EX_NONE, status.getExceptionCode())
                 << status << " returned for getAudioPort port ID " << connectedPortId;
         EXPECT_EQ(portConnected.get(), connectedPort);
         const auto& portProfiles = connectedPort.profiles;
@@ -669,8 +723,8 @@
 
         std::vector<AudioPort> allPorts;
         {
-            Status status = module->getAudioPorts(&allPorts);
-            ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+            ScopedAStatus status = module->getAudioPorts(&allPorts);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
         }
         const auto allPortsIt = findById(allPorts, connectedPortId);
         EXPECT_NE(allPorts.end(), allPortsIt);
@@ -685,16 +739,16 @@
     ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
     for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
         {
-            sp<IStreamIn> stream;
-            Status status = module->openInputStream(portConfigId, {}, &stream);
-            EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+            std::shared_ptr<IStreamIn> stream;
+            ScopedAStatus status = module->openInputStream(portConfigId, {}, &stream);
+            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                     << status << " openInputStream returned for port config ID " << portConfigId;
             EXPECT_EQ(nullptr, stream);
         }
         {
-            sp<IStreamOut> stream;
-            Status status = module->openOutputStream(portConfigId, {}, {}, &stream);
-            EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+            std::shared_ptr<IStreamOut> stream;
+            ScopedAStatus status = module->openOutputStream(portConfigId, {}, {}, &stream);
+            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                     << status << " openOutputStream returned for port config ID " << portConfigId;
             EXPECT_EQ(nullptr, stream);
         }
@@ -711,8 +765,8 @@
     ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
     std::vector<AudioPortConfig> portConfigs;
     {
-        Status status = module->getAudioPortConfigs(&portConfigs);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPortConfigs(&portConfigs);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     for (const auto& config : portConfigs) {
         EXPECT_EQ(1, portIds.count(config.portId))
@@ -724,8 +778,8 @@
     std::set<int32_t> portConfigIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
     for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
-        Status status = module->resetAudioPortConfig(portConfigId);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->resetAudioPortConfig(portConfigId);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port config ID " << portConfigId;
     }
 }
@@ -735,19 +789,19 @@
 TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
     std::vector<AudioPortConfig> portConfigsBefore;
     {
-        Status status = module->getAudioPortConfigs(&portConfigsBefore);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPortConfigs(&portConfigsBefore);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     // TODO: Change port configs according to port profiles.
     for (const auto& c : portConfigsBefore) {
-        Status status = module->resetAudioPortConfig(c.id);
-        EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+        ScopedAStatus status = module->resetAudioPortConfig(c.id);
+        EXPECT_EQ(EX_NONE, status.getExceptionCode())
                 << status << " returned for port config ID " << c.id;
     }
     std::vector<AudioPortConfig> portConfigsAfter;
     {
-        Status status = module->getAudioPortConfigs(&portConfigsAfter);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPortConfigs(&portConfigsAfter);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     for (const auto& c : portConfigsBefore) {
         auto afterIt = findById<AudioPortConfig>(portConfigsAfter, c.id);
@@ -770,8 +824,8 @@
     portConfig.portId = srcMixPort.value().id;
     {
         bool applied = true;
-        Status status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+        ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode())
                 << status << "; Config: " << portConfig.toString();
         EXPECT_FALSE(applied);
     }
@@ -826,8 +880,8 @@
         AudioPortConfig portConfig, suggestedConfig;
         bool applied;
         portConfig.portId = portId;
-        Status status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port ID " << portId;
         EXPECT_FALSE(suggestedConfig.format.has_value());
         EXPECT_FALSE(suggestedConfig.channelMask.has_value());
@@ -842,8 +896,8 @@
         AudioPortConfig portConfig, suggestedConfig;
         bool applied;
         portConfig.id = portConfigId;
-        Status status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port config ID " << portConfigId;
         EXPECT_FALSE(suggestedConfig.format.has_value());
         EXPECT_FALSE(suggestedConfig.channelMask.has_value());
@@ -858,15 +912,15 @@
         GTEST_SKIP() << "No external devices in the module.";
     }
     AudioPort ignored;
-    WithDebugFlags doNotSimulateConnections(debug);
+    WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug);
     doNotSimulateConnections.flags().simulateDeviceConnections = false;
     ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
     for (const auto& port : ports) {
         AudioPort portWithData = port;
         portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
                 GenerateUniqueDeviceAddress();
-        Status status = module->connectExternalDevice(portWithData, &ignored);
-        EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+        ScopedAStatus status = module->connectExternalDevice(portWithData, &ignored);
+        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                 << status << " returned for static port " << portWithData.toString();
     }
 }
@@ -881,8 +935,8 @@
     ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
     ModuleDebug midwayDebugChange = debug.flags();
     midwayDebugChange.simulateDeviceConnections = false;
-    Status status = module->setModuleDebug(midwayDebugChange);
-    EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+    ScopedAStatus status = module->setModuleDebug(midwayDebugChange);
+    EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
             << status << " returned when trying to disable connections simulation "
             << "while having a connected device";
 }
@@ -894,39 +948,39 @@
     for (const auto portId : GetNonExistentIds(portIds)) {
         AudioPort invalidPort;
         invalidPort.id = portId;
-        Status status = module->connectExternalDevice(invalidPort, &ignored);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->connectExternalDevice(invalidPort, &ignored);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port ID " << portId << " when setting CONNECTED state";
         status = module->disconnectExternalDevice(portId);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port ID " << portId
                 << " when setting DISCONNECTED state";
     }
 
     std::vector<AudioPort> ports;
     {
-        Status status = module->getAudioPorts(&ports);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPorts(&ports);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     for (const auto& port : ports) {
         if (port.ext.getTag() != AudioPortExt::Tag::device) {
-            Status status = module->connectExternalDevice(port, &ignored);
-            EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+            ScopedAStatus status = module->connectExternalDevice(port, &ignored);
+            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                     << status << " returned for non-device port ID " << port.id
                     << " when setting CONNECTED state";
             status = module->disconnectExternalDevice(port.id);
-            EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                     << status << " returned for non-device port ID " << port.id
                     << " when setting DISCONNECTED state";
         } else {
             const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
             if (devicePort.device.type.connection.empty()) {
-                Status status = module->connectExternalDevice(port, &ignored);
-                EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+                ScopedAStatus status = module->connectExternalDevice(port, &ignored);
+                EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                         << status << " returned for permanently attached device port ID " << port.id
                         << " when setting CONNECTED state";
                 status = module->disconnectExternalDevice(port.id);
-                EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+                EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                         << status << " returned for permanently attached device port ID " << port.id
                         << " when setting DISCONNECTED state";
             }
@@ -943,8 +997,8 @@
         GTEST_SKIP() << "No external devices in the module.";
     }
     for (const auto& port : ports) {
-        Status status = module->disconnectExternalDevice(port.id);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->disconnectExternalDevice(port.id);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned when disconnecting already disconnected device port ID "
                 << port.id;
         AudioPort portWithData = port;
@@ -953,14 +1007,14 @@
         WithDevicePortConnectedState portConnected(portWithData);
         ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
         status = module->connectExternalDevice(portConnected.get(), &ignored);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned when trying to connect a connected device port "
                 << portConnected.get().toString();
         status = module->connectExternalDevice(portWithData, &ignored);
-        EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                 << status << " returned when connecting again the external device "
                 << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString();
-        if (status.exceptionCode() == Status::EX_NONE) {
+        if (status.getExceptionCode() == EX_NONE) {
             ADD_FAILURE() << "Returned connected port " << ignored.toString() << " for template "
                           << portWithData.toString();
         }
@@ -984,8 +1038,8 @@
             // Our test assumes that 'getAudioPort' returns at least one profile, and it
             // is not a dynamic profile.
             ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
-            Status status = module->disconnectExternalDevice(portConnected.getId());
-            EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+            ScopedAStatus status = module->disconnectExternalDevice(portConnected.getId());
+            EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                     << status << " returned when trying to disconnect device port ID " << port.id
                     << " with active configuration " << config.getId();
         }
@@ -1001,8 +1055,8 @@
     for (const auto& port : ports) {
         std::vector<AudioRoute> routesBefore;
         {
-            Status status = module->getAudioRoutes(&routesBefore);
-            ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+            ScopedAStatus status = module->getAudioRoutes(&routesBefore);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
         }
 
         int32_t connectedPortId;
@@ -1012,32 +1066,32 @@
             connectedPortId = portConnected.getId();
             std::vector<AudioRoute> connectedPortRoutes;
             {
-                Status status =
+                ScopedAStatus status =
                         module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes);
-                ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+                ASSERT_EQ(EX_NONE, status.getExceptionCode())
                         << status << " returned when retrieving routes for connected port id "
                         << connectedPortId;
             }
             // There must be routes for the port to be useful.
             if (connectedPortRoutes.empty()) {
                 std::vector<AudioRoute> allRoutes;
-                Status status = module->getAudioRoutes(&allRoutes);
-                ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+                ScopedAStatus status = module->getAudioRoutes(&allRoutes);
+                ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
                 ADD_FAILURE() << " no routes returned for the connected port "
                               << portConnected.get().toString()
                               << "; all routes: " << android::internal::ToString(allRoutes);
             }
         }
         std::vector<AudioRoute> ignored;
-        Status status = module->getAudioRoutesForAudioPort(connectedPortId, &ignored);
-        ASSERT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->getAudioRoutesForAudioPort(connectedPortId, &ignored);
+        ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned when retrieving routes for released connected port id "
                 << connectedPortId;
 
         std::vector<AudioRoute> routesAfter;
         {
-            Status status = module->getAudioRoutes(&routesAfter);
-            ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+            ScopedAStatus status = module->getAudioRoutes(&routesAfter);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
         }
         ASSERT_EQ(routesBefore.size(), routesAfter.size())
                 << "Sizes of audio route arrays do not match after creating and "
@@ -1063,14 +1117,14 @@
         if (!portConfig.has_value()) {
             GTEST_SKIP() << "No mix port for attached devices";
         }
-        sp<Stream> heldStream;
+        std::shared_ptr<Stream> heldStream;
         {
             WithStream<Stream> stream(portConfig.value());
             ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get()));
-            heldStream = stream.get();
+            heldStream = stream.getSharedPointer();
         }
-        Status status = heldStream->close();
-        EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+        ScopedAStatus status = heldStream->close();
+        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                 << status << " when closing the stream twice";
     }
 
@@ -1107,12 +1161,11 @@
                     ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get()));
                 } else {
                     ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-                    Status status = stream.SetUpNoChecks(module.get());
-                    EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+                    ScopedAStatus status = stream.SetUpNoChecks(module.get());
+                    EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                             << status << " open" << direction(true)
-                            << "Stream"
-                               " returned for port config ID "
-                            << stream.getPortId() << ", maxOpenStreamCount is " << maxStreamCount;
+                            << "Stream returned for port config ID " << stream.getPortId()
+                            << ", maxOpenStreamCount is " << maxStreamCount;
                 }
             }
         }
@@ -1130,8 +1183,8 @@
         }
         WithStream<Stream> stream(portConfig.value());
         ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-        Status status = stream.SetUpNoChecks(module.get());
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = stream.SetUpNoChecks(module.get());
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " open" << direction(true) << "Stream returned for port config ID "
                 << stream.getPortId();
         EXPECT_EQ(nullptr, stream.get());
@@ -1152,8 +1205,8 @@
         }
         WithStream<Stream> stream(portConfig.value());
         ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get()));
-        Status status = module->resetAudioPortConfig(stream.getPortId());
-        EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+        ScopedAStatus status = module->resetAudioPortConfig(stream.getPortId());
+        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                 << status << " returned for port config ID " << stream.getPortId();
     }
 
@@ -1161,8 +1214,8 @@
         WithStream<Stream> stream1(portConfig);
         ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get()));
         WithStream<Stream> stream2;
-        Status status = stream2.SetUpNoChecks(module.get(), stream1.getPortConfig());
-        EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+        ScopedAStatus status = stream2.SetUpNoChecks(module.get(), stream1.getPortConfig());
+        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                 << status << " when opening " << direction(false)
                 << " stream twice for the same port config ID " << stream1.getPortId();
     }
@@ -1195,7 +1248,7 @@
     auto primaryPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [](const AudioPort& port) {
         constexpr int primaryOutputFlag = 1 << static_cast<int>(AudioOutputFlags::PRIMARY);
         return port.flags.getTag() == AudioIoFlags::Tag::output &&
-               ((port.flags.get<AudioIoFlags::Tag::output>() & primaryOutputFlag) != 0);
+               (port.flags.get<AudioIoFlags::Tag::output>() & primaryOutputFlag) != 0;
     });
     if (primaryPortIt == mixPorts.end()) {
         GTEST_SKIP() << "No primary mix port";
@@ -1208,6 +1261,31 @@
     EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
 }
 
+TEST_P(AudioStreamOut, RequireOffloadInfo) {
+    const auto mixPorts = moduleConfig->getMixPorts(false);
+    auto offloadPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [&](const AudioPort& port) {
+        constexpr int compressOffloadFlag = 1
+                                            << static_cast<int>(AudioOutputFlags::COMPRESS_OFFLOAD);
+        return port.flags.getTag() == AudioIoFlags::Tag::output &&
+               (port.flags.get<AudioIoFlags::Tag::output>() & compressOffloadFlag) != 0 &&
+               !moduleConfig->getAttachedSinkDevicesPortsForMixPort(port).empty();
+    });
+    if (offloadPortIt == mixPorts.end()) {
+        GTEST_SKIP()
+                << "No mix port for compressed offload that could be routed to attached devices";
+    }
+    const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *offloadPortIt);
+    ASSERT_TRUE(portConfig.has_value())
+            << "No profiles specified for the compressed offload mix port";
+    std::shared_ptr<IStreamOut> ignored;
+    ScopedAStatus status = module->openOutputStream(portConfig.value().id,
+                                                    GenerateSourceMetadata(portConfig.value()),
+                                                    {} /* offloadInfo */, &ignored);
+    EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+            << status
+            << " returned when no offload info is provided for a compressed offload mix port";
+}
+
 // Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
 // to avoid clashing with 'AudioPatch' class.
 class AudioModulePatch : public AudioCoreModule {
@@ -1226,8 +1304,8 @@
         AudioPatch patch;
         patch.sourcePortConfigIds = sources;
         patch.sinkPortConfigIds = sinks;
-        Status status = module->setAudioPatch(patch, &patch);
-        ASSERT_EQ(expectedException, status.exceptionCode())
+        ScopedAStatus status = module->setAudioPatch(patch, &patch);
+        ASSERT_EQ(expectedException, status.getExceptionCode())
                 << status << ": patch source ids: " << android::internal::ToString(sources)
                 << "; sink ids: " << android::internal::ToString(sinks);
     }
@@ -1246,8 +1324,8 @@
                                           patch.get().sinkPortConfigIds.begin(),
                                           patch.get().sinkPortConfigIds.end());
         for (const auto portConfigId : sourceAndSinkPortConfigIds) {
-            Status status = module->resetAudioPortConfig(portConfigId);
-            EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+            ScopedAStatus status = module->resetAudioPortConfig(portConfigId);
+            EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                     << status << " returned for port config ID " << portConfigId;
         }
     }
@@ -1266,22 +1344,22 @@
             ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
         }
         EXPECT_NO_FATAL_FAILURE(
-                SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()}));
+                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()}));
         EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
-                Status::EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()},
+                EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()},
                 {sinkPortConfig.getId()}));
         EXPECT_NO_FATAL_FAILURE(
-                SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {}));
+                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {}));
         EXPECT_NO_FATAL_FAILURE(
-                SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()},
+                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()},
                                       {sinkPortConfig.getId(), sinkPortConfig.getId()}));
 
         std::set<int32_t> portConfigIds;
         ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
         for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
-            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
-                    Status::EX_ILLEGAL_ARGUMENT, {portConfigId}, {sinkPortConfig.getId()}));
-            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT,
+            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {portConfigId},
+                                                          {sinkPortConfig.getId()}));
+            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT,
                                                           {srcPortConfig.getId()}, {portConfigId}));
         }
     }
@@ -1293,8 +1371,8 @@
         }
         WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second);
         ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get()));
-        Status status = patch.SetUpNoChecks(module.get());
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = patch.SetUpNoChecks(module.get());
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << ": when setting up a patch from "
                 << srcSinkPair.value().first.toString() << " to "
                 << srcSinkPair.value().second.toString() << " that does not have a route";
@@ -1307,11 +1385,12 @@
         }
         for (const auto& srcSinkGroup : srcSinkGroups) {
             const auto& route = srcSinkGroup.first;
-            std::vector<WithAudioPatch> patches;
+            std::vector<std::unique_ptr<WithAudioPatch>> patches;
             for (const auto& srcSink : srcSinkGroup.second) {
                 if (!route.isExclusive) {
-                    patches.emplace_back(srcSink.first, srcSink.second);
-                    EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1].SetUp(module.get()));
+                    patches.push_back(
+                            std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
+                    EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
                 } else {
                     WithAudioPatch patch(srcSink.first, srcSink.second);
                     EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
@@ -1351,8 +1430,9 @@
         for (const auto patchId : GetNonExistentIds(patchIds)) {
             AudioPatch patchWithNonExistendId = patch.get();
             patchWithNonExistendId.id = patchId;
-            Status status = module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId);
-            EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+            ScopedAStatus status =
+                    module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId);
+            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                     << status << " returned for patch ID " << patchId;
         }
     }
@@ -1375,8 +1455,8 @@
     std::set<int32_t> patchIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
     for (const auto patchId : GetNonExistentIds(patchIds)) {
-        Status status = module->resetAudioPatch(patchId);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->resetAudioPatch(patchId);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for patch ID " << patchId;
     }
 }
@@ -1398,9 +1478,26 @@
                          android::PrintInstanceNameToString);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch);
 
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+  public:
+    void OnTestStart(const ::testing::TestInfo& test_info) override {
+        TraceTestState("Started", test_info);
+    }
+
+    void OnTestEnd(const ::testing::TestInfo& test_info) override {
+        TraceTestState("Completed", test_info);
+    }
+
+  private:
+    static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
+        LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
+    }
+};
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
-    ProcessState::self()->setThreadPoolMaxThreadCount(1);
-    ProcessState::self()->startThreadPool();
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index dfc2386..44d3cbd 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <fstream>
+#include <numeric>
+
 #include <android-base/chrono_utils.h>
 
 #include "Generators.h"
@@ -517,20 +520,10 @@
     }
 
     bool canQueryPresentationPosition() const {
-        auto maybeSinkAddress =
-                getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName());
-        // Returning 'true' when no sink is found so the test can fail later with a more clear
-        // problem description.
-        return !maybeSinkAddress.has_value() ||
-               !xsd::isTelephonyDevice(maybeSinkAddress.value().deviceType);
+        return !xsd::isTelephonyDevice(address.deviceType);
     }
 
     void createPatchIfNeeded() {
-        auto maybeSinkAddress =
-                getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName());
-        ASSERT_TRUE(maybeSinkAddress.has_value())
-                << "No sink device found for mix port " << getMixPortName() << " (module "
-                << getDeviceName() << ")";
         if (areAudioPatchesSupported()) {
             AudioPortConfig source;
             source.base.format.value(getConfig().base.format);
@@ -540,13 +533,13 @@
             source.ext.mix().ioHandle = helper.getIoHandle();
             source.ext.mix().useCase.stream({});
             AudioPortConfig sink;
-            sink.ext.device(maybeSinkAddress.value());
+            sink.ext.device(address);
             EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{source},
                                                     hidl_vec<AudioPortConfig>{sink},
                                                     returnIn(res, mPatchHandle)));
             mHasPatch = res == Result::OK;
         } else {
-            EXPECT_OK(stream->setDevices({maybeSinkAddress.value()}));
+            EXPECT_OK(stream->setDevices({address}));
         }
     }
 
@@ -556,10 +549,6 @@
                 EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
                 mHasPatch = false;
             }
-        } else {
-            if (stream) {
-                EXPECT_OK(stream->setDevices({address}));
-            }
         }
     }
 
@@ -575,16 +564,22 @@
         // Sometimes HAL doesn't have enough information until the audio data actually gets
         // consumed by the hardware.
         bool timedOut = false;
-        res = Result::INVALID_STATE;
-        for (android::base::Timer elapsed;
-             res != Result::OK && !writer.hasError() &&
-             !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
-            usleep(kWriteDurationUs);
-            ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts)));
-            ASSERT_RESULT(okOrInvalidState, res);
+        if (!firstPosition || *firstPosition == std::numeric_limits<uint64_t>::max()) {
+            res = Result::INVALID_STATE;
+            for (android::base::Timer elapsed;
+                 res != Result::OK && !writer.hasError() &&
+                 !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
+                usleep(kWriteDurationUs);
+                ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts)));
+                ASSERT_RESULT(okOrInvalidState, res);
+            }
+            ASSERT_FALSE(writer.hasError());
+            ASSERT_FALSE(timedOut);
+        } else {
+            // Use `firstPosition` instead of querying it from the HAL. This is used when
+            // `waitForPresentationPositionAdvance` is called in a loop.
+            framesInitial = *firstPosition;
         }
-        ASSERT_FALSE(writer.hasError());
-        ASSERT_FALSE(timedOut);
 
         uint64_t frames = framesInitial;
         for (android::base::Timer elapsed;
@@ -646,7 +641,7 @@
     ASSERT_OK(stream->standby());
     writer.resume();
 
-    uint64_t frames;
+    uint64_t frames = std::numeric_limits<uint64_t>::max();
     ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer, &frames));
     EXPECT_GT(frames, framesInitial);
 
@@ -691,24 +686,12 @@
         InputStreamTest::TearDown();
     }
 
-    bool canQueryCapturePosition() const {
-        auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
-                getDeviceName(), getMixPortName());
-        // Returning 'true' when no source is found so the test can fail later with a more clear
-        // problem description.
-        return !maybeSourceAddress.has_value() ||
-               !xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType);
-    }
+    bool canQueryCapturePosition() const { return !xsd::isTelephonyDevice(address.deviceType); }
 
     void createPatchIfNeeded() {
-        auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
-                getDeviceName(), getMixPortName());
-        ASSERT_TRUE(maybeSourceAddress.has_value())
-                << "No source device found for mix port " << getMixPortName() << " (module "
-                << getDeviceName() << ")";
         if (areAudioPatchesSupported()) {
             AudioPortConfig source;
-            source.ext.device(maybeSourceAddress.value());
+            source.ext.device(address);
             AudioPortConfig sink;
             sink.base.format.value(getConfig().base.format);
             sink.base.sampleRateHz.value(getConfig().base.sampleRateHz);
@@ -721,20 +704,14 @@
                                                     returnIn(res, mPatchHandle)));
             mHasPatch = res == Result::OK;
         } else {
-            EXPECT_OK(stream->setDevices({maybeSourceAddress.value()}));
+            EXPECT_OK(stream->setDevices({address}));
         }
     }
 
     void releasePatchIfNeeded() {
-        if (getDevice()) {
-            if (areAudioPatchesSupported() && mHasPatch) {
-                EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
-                mHasPatch = false;
-            }
-        } else {
-            if (stream) {
-                EXPECT_OK(stream->setDevices({address}));
-            }
+        if (getDevice() && areAudioPatchesSupported() && mHasPatch) {
+            EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
+            mHasPatch = false;
         }
     }
 
@@ -864,14 +841,8 @@
     }
     ASSERT_OK(res);
 
-    auto maybeSourceAddress =
-            getCachedPolicyConfig().getSourceDeviceForMixPort(getDeviceName(), getMixPortName());
-    ASSERT_TRUE(maybeSourceAddress.has_value())
-            << "No source device found for mix port " << getMixPortName() << " (module "
-            << getDeviceName() << ")";
-
     for (auto microphone : microphones) {
-        if (microphone.deviceAddress == maybeSourceAddress.value()) {
+        if (microphone.deviceAddress == address) {
             StreamReader reader(stream.get(), stream->getBufferSize());
             ASSERT_TRUE(reader.start());
             reader.pause();  // This ensures that at least one read has happened.
@@ -889,3 +860,100 @@
                         ::testing::ValuesIn(getBuiltinMicConfigParameters()),
                         &DeviceConfigParameterToString);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MicrophoneInfoInputStreamTest);
+
+static const std::vector<DeviceConfigParameter>& getOutputDeviceCompressedConfigParameters(
+        const AudioConfigBase& configToMatch) {
+    static const std::vector<DeviceConfigParameter> parameters = [&] {
+        auto allParams = getOutputDeviceConfigParameters();
+        std::vector<DeviceConfigParameter> compressedParams;
+        std::copy_if(allParams.begin(), allParams.end(), std::back_inserter(compressedParams),
+                     [&](auto cfg) {
+                         if (std::get<PARAM_CONFIG>(cfg).base != configToMatch) return false;
+                         const auto& flags = std::get<PARAM_FLAGS>(cfg);
+                         return std::find_if(flags.begin(), flags.end(), [](const auto& flag) {
+                                    return flag ==
+                                           toString(xsd::AudioInOutFlag::
+                                                            AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+                                }) != flags.end();
+                     });
+        return compressedParams;
+    }();
+    return parameters;
+}
+
+class CompressedOffloadOutputStreamTest : public PcmOnlyConfigOutputStreamTest {
+  public:
+    void loadData(const std::string& fileName, std::vector<uint8_t>* data) {
+        std::ifstream is(fileName, std::ios::in | std::ios::binary);
+        ASSERT_TRUE(is.good()) << "Failed to open file " << fileName;
+        is.seekg(0, is.end);
+        data->reserve(data->size() + is.tellg());
+        is.seekg(0, is.beg);
+        data->insert(data->end(), std::istreambuf_iterator<char>(is),
+                     std::istreambuf_iterator<char>());
+        ASSERT_TRUE(!is.fail()) << "Failed to read from file " << fileName;
+    }
+};
+
+TEST_P(CompressedOffloadOutputStreamTest, Mp3FormatGaplessOffload) {
+    doc::test("Check that compressed offload mix ports for MP3 implement gapless offload");
+    const auto& flags = getOutputFlags();
+    if (std::find_if(flags.begin(), flags.end(), [](const auto& flag) {
+            return flag == toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD);
+        }) == flags.end()) {
+        GTEST_SKIP() << "Compressed offload mix port does not support gapless offload";
+    }
+    // FIXME: The presentation position is not updated if there is no zero padding in data.
+    std::vector<uint8_t> offloadData(stream->getBufferSize());
+    ASSERT_NO_FATAL_FAILURE(loadData("/data/local/tmp/sine882hz3s.mp3", &offloadData));
+    ASSERT_FALSE(offloadData.empty());
+    ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
+    const int presentationeEndPrecisionMs = 1000;
+    const int sampleRate = 44100;
+    const int significantSampleNumber = (presentationeEndPrecisionMs * sampleRate) / 1000;
+    const int delay = 576 + 1000;
+    const int padding = 756 + 1000;
+    const int durationMs = 3000 - 44;
+    // StreamWriter plays 'offloadData' in a loop, possibly using multiple calls to 'write',
+    // this depends on the relative sizes of 'offloadData' and the HAL buffer. Writer calls
+    // 'onDataWrap' callback each time it wraps around the buffer.
+    StreamWriter writer(
+            stream.get(), stream->getBufferSize(), std::move(offloadData), [&]() /* onDataWrap */ {
+                Parameters::set(stream,
+                                {{AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, std::to_string(delay)},
+                                 {AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, std::to_string(padding)}});
+                stream->drain(AudioDrain::EARLY_NOTIFY);
+            });
+    ASSERT_TRUE(writer.start());
+    ASSERT_TRUE(writer.waitForAtLeastOneCycle());
+    // Decrease the volume since the test plays a loud sine wave.
+    ASSERT_OK(stream->setVolume(0.1, 0.1));
+    // How many times to loop the track so that the sum of gapless delay and padding from
+    // the first presentation end to the last is at least 'presentationeEndPrecisionMs'.
+    const int playbackNumber = (int)(significantSampleNumber / ((float)delay + padding) + 1);
+    std::vector<float> presentationEndTimes;
+    uint64_t previousPosition = std::numeric_limits<uint64_t>::max();
+    for (int i = 0; i < playbackNumber; ++i) {
+        const auto start = std::chrono::steady_clock::now();
+        ASSERT_NO_FATAL_FAILURE(
+                waitForPresentationPositionAdvance(writer, &previousPosition, &previousPosition));
+        presentationEndTimes.push_back(std::chrono::duration_cast<std::chrono::milliseconds>(
+                                               std::chrono::steady_clock::now() - start)
+                                               .count());
+    }
+    const float avgDuration =
+            std::accumulate(presentationEndTimes.begin(), presentationEndTimes.end(), 0.0) /
+            presentationEndTimes.size();
+    EXPECT_NEAR(durationMs, avgDuration, presentationeEndPrecisionMs * 0.1);
+    writer.stop();
+    releasePatchIfNeeded();
+}
+
+INSTANTIATE_TEST_CASE_P(
+        CompressedOffloadOutputStream, CompressedOffloadOutputStreamTest,
+        ::testing::ValuesIn(getOutputDeviceCompressedConfigParameters(AudioConfigBase{
+                .format = xsd::toString(xsd::AudioFormat::AUDIO_FORMAT_MP3),
+                .sampleRateHz = 44100,
+                .channelMask = xsd::toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO)})),
+        &DeviceConfigParameterToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CompressedOffloadOutputStreamTest);
diff --git a/audio/core/all-versions/vts/functional/7.0/Generators.cpp b/audio/core/all-versions/vts/functional/7.0/Generators.cpp
index f936d0a..8b955b6 100644
--- a/audio/core/all-versions/vts/functional/7.0/Generators.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/Generators.cpp
@@ -57,9 +57,6 @@
 
 static std::tuple<std::vector<AudioInOutFlag>, bool> generateOutFlags(
         const xsd::MixPorts::MixPort& mixPort) {
-    static const std::vector<AudioInOutFlag> offloadFlags = {
-            toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
-            toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
     std::vector<AudioInOutFlag> flags;
     bool isOffload = false;
     if (mixPort.hasFlags()) {
@@ -67,14 +64,10 @@
         isOffload = std::find(xsdFlags.begin(), xsdFlags.end(),
                               xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
                     xsdFlags.end();
-        if (!isOffload) {
-            for (auto flag : xsdFlags) {
-                if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
-                    flags.push_back(toString(flag));
-                }
+        for (auto flag : xsdFlags) {
+            if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
+                flags.push_back(toString(flag));
             }
-        } else {
-            flags = offloadFlags;
         }
     }
     return {flags, isOffload};
@@ -85,10 +78,10 @@
             .base = base,
             .streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC),
             .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
-            .bitRatePerSecond = 320,
+            .bitRatePerSecond = 192,  // as in sine882hz3s.mp3
             .durationMicroseconds = -1,
             .bitWidth = 16,
-            .bufferSize = 256  // arbitrary value
+            .bufferSize = 72000  // 3 seconds at 192 kbps, as in sine882hz3s.mp3
     };
 }
 
@@ -100,11 +93,10 @@
         if (!module || !module->getFirstMixPorts()) break;
         for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
             if (mixPort.getRole() != xsd::Role::source) continue;  // not an output profile
-            if (getCachedPolicyConfig()
-                        .getAttachedSinkDeviceForMixPort(moduleName, mixPort.getName())
-                        .empty()) {
-                continue;  // no attached device
-            }
+            const auto attachedDeviceAddress =
+                    getCachedPolicyConfig().getDeviceAddressOfSinkDeviceAttachedToMixPort(
+                            moduleName, mixPort.getName());
+            if (!attachedDeviceAddress.has_value()) continue;
             auto [flags, isOffload] = generateOutFlags(mixPort);
             for (const auto& profile : mixPort.getProfile()) {
                 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
@@ -118,7 +110,8 @@
                     if (isOffload) {
                         config.offloadInfo.info(generateOffloadInfo(config.base));
                     }
-                    result.emplace_back(device, mixPort.getName(), config, flags);
+                    result.emplace_back(device, mixPort.getName(), attachedDeviceAddress.value(),
+                                        config, flags);
                     if (oneProfilePerDevice) break;
                 }
                 if (oneProfilePerDevice) break;
@@ -162,13 +155,16 @@
                             profile.getFormat(),
                             static_cast<uint32_t>(profile.getSamplingRates()[0]),
                             toString(profile.getChannelMasks()[0])};
+                    DeviceAddress defaultDevice = {
+                            toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT), {}};
                     {
                         AudioConfig config{.base = validBase};
                         config.base.channelMask = "random_string";
                         if (isOffload) {
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                         }
-                        result.emplace_back(device, mixPort.getName(), config, validFlags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            validFlags);
                     }
                     {
                         AudioConfig config{.base = validBase};
@@ -176,7 +172,8 @@
                         if (isOffload) {
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                         }
-                        result.emplace_back(device, mixPort.getName(), config, validFlags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            validFlags);
                     }
                     if (generateInvalidFlags) {
                         AudioConfig config{.base = validBase};
@@ -184,32 +181,37 @@
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                         }
                         std::vector<AudioInOutFlag> flags = {"random_string", ""};
-                        result.emplace_back(device, mixPort.getName(), config, flags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            flags);
                     }
                     if (isOffload) {
                         {
                             AudioConfig config{.base = validBase};
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                             config.offloadInfo.info().base.channelMask = "random_string";
-                            result.emplace_back(device, mixPort.getName(), config, validFlags);
+                            result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                                validFlags);
                         }
                         {
                             AudioConfig config{.base = validBase};
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                             config.offloadInfo.info().base.format = "random_string";
-                            result.emplace_back(device, mixPort.getName(), config, validFlags);
+                            result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                                validFlags);
                         }
                         {
                             AudioConfig config{.base = validBase};
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                             config.offloadInfo.info().streamType = "random_string";
-                            result.emplace_back(device, mixPort.getName(), config, validFlags);
+                            result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                                validFlags);
                         }
                         {
                             AudioConfig config{.base = validBase};
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                             config.offloadInfo.info().usage = "random_string";
-                            result.emplace_back(device, mixPort.getName(), config, validFlags);
+                            result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                                validFlags);
                         }
                         hasOffloadConfig = true;
                     } else {
@@ -233,11 +235,10 @@
         if (!module || !module->getFirstMixPorts()) break;
         for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
             if (mixPort.getRole() != xsd::Role::sink) continue;  // not an input profile
-            if (getCachedPolicyConfig()
-                        .getAttachedSourceDeviceForMixPort(moduleName, mixPort.getName())
-                        .empty()) {
-                continue;  // no attached device
-            }
+            const auto attachedDeviceAddress =
+                    getCachedPolicyConfig().getDeviceAddressOfSourceDeviceAttachedToMixPort(
+                            moduleName, mixPort.getName());
+            if (!attachedDeviceAddress.has_value()) continue;
             std::vector<AudioInOutFlag> flags;
             if (mixPort.hasFlags()) {
                 std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
@@ -250,7 +251,8 @@
                 auto configs = combineAudioConfig(profile.getChannelMasks(),
                                                   profile.getSamplingRates(), profile.getFormat());
                 for (const auto& config : configs) {
-                    result.emplace_back(device, mixPort.getName(), config, flags);
+                    result.emplace_back(device, mixPort.getName(), attachedDeviceAddress.value(),
+                                        config, flags);
                     if (oneProfilePerDevice) break;
                 }
                 if (oneProfilePerDevice) break;
@@ -298,20 +300,25 @@
                             profile.getFormat(),
                             static_cast<uint32_t>(profile.getSamplingRates()[0]),
                             toString(profile.getChannelMasks()[0])};
+                    DeviceAddress defaultDevice = {
+                            toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT), {}};
                     {
                         AudioConfig config{.base = validBase};
                         config.base.channelMask = "random_string";
-                        result.emplace_back(device, mixPort.getName(), config, validFlags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            validFlags);
                     }
                     {
                         AudioConfig config{.base = validBase};
                         config.base.format = "random_string";
-                        result.emplace_back(device, mixPort.getName(), config, validFlags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            validFlags);
                     }
                     if (generateInvalidFlags) {
                         AudioConfig config{.base = validBase};
                         std::vector<AudioInOutFlag> flags = {"random_string", ""};
-                        result.emplace_back(device, mixPort.getName(), config, flags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            flags);
                     }
                     hasConfig = true;
                     break;
diff --git a/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h b/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h
index 4aea503..c1d5669 100644
--- a/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h
+++ b/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h
@@ -61,6 +61,18 @@
     const std::set<std::string>& getModulesWithDevicesNames() const {
         return mModulesWithDevicesNames;
     }
+    std::optional<DeviceAddress> getDeviceAddressOfSinkDeviceAttachedToMixPort(
+            const std::string& moduleName, const std::string& mixPortName) const {
+        const auto attachedDevicePort = getAttachedSinkDeviceForMixPort(moduleName, mixPortName);
+        if (attachedDevicePort.empty()) return {};
+        return getDeviceAddressOfDevicePort(moduleName, attachedDevicePort);
+    }
+    std::optional<DeviceAddress> getDeviceAddressOfSourceDeviceAttachedToMixPort(
+            const std::string& moduleName, const std::string& mixPortName) const {
+        const auto attachedDevicePort = getAttachedSourceDeviceForMixPort(moduleName, mixPortName);
+        if (attachedDevicePort.empty()) return {};
+        return getDeviceAddressOfDevicePort(moduleName, attachedDevicePort);
+    }
     std::string getAttachedSinkDeviceForMixPort(const std::string& moduleName,
                                                 const std::string& mixPortName) const {
         return findAttachedDevice(getAttachedDevices(moduleName),
@@ -84,8 +96,6 @@
     const std::vector<std::string>& getAttachedDevices(const std::string& moduleName) const;
     std::optional<DeviceAddress> getDeviceAddressOfDevicePort(
             const std::string& moduleName, const std::string& devicePortName) const;
-    std::string getDevicePortTagNameFromType(const std::string& moduleName,
-                                             const AudioDevice& deviceType) const;
     std::set<std::string> getSinkDevicesForMixPort(const std::string& moduleName,
                                                    const std::string& mixPortName) const;
     std::set<std::string> getSourceDevicesForMixPort(const std::string& moduleName,
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index c757032..5b0a7f2 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -190,6 +190,7 @@
     ],
     data: [
         ":audio_policy_configuration_V7_0",
+        "data/sine882hz3s.mp3",
     ],
     // Use test_config for vts suite.
     // TODO(b/146104851): Add auto-gen rules and remove it.
@@ -223,6 +224,7 @@
     ],
     data: [
         ":audio_policy_configuration_V7_1",
+        "data/sine882hz3s.mp3",
     ],
     // Use test_config for vts suite.
     // TODO(b/146104851): Add auto-gen rules and remove it.
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 38e9e5f..6c5584d 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -617,7 +617,8 @@
                     std::get<PARAM_FLAGS>(info.param)));
 #elif MAJOR_VERSION >= 7
     const auto configPart =
-            std::to_string(config.base.sampleRateHz) + "_" +
+            ::testing::PrintToString(std::get<PARAM_ATTACHED_DEV_ADDR>(info.param).deviceType) +
+            "_" + std::to_string(config.base.sampleRateHz) + "_" +
             // The channel masks and flags are vectors of strings, just need to sanitize them.
             SanitizeStringForGTestName(::testing::PrintToString(config.base.channelMask)) + "_" +
             SanitizeStringForGTestName(::testing::PrintToString(std::get<PARAM_FLAGS>(info.param)));
@@ -658,6 +659,9 @@
                 std::get<INDEX_OUTPUT>(std::get<PARAM_FLAGS>(GetParam())));
     }
 #elif MAJOR_VERSION >= 7
+    DeviceAddress getAttachedDeviceAddress() const {
+        return std::get<PARAM_ATTACHED_DEV_ADDR>(GetParam());
+    }
     hidl_vec<AudioInOutFlag> getInputFlags() const { return std::get<PARAM_FLAGS>(GetParam()); }
     hidl_vec<AudioInOutFlag> getOutputFlags() const { return std::get<PARAM_FLAGS>(GetParam()); }
 #endif
@@ -933,6 +937,14 @@
 
     StreamWriter(IStreamOut* stream, size_t bufferSize)
         : mStream(stream), mBufferSize(bufferSize), mData(mBufferSize) {}
+    StreamWriter(IStreamOut* stream, size_t bufferSize, std::vector<uint8_t>&& data,
+                 std::function<void()> onDataWrap)
+        : mStream(stream),
+          mBufferSize(bufferSize),
+          mData(std::move(data)),
+          mOnDataWrap(onDataWrap) {
+        ALOGW("StreamWriter data size: %d", (int)mData.size());
+    }
     ~StreamWriter() {
         stop();
         if (mEfGroup) {
@@ -998,9 +1010,11 @@
             ALOGE("command message queue write failed");
             return false;
         }
-        const size_t dataSize = std::min(mData.size(), mDataMQ->availableToWrite());
-        bool success = mDataMQ->write(mData.data(), dataSize);
+        const size_t dataSize = std::min(mData.size() - mDataPosition, mDataMQ->availableToWrite());
+        bool success = mDataMQ->write(mData.data() + mDataPosition, dataSize);
         ALOGE_IF(!success, "data message queue write failed");
+        mDataPosition += dataSize;
+        if (mDataPosition >= mData.size()) mDataPosition = 0;
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
 
         uint32_t efState = 0;
@@ -1026,6 +1040,7 @@
             ALOGE("bad wait status: %d", ret);
             success = false;
         }
+        if (success && mDataPosition == 0) mOnDataWrap();
         return success;
     }
 
@@ -1033,6 +1048,8 @@
     IStreamOut* const mStream;
     const size_t mBufferSize;
     std::vector<uint8_t> mData;
+    std::function<void()> mOnDataWrap = []() {};
+    size_t mDataPosition = 0;
     std::unique_ptr<CommandMQ> mCommandMQ;
     std::unique_ptr<DataMQ> mDataMQ;
     std::unique_ptr<StatusMQ> mStatusMQ;
@@ -1047,7 +1064,7 @@
 #if MAJOR_VERSION <= 6
         address.device = AudioDevice::OUT_DEFAULT;
 #elif MAJOR_VERSION >= 7
-        address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT);
+        address = getAttachedDeviceAddress();
 #endif
         const AudioConfig& config = getConfig();
         auto flags = getOutputFlags();
@@ -1243,16 +1260,11 @@
 #if MAJOR_VERSION <= 6
         address.device = AudioDevice::IN_DEFAULT;
 #elif MAJOR_VERSION >= 7
-        auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
-                getDeviceName(), getMixPortName());
+        address = getAttachedDeviceAddress();
         auto& metadata = initMetadata.tracks[0];
-        if (maybeSourceAddress.has_value() &&
-            !xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType)) {
-            address = maybeSourceAddress.value();
+        if (!xsd::isTelephonyDevice(address.deviceType)) {
             metadata.source = toString(xsd::AudioSource::AUDIO_SOURCE_UNPROCESSED);
             metadata.channelMask = getConfig().base.channelMask;
-        } else {
-            address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
         }
 #if MAJOR_VERSION == 7 && MINOR_VERSION >= 1
         auto flagsIt = std::find(flags.begin(), flags.end(),
diff --git a/audio/core/all-versions/vts/functional/AudioTestDefinitions.h b/audio/core/all-versions/vts/functional/AudioTestDefinitions.h
index 802b87b..3de06c3 100644
--- a/audio/core/all-versions/vts/functional/AudioTestDefinitions.h
+++ b/audio/core/all-versions/vts/functional/AudioTestDefinitions.h
@@ -39,9 +39,10 @@
         std::variant<android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::AudioInputFlag,
                      android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::AudioOutputFlag>>;
 #elif MAJOR_VERSION >= 7
-enum { PARAM_DEVICE, PARAM_PORT_NAME, PARAM_CONFIG, PARAM_FLAGS };
+enum { PARAM_DEVICE, PARAM_PORT_NAME, PARAM_ATTACHED_DEV_ADDR, PARAM_CONFIG, PARAM_FLAGS };
 using DeviceConfigParameter =
         std::tuple<DeviceParameter, std::string,
+                   android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::DeviceAddress,
                    android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::AudioConfig,
                    std::vector<android::hardware::audio::CORE_TYPES_CPP_VERSION::AudioInOutFlag>>;
 #endif
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
index f0e2695..8da5744 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
@@ -29,6 +29,7 @@
         <option name="cleanup" value="true" />
         <option name="push" value="VtsHalAudioV7_0TargetTest->/data/local/tmp/VtsHalAudioV7_0TargetTest" />
         <option name="push" value="audio_policy_configuration_V7_0.xsd->/data/local/tmp/audio_policy_configuration_V7_0.xsd" />
+        <option name="push" value="sine882hz3s.mp3->/data/local/tmp/sine882hz3s.mp3" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV7_1TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV7_1TargetTest.xml
index 7ce1477..227df18 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV7_1TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV7_1TargetTest.xml
@@ -29,6 +29,8 @@
         <option name="cleanup" value="true" />
         <option name="push" value="VtsHalAudioV7_1TargetTest->/data/local/tmp/VtsHalAudioV7_1TargetTest" />
         <option name="push" value="audio_policy_configuration_V7_1.xsd->/data/local/tmp/audio_policy_configuration_V7_1.xsd" />
+        <option name="push" value="sine882hz3s.mp3->/data/local/tmp/sine882hz3s.mp3" />
+
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
diff --git a/audio/core/all-versions/vts/functional/data/sine882hz3s.mp3 b/audio/core/all-versions/vts/functional/data/sine882hz3s.mp3
new file mode 100644
index 0000000..0604f9b
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/data/sine882hz3s.mp3
Binary files differ
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 9edd2bd..edc8949 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -1118,6 +1118,19 @@
                         },
                 .initialValue = {.stringValue = {"Test"}},
         },
+        // This property is later defined in the AIDL VHAL interface. However, HIDL VHAL might
+        // require support for this property to meet EU regulation.
+        {
+                .config =
+                        {
+                                // GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT
+                                .prop = 0x11400F47,
+                                .access = VehiclePropertyAccess::READ,
+                                .changeMode = VehiclePropertyChangeMode::STATIC,
+                        },
+                // GsrComplianceRequirementType::GSR_COMPLIANCE_REQUIRED_V1
+                .initialValue = {.int32Values = {1}},
+        },
 #ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
         // Vendor propetry for E2E ClusterHomeService testing.
         {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
index f01444e..74f5a7a 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
@@ -141,7 +141,7 @@
 TEST_F(DefaultVhalImplTest, testListProperties) {
     std::vector<VehiclePropConfig> configs = mHal->listProperties();
 
-    EXPECT_EQ((size_t)122, configs.size());
+    EXPECT_EQ((size_t)123, configs.size());
 }
 
 TEST_F(DefaultVhalImplTest, testGetDefaultPropertyFloat) {
diff --git a/automotive/vehicle/aidl/impl/Android.bp b/automotive/vehicle/aidl/impl/Android.bp
index 196f431..73f7df0 100644
--- a/automotive/vehicle/aidl/impl/Android.bp
+++ b/automotive/vehicle/aidl/impl/Android.bp
@@ -21,7 +21,7 @@
 cc_defaults {
     name: "VehicleHalInterfaceDefaults",
     static_libs: [
-        "android.hardware.automotive.vehicle-V1-ndk",
+        "android.hardware.automotive.vehicle-V2-ndk",
     ],
 }
 
diff --git a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
index f465dc0..409b932 100644
--- a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
+++ b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
@@ -36,6 +36,7 @@
 using ::aidl::android::hardware::automotive::vehicle::EvsServiceState;
 using ::aidl::android::hardware::automotive::vehicle::EvsServiceType;
 using ::aidl::android::hardware::automotive::vehicle::FuelType;
+using ::aidl::android::hardware::automotive::vehicle::GsrComplianceRequirementType;
 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
@@ -1255,6 +1256,19 @@
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                         },
         },
+        {
+                .config =
+                        {
+                                .prop = toInt(
+                                        VehicleProperty::
+                                                GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT),
+                                .access = VehiclePropertyAccess::READ,
+                                .changeMode = VehiclePropertyChangeMode::STATIC,
+                        },
+                .initialValue = {.int32Values = {toInt(
+                                         GsrComplianceRequirementType::
+                                                 GSR_COMPLIANCE_REQUIRED_THROUGH_SYSTEM_IMAGE)}},
+        },
 #ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
         // Vendor propetry for E2E ClusterHomeService testing.
         {
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index a7fcdcf..6af1223 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -26,6 +26,7 @@
 #include <aidl/android/hardware/automotive/vehicle/GetValueRequest.h>
 #include <aidl/android/hardware/automotive/vehicle/GetValueResult.h>
 #include <aidl/android/hardware/automotive/vehicle/GetValueResults.h>
+#include <aidl/android/hardware/automotive/vehicle/GsrComplianceRequirementType.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2CommonIgnitionMonitors.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2FuelSystemStatus.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2FuelType.h>
diff --git a/automotive/vehicle/vts/Android.bp b/automotive/vehicle/vts/Android.bp
index b78e0ff..1cfd542 100644
--- a/automotive/vehicle/vts/Android.bp
+++ b/automotive/vehicle/vts/Android.bp
@@ -44,6 +44,7 @@
     test_suites: [
         "general-tests",
         "vts",
+        "automotive-tests",
     ],
     require_root: true,
 }
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index c431d85..5de206b 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -48,6 +48,7 @@
 using ::android::getAidlHalInstanceNames;
 using ::android::base::ScopedLockAssertion;
 using ::android::base::StringPrintf;
+using ::android::frameworks::automotive::vhal::ErrorCode;
 using ::android::frameworks::automotive::vhal::HalPropError;
 using ::android::frameworks::automotive::vhal::IHalPropConfig;
 using ::android::frameworks::automotive::vhal::IHalPropValue;
@@ -287,7 +288,7 @@
     auto setValueResult = mVhalClient->setValueSync(*getValueResult.value());
 
     ASSERT_FALSE(setValueResult.ok()) << "Expect set a read-only value to fail";
-    ASSERT_EQ(setValueResult.error().code(), StatusCode::ACCESS_DENIED);
+    ASSERT_EQ(setValueResult.error().code(), ErrorCode::ACCESS_DENIED_FROM_VHAL);
 }
 
 // Test subscribe() and unsubscribe().
diff --git a/boot/1.1/default/boot_control/include/private/boot_control_definition.h b/boot/1.1/default/boot_control/include/private/boot_control_definition.h
index 8f02111..57c2f73 100644
--- a/boot/1.1/default/boot_control/include/private/boot_control_definition.h
+++ b/boot/1.1/default/boot_control/include/private/boot_control_definition.h
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <stdint.h>
+
+#include <bootloader_message/bootloader_message.h>
 
 /**
  * The A/B-specific bootloader message structure (4-KiB).
diff --git a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
index c38f257..05f136e 100644
--- a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
+++ b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
@@ -1,4 +1,5 @@
 /*
+
  * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +20,7 @@
 #include <vector>
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android/hardware/boot/1.1/IBootControl.h>
 #include <android/hardware/boot/1.1/types.h>
 #include <gmock/gmock.h>
@@ -37,9 +39,21 @@
 using ::android::hardware::boot::V1_1::MergeStatus;
 using ::testing::Contains;
 
+bool IsVirtualAbEnabled();
+
+#define SKIP_IF_NON_VIRTUAL_AB()                                                        \
+    do {                                                                                \
+        if (!IsVirtualAbEnabled()) GTEST_SKIP() << "Test for Virtual A/B devices only"; \
+    } while (0)
+
+bool IsVirtualAbEnabled() {
+    return android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
+}
+
 class BootHidlTest : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
+        SKIP_IF_NON_VIRTUAL_AB();
         boot = IBootControl::getService(GetParam());
         ASSERT_NE(boot, nullptr);
 
diff --git a/boot/aidl/client/Android.bp b/boot/aidl/client/Android.bp
new file mode 100644
index 0000000..db4a7ea
--- /dev/null
+++ b/boot/aidl/client/Android.bp
@@ -0,0 +1,31 @@
+
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library {
+    name: "libboot_control_client",
+    srcs: [
+        "BootControlClient.cpp"
+    ],
+    export_include_dirs: ["include"],
+    export_shared_lib_headers: ["android.hardware.boot-V1-ndk"],
+    recovery_available: true,
+    shared_libs: [
+        "android.hardware.boot-V1-ndk",
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
+        "android.hardware.boot@1.2",
+        "libhidlbase",
+        "libbinder_ndk",
+        "libbase",
+        "libcutils",
+        "libutils",
+    ],
+}
diff --git a/boot/aidl/client/BootControlClient.cpp b/boot/aidl/client/BootControlClient.cpp
new file mode 100644
index 0000000..89258d2
--- /dev/null
+++ b/boot/aidl/client/BootControlClient.cpp
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2022 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 <BootControlClient.h>
+
+#include <aidl/android/hardware/boot/IBootControl.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
+#include <android/hardware/boot/1.1/IBootControl.h>
+#include <android/hardware/boot/1.2/IBootControl.h>
+#include "utils/StrongPointer.h"
+
+#define CONCAT(x, y) x##y
+
+#define LOG_NDK_STATUS(x)                                                                   \
+    do {                                                                                    \
+        const auto CONCAT(status, __COUNTER__) = x;                                         \
+        if (!CONCAT(status, __COUNTER__).isOk()) {                                          \
+            LOG(ERROR) << #x << " failed " << CONCAT(status, __COUNTER__).getDescription(); \
+        }                                                                                   \
+    } while (0)
+
+using aidl::android::hardware::boot::MergeStatus;
+
+std::ostream& operator<<(std::ostream& os, MergeStatus status) {
+    switch (status) {
+        case MergeStatus::NONE:
+            os << "MergeStatus::NONE";
+            break;
+        case MergeStatus::UNKNOWN:
+            os << "MergeStatus::UNKNOWN";
+            break;
+        case MergeStatus::SNAPSHOTTED:
+            os << "MergeStatus::SNAPSHOTTED";
+            break;
+        case MergeStatus::MERGING:
+            os << "MergeStatus::MERGING";
+            break;
+        case MergeStatus::CANCELLED:
+            os << "MergeStatus::CANCELLED";
+            break;
+        default:
+            os << static_cast<int>(status);
+            break;
+    }
+    return os;
+}
+
+namespace android::hal {
+class BootControlClientAidl final : public BootControlClient {
+    using IBootControl = ::aidl::android::hardware::boot::IBootControl;
+
+  public:
+    BootControlClientAidl(std::shared_ptr<IBootControl> module) : module_(module) {}
+
+    BootControlVersion GetVersion() const override { return BootControlVersion::BOOTCTL_AIDL; }
+
+    ~BootControlClientAidl() = default;
+    virtual int32_t GetNumSlots() const {
+        int32_t ret = -1;
+        LOG_NDK_STATUS(module_->getNumberSlots(&ret));
+        return ret;
+    }
+
+    int32_t GetCurrentSlot() const {
+        int32_t ret = -1;
+        LOG_NDK_STATUS(module_->getCurrentSlot(&ret));
+        return ret;
+    }
+    MergeStatus getSnapshotMergeStatus() const {
+        MergeStatus status = MergeStatus::UNKNOWN;
+        LOG_NDK_STATUS(module_->getSnapshotMergeStatus(&status));
+        return status;
+    }
+    std::string GetSuffix(int32_t slot) const {
+        std::string ret;
+        const auto status = module_->getSuffix(slot, &ret);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << status.getDescription();
+            return {};
+        }
+        return ret;
+    }
+
+    std::optional<bool> IsSlotBootable(int32_t slot) const {
+        bool ret = false;
+        const auto status = module_->isSlotBootable(slot, &ret);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << status.getDescription();
+            return {};
+        }
+        return ret;
+    }
+
+    CommandResult MarkSlotUnbootable(int32_t slot) {
+        const auto status = module_->setSlotAsUnbootable(slot);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << status.getDescription();
+        }
+        return {.success = status.isOk(), .errMsg = status.getDescription()};
+    }
+
+    CommandResult SetActiveBootSlot(int slot) {
+        const auto status = module_->setActiveBootSlot(slot);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << status.getDescription();
+        }
+        return {.success = status.isOk(), .errMsg = status.getDescription()};
+    }
+    int GetActiveBootSlot() const {
+        int ret = -1;
+        LOG_NDK_STATUS(module_->getActiveBootSlot(&ret));
+        return ret;
+    }
+
+    // Check if |slot| is marked boot successfully.
+    std::optional<bool> IsSlotMarkedSuccessful(int slot) const {
+        bool ret = false;
+        const auto status = module_->isSlotMarkedSuccessful(slot, &ret);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << status.getDescription();
+            return {};
+        }
+        return ret;
+    }
+
+    CommandResult MarkBootSuccessful() {
+        const auto status = module_->markBootSuccessful();
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << status.getDescription();
+        }
+        return {.success = status.isOk(), .errMsg = status.getDescription()};
+    }
+
+    CommandResult SetSnapshotMergeStatus(aidl::android::hardware::boot::MergeStatus merge_status) {
+        const auto status = module_->setSnapshotMergeStatus(merge_status);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")"
+                       << " failed " << status.getDescription();
+        }
+        return {.success = status.isOk(), .errMsg = status.getDescription()};
+    }
+
+  private:
+    const std::shared_ptr<IBootControl> module_;
+};
+
+using namespace android::hardware::boot;
+
+class BootControlClientHIDL final : public BootControlClient {
+  public:
+    BootControlClientHIDL(android::sp<V1_0::IBootControl> module_v1,
+                          android::sp<V1_1::IBootControl> module_v1_1,
+                          android::sp<V1_2::IBootControl> module_v1_2)
+        : module_v1_(module_v1), module_v1_1_(module_v1_1), module_v1_2_(module_v1_2) {
+        CHECK(module_v1_ != nullptr);
+    }
+    BootControlVersion GetVersion() const override {
+        if (module_v1_2_ != nullptr) {
+            return BootControlVersion::BOOTCTL_V1_2;
+        } else if (module_v1_1_ != nullptr) {
+            return BootControlVersion::BOOTCTL_V1_1;
+        } else {
+            return BootControlVersion::BOOTCTL_V1_0;
+        }
+    }
+    int32_t GetNumSlots() const {
+        const auto ret = module_v1_->getNumberSlots();
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+        }
+        return ret.withDefault(-1);
+    }
+
+    int32_t GetCurrentSlot() const {
+        const auto ret = module_v1_->getCurrentSlot();
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+        }
+        return ret.withDefault(-1);
+    }
+
+    std::string GetSuffix(int32_t slot) const {
+        std::string suffix;
+        const auto ret = module_v1_->getSuffix(
+                slot,
+                [&](const ::android::hardware::hidl_string& slotSuffix) { suffix = slotSuffix; });
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << ret.description();
+        }
+        return suffix;
+    }
+
+    std::optional<bool> IsSlotBootable(int32_t slot) const {
+        const auto ret = module_v1_->isSlotBootable(slot);
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << ret.description();
+            return {};
+        }
+        const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
+        if (bool_result == V1_0::BoolResult::INVALID_SLOT) {
+            return {};
+        }
+        return bool_result == V1_0::BoolResult::TRUE;
+    }
+
+    CommandResult MarkSlotUnbootable(int32_t slot) {
+        CommandResult result;
+        const auto ret =
+                module_v1_->setSlotAsUnbootable(slot, [&](const V1_0::CommandResult& error) {
+                    result.success = error.success;
+                    result.errMsg = error.errMsg;
+                });
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << ret.description();
+        }
+        return result;
+    }
+
+    CommandResult SetActiveBootSlot(int32_t slot) {
+        CommandResult result;
+        const auto ret = module_v1_->setActiveBootSlot(slot, [&](const V1_0::CommandResult& error) {
+            result.success = error.success;
+            result.errMsg = error.errMsg;
+        });
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << ret.description();
+        }
+        return result;
+    }
+
+    CommandResult MarkBootSuccessful() {
+        CommandResult result;
+        const auto ret = module_v1_->markBootSuccessful([&](const V1_0::CommandResult& error) {
+            result.success = error.success;
+            result.errMsg = error.errMsg;
+        });
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+        }
+        return result;
+    }
+
+    std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const {
+        const auto ret = module_v1_->isSlotMarkedSuccessful(slot);
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << ret.description();
+            return {};
+        }
+        const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
+        if (bool_result == V1_0::BoolResult::INVALID_SLOT) {
+            return {};
+        }
+        return bool_result == V1_0::BoolResult::TRUE;
+    }
+
+    MergeStatus getSnapshotMergeStatus() const {
+        if (module_v1_1_ == nullptr) {
+            LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.1";
+            return MergeStatus::UNKNOWN;
+        }
+        const auto ret = module_v1_1_->getSnapshotMergeStatus();
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+        }
+        return static_cast<MergeStatus>(
+                ret.withDefault(static_cast<V1_1::MergeStatus>(MergeStatus::UNKNOWN)));
+    }
+
+    CommandResult SetSnapshotMergeStatus(MergeStatus merge_status) {
+        if (module_v1_1_ == nullptr) {
+            return {.success = false,
+                    .errMsg = "setSnapshotMergeStatus is unsupported, requires at least boot v1.1"};
+        }
+        const auto ret =
+                module_v1_1_->setSnapshotMergeStatus(static_cast<V1_1::MergeStatus>(merge_status));
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")"
+                       << " failed " << ret.description();
+        }
+        return {.success = ret.isOk(), .errMsg = ret.description()};
+    }
+
+    int32_t GetActiveBootSlot() const {
+        if (module_v1_2_ == nullptr) {
+            LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.2";
+            return -1;
+        }
+        const auto ret = module_v1_2_->getActiveBootSlot();
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+        }
+        return ret.withDefault(-1);
+    }
+
+  private:
+    android::sp<V1_0::IBootControl> module_v1_;
+    android::sp<V1_1::IBootControl> module_v1_1_;
+    android::sp<V1_2::IBootControl> module_v1_2_;
+};
+
+std::unique_ptr<BootControlClient> BootControlClient::WaitForService() {
+    const auto instance_name =
+            std::string(::aidl::android::hardware::boot::IBootControl::descriptor) + "/default";
+
+    if (AServiceManager_isDeclared(instance_name.c_str())) {
+        auto module = ::aidl::android::hardware::boot::IBootControl::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(instance_name.c_str())));
+        if (module == nullptr) {
+            LOG(ERROR) << "AIDL " << instance_name
+                       << " is declared but waitForService returned nullptr.";
+            return nullptr;
+        }
+        LOG(INFO) << "Using AIDL version of IBootControl";
+        return std::make_unique<BootControlClientAidl>(module);
+    }
+    LOG(INFO) << "AIDL IBootControl not available, falling back to HIDL.";
+
+    android::sp<V1_0::IBootControl> v1_0_module;
+    android::sp<V1_1::IBootControl> v1_1_module;
+    android::sp<V1_2::IBootControl> v1_2_module;
+    v1_0_module = V1_0::IBootControl::getService();
+    if (v1_0_module == nullptr) {
+        LOG(ERROR) << "Error getting bootctrl v1.0 module.";
+        return nullptr;
+    }
+    v1_1_module = V1_1::IBootControl::castFrom(v1_0_module);
+    v1_2_module = V1_2::IBootControl::castFrom(v1_0_module);
+    if (v1_2_module != nullptr) {
+        LOG(INFO) << "Using HIDL version 1.2 of IBootControl";
+    } else if (v1_1_module != nullptr) {
+        LOG(INFO) << "Using HIDL version 1.1 of IBootControl";
+    } else {
+        LOG(INFO) << "Using HIDL version 1.0 of IBootControl";
+    }
+
+    return std::make_unique<BootControlClientHIDL>(v1_0_module, v1_1_module, v1_2_module);
+}
+
+}  // namespace android::hal
diff --git a/boot/aidl/client/include/BootControlClient.h b/boot/aidl/client/include/BootControlClient.h
new file mode 100644
index 0000000..472e82e
--- /dev/null
+++ b/boot/aidl/client/include/BootControlClient.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BOOT_CONTROL_CLIENT_H_
+#define __BOOT_CONTROL_CLIENT_H_
+
+#include <aidl/android/hardware/boot/MergeStatus.h>
+
+#include <stdint.h>
+
+#include <memory>
+#include <optional>
+
+namespace android::hal {
+
+struct CommandResult {
+    bool success;
+    std::string errMsg;
+    constexpr bool IsOk() const { return success; }
+};
+
+enum class BootControlVersion { BOOTCTL_V1_0, BOOTCTL_V1_1, BOOTCTL_V1_2, BOOTCTL_AIDL };
+
+class BootControlClient {
+  public:
+    using MergeStatus = aidl::android::hardware::boot::MergeStatus;
+    virtual ~BootControlClient() = default;
+    virtual BootControlVersion GetVersion() const = 0;
+    // Return the number of update slots in the system. A system will normally
+    // have two slots, named "A" and "B" in the documentation, but sometimes
+    // images running from other media can have only one slot, like some USB
+    // image. Systems with only one slot won't be able to update.
+    [[nodiscard]] virtual int32_t GetNumSlots() const = 0;
+
+    // Return the slot where we are running the system from. On success, the
+    // result is a number between 0 and GetNumSlots() - 1. Otherwise, log an error
+    // and return kInvalidSlot.
+    [[nodiscard]] virtual int32_t GetCurrentSlot() const = 0;
+
+    // Return string suffix for input slot. Usually, for slot 0 the suffix is _a, and for slot 1 the
+    // suffix is _b.
+    [[nodiscard]] virtual std::string GetSuffix(int32_t slot) const = 0;
+
+    // Returns whether the passed |slot| is marked as bootable. Returns false if
+    // the slot is invalid.
+    [[nodiscard]] virtual std::optional<bool> IsSlotBootable(int32_t slot) const = 0;
+
+    // Mark the specified slot unbootable. No other slot flags are modified.
+    // Returns true on success.
+    [[nodiscard]] virtual CommandResult MarkSlotUnbootable(int32_t slot) = 0;
+
+    // Set the passed |slot| as the preferred boot slot. Returns whether it
+    // succeeded setting the active slot. If succeeded, on next boot the
+    // bootloader will attempt to load the |slot| marked as active. Note that this
+    // method doesn't change the value of GetCurrentSlot() on the current boot.
+    // Return true if operation succeeded.
+    [[nodiscard]] virtual CommandResult SetActiveBootSlot(int32_t slot) = 0;
+
+    // Check if |slot| is marked boot successfully. Return empty optional if the RPC call failed.
+    [[nodiscard]] virtual std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const = 0;
+
+    // Mark boot as successful. Return an error message if operation failed.
+    [[nodiscard]] virtual CommandResult MarkBootSuccessful() = 0;
+
+    // Added in IBootControl v1.1
+    // Return the current merge status.
+    [[nodiscard]] virtual MergeStatus getSnapshotMergeStatus() const = 0;
+
+    // Set snapshot merge status, return true if succeeded.
+    [[nodiscard]] virtual CommandResult SetSnapshotMergeStatus(MergeStatus status) = 0;
+
+    // Added in IBootControl v1.2
+    // Get the active slot. In other words, the slot which will be used on
+    // next system reboot. This should match the |slot| parameter of last
+    // successful call to |SetActiveBootSlot|.
+    // Return 0xFFFFFFFF if underlying HAL doesn't support this operation.
+    [[nodiscard]] virtual int32_t GetActiveBootSlot() const = 0;
+
+    [[nodiscard]] static std::unique_ptr<BootControlClient> WaitForService();
+};
+
+}  // namespace android::hal
+
+#endif
diff --git a/boot/aidl/default/Android.bp b/boot/aidl/default/Android.bp
new file mode 100644
index 0000000..6aefae8
--- /dev/null
+++ b/boot/aidl/default/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.boot-service.default",
+    defaults: ["libboot_control_defaults"],
+    relative_install_path: "hw",
+    init_rc: ["boot-default.rc"],
+    vintf_fragments: ["boot-default.xml"],
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.boot@1.1",
+        "android.hardware.boot-V1-ndk",
+    ],
+    static_libs: [
+        "libboot_control",
+    ],
+    srcs: ["main.cpp", "BootControl.cpp"],
+}
diff --git a/boot/aidl/default/BootControl.cpp b/boot/aidl/default/BootControl.cpp
new file mode 100644
index 0000000..4e3c21b
--- /dev/null
+++ b/boot/aidl/default/BootControl.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 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 "BootControl.h"
+#include <cstdint>
+
+#include <android-base/logging.h>
+
+using HIDLMergeStatus = ::android::bootable::BootControl::MergeStatus;
+using ndk::ScopedAStatus;
+
+namespace aidl::android::hardware::boot {
+
+BootControl::BootControl() {
+    CHECK(impl_.Init());
+}
+
+ScopedAStatus BootControl::getActiveBootSlot(int32_t* _aidl_return) {
+    *_aidl_return = impl_.GetActiveBootSlot();
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getCurrentSlot(int32_t* _aidl_return) {
+    *_aidl_return = impl_.GetCurrentSlot();
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getNumberSlots(int32_t* _aidl_return) {
+    *_aidl_return = impl_.GetNumberSlots();
+    return ScopedAStatus::ok();
+}
+
+namespace {
+
+static constexpr MergeStatus ToAIDLMergeStatus(HIDLMergeStatus status) {
+    switch (status) {
+        case HIDLMergeStatus::NONE:
+            return MergeStatus::NONE;
+        case HIDLMergeStatus::UNKNOWN:
+            return MergeStatus::UNKNOWN;
+        case HIDLMergeStatus::SNAPSHOTTED:
+            return MergeStatus::SNAPSHOTTED;
+        case HIDLMergeStatus::MERGING:
+            return MergeStatus::MERGING;
+        case HIDLMergeStatus::CANCELLED:
+            return MergeStatus::CANCELLED;
+    }
+}
+
+static constexpr HIDLMergeStatus ToHIDLMergeStatus(MergeStatus status) {
+    switch (status) {
+        case MergeStatus::NONE:
+            return HIDLMergeStatus::NONE;
+        case MergeStatus::UNKNOWN:
+            return HIDLMergeStatus::UNKNOWN;
+        case MergeStatus::SNAPSHOTTED:
+            return HIDLMergeStatus::SNAPSHOTTED;
+        case MergeStatus::MERGING:
+            return HIDLMergeStatus::MERGING;
+        case MergeStatus::CANCELLED:
+            return HIDLMergeStatus::CANCELLED;
+    }
+}
+
+}
+
+ScopedAStatus BootControl::getSnapshotMergeStatus(MergeStatus* _aidl_return) {
+    *_aidl_return = ToAIDLMergeStatus(impl_.GetSnapshotMergeStatus());
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getSuffix(int32_t in_slot, std::string* _aidl_return) {
+    if (!impl_.IsValidSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+    }
+    *_aidl_return = impl_.GetSuffix(in_slot);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::isSlotBootable(int32_t in_slot, bool* _aidl_return) {
+    if (!impl_.IsValidSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+    }
+    *_aidl_return = impl_.IsSlotBootable(in_slot);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) {
+    if (!impl_.IsValidSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+    }
+    *_aidl_return = impl_.IsSlotMarkedSuccessful(in_slot);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::markBootSuccessful() {
+    if (!impl_.MarkBootSuccessful()) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+                                                                  "Operation failed");
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setActiveBootSlot(int32_t in_slot) {
+    if (!impl_.IsValidSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+    }
+    if (!impl_.SetActiveBootSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+                                                                  "Operation failed");
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setSlotAsUnbootable(int32_t in_slot) {
+    if (!impl_.IsValidSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+    }
+    if (!impl_.SetSlotAsUnbootable(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+                                                                  "Operation failed");
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setSnapshotMergeStatus(MergeStatus in_status) {
+    if (!impl_.SetSnapshotMergeStatus(ToHIDLMergeStatus(in_status))) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+                                                                  "Operation failed");
+    }
+    return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::boot
diff --git a/boot/aidl/default/BootControl.h b/boot/aidl/default/BootControl.h
new file mode 100644
index 0000000..54cd32d
--- /dev/null
+++ b/boot/aidl/default/BootControl.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/boot/BnBootControl.h>
+#include <libboot_control/libboot_control.h>
+
+namespace aidl::android::hardware::boot {
+
+class BootControl final : public BnBootControl {
+  public:
+    BootControl();
+    ::ndk::ScopedAStatus getActiveBootSlot(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getCurrentSlot(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getNumberSlots(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getSnapshotMergeStatus(
+            ::aidl::android::hardware::boot::MergeStatus* _aidl_return) override;
+    ::ndk::ScopedAStatus getSuffix(int32_t in_slot, std::string* _aidl_return) override;
+    ::ndk::ScopedAStatus isSlotBootable(int32_t in_slot, bool* _aidl_return) override;
+    ::ndk::ScopedAStatus isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) override;
+    ::ndk::ScopedAStatus markBootSuccessful() override;
+    ::ndk::ScopedAStatus setActiveBootSlot(int32_t in_slot) override;
+    ::ndk::ScopedAStatus setSlotAsUnbootable(int32_t in_slot) override;
+    ::ndk::ScopedAStatus setSnapshotMergeStatus(
+            ::aidl::android::hardware::boot::MergeStatus in_status) override;
+
+  private:
+    ::android::bootable::BootControl impl_;
+};
+
+}  // namespace aidl::android::hardware::boot
diff --git a/boot/aidl/default/boot-default.rc b/boot/aidl/default/boot-default.rc
new file mode 100644
index 0000000..589f803
--- /dev/null
+++ b/boot/aidl/default/boot-default.rc
@@ -0,0 +1,5 @@
+service vendor.boot-default /vendor/bin/hw/android.hardware.boot-service.default
+    class early_hal
+    user root
+    group root
+
diff --git a/boot/aidl/default/boot-default.xml b/boot/aidl/default/boot-default.xml
new file mode 100644
index 0000000..23ccc4e
--- /dev/null
+++ b/boot/aidl/default/boot-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.boot</name>
+        <fqname>IBootControl/default</fqname>
+    </hal>
+</manifest>
diff --git a/boot/aidl/default/main.cpp b/boot/aidl/default/main.cpp
new file mode 100644
index 0000000..70b284e
--- /dev/null
+++ b/boot/aidl/default/main.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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 "BootControl.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::boot::BootControl;
+using aidl::android::hardware::boot::IBootControl;
+
+int main(int, char* argv[]) {
+    android::base::InitLogging(argv, android::base::KernelLogger);
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<IBootControl> service = ndk::SharedRefBase::make<BootControl>();
+
+    const std::string instance = std::string(BootControl::descriptor) + "/default";
+    auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance << " " << status;
+    LOG(INFO) << "IBootControl AIDL service running...";
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/broadcastradio/1.0/default/OWNERS b/broadcastradio/1.0/default/OWNERS
index 57e6592..302fdd7 100644
--- a/broadcastradio/1.0/default/OWNERS
+++ b/broadcastradio/1.0/default/OWNERS
@@ -1,3 +1,4 @@
-elaurent@google.com
-mnaganov@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/broadcastradio/1.0/vts/functional/OWNERS b/broadcastradio/1.0/vts/functional/OWNERS
index 778c4a2..aa19d6a 100644
--- a/broadcastradio/1.0/vts/functional/OWNERS
+++ b/broadcastradio/1.0/vts/functional/OWNERS
@@ -1,2 +1,5 @@
 # Bug component: 533946
+xuweilin@google.com
 oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/broadcastradio/1.1/default/OWNERS b/broadcastradio/1.1/default/OWNERS
index 136b607..259b91e 100644
--- a/broadcastradio/1.1/default/OWNERS
+++ b/broadcastradio/1.1/default/OWNERS
@@ -1,3 +1,5 @@
 # Automotive team
-egranata@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/broadcastradio/1.1/vts/OWNERS b/broadcastradio/1.1/vts/OWNERS
index 2c21c25..aa19d6a 100644
--- a/broadcastradio/1.1/vts/OWNERS
+++ b/broadcastradio/1.1/vts/OWNERS
@@ -1,3 +1,5 @@
 # Bug component: 533946
+xuweilin@google.com
 oscarazu@google.com
+ericjeong@google.com
 keunyoung@google.com
diff --git a/broadcastradio/2.0/default/OWNERS b/broadcastradio/2.0/default/OWNERS
index 136b607..259b91e 100644
--- a/broadcastradio/2.0/default/OWNERS
+++ b/broadcastradio/2.0/default/OWNERS
@@ -1,3 +1,5 @@
 # Automotive team
-egranata@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/broadcastradio/2.0/vts/OWNERS b/broadcastradio/2.0/vts/OWNERS
index 1ff7407..09690ef 100644
--- a/broadcastradio/2.0/vts/OWNERS
+++ b/broadcastradio/2.0/vts/OWNERS
@@ -1,6 +1,8 @@
 # Automotive team
-egranata@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
 
 # VTS team
 dshi@google.com
diff --git a/broadcastradio/2.0/vts/functional/OWNERS b/broadcastradio/2.0/vts/functional/OWNERS
index 2c21c25..aa19d6a 100644
--- a/broadcastradio/2.0/vts/functional/OWNERS
+++ b/broadcastradio/2.0/vts/functional/OWNERS
@@ -1,3 +1,5 @@
 # Bug component: 533946
+xuweilin@google.com
 oscarazu@google.com
+ericjeong@google.com
 keunyoung@google.com
diff --git a/broadcastradio/common/OWNERS b/broadcastradio/common/OWNERS
index 136b607..259b91e 100644
--- a/broadcastradio/common/OWNERS
+++ b/broadcastradio/common/OWNERS
@@ -1,3 +1,5 @@
 # Automotive team
-egranata@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
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 bdaaf96..fb5048a 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -388,25 +388,28 @@
 }
 
 int get_vsr_api_level() {
-    int api_level = ::android::base::GetIntProperty("ro.board.api_level", -1);
-    if (api_level == -1) {
-        api_level = ::android::base::GetIntProperty("ro.board.first_api_level", -1);
+    int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
+    if (vendor_api_level != -1) {
+        return vendor_api_level;
     }
-    if (api_level == -1) {
-        api_level = ::android::base::GetIntProperty("ro.vndk.version", -1);
+
+    // Android S and older devices do not define ro.vendor.api_level
+    vendor_api_level = ::android::base::GetIntProperty("ro.board.api_level", -1);
+    if (vendor_api_level == -1) {
+        vendor_api_level = ::android::base::GetIntProperty("ro.board.first_api_level", -1);
     }
-    // We really should have a VSR API level by now.  But on cuttlefish, and perhaps other weird
-    // devices, we may not.  So, we use the SDK first or current API level if needed.  If this goes
-    // wrong, it should go wrong in the direction of being too strict rather than too lenient, which
-    // should provoke someone to examine why we don't have proper VSR API level properties.
-    if (api_level == -1) {
-        api_level = ::android::base::GetIntProperty("ro.product.first_api_level", -1);
+
+    int product_api_level = ::android::base::GetIntProperty("ro.product.first_api_level", -1);
+    if (product_api_level == -1) {
+        product_api_level = ::android::base::GetIntProperty("ro.build.version.sdk", -1);
+        EXPECT_NE(product_api_level, -1) << "Could not find ro.build.version.sdk";
     }
-    if (api_level == -1) {
-        api_level = ::android::base::GetIntProperty("ro.build.version.sdk", -1);
+
+    // VSR API level is the minimum of vendor_api_level and product_api_level.
+    if (vendor_api_level == -1 || vendor_api_level > product_api_level) {
+        return product_api_level;
     }
-    EXPECT_NE(api_level, -1) << "Could not find a VSR level, or equivalent.";
-    return api_level;
+    return vendor_api_level;
 }
 
 bool is_gsi() {
diff --git a/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
index 2ae9c2b..00e9837 100755
--- a/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
+++ b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
@@ -400,9 +400,18 @@
                             << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
                             << " not allowed for devices launching with Android T and above";
                 } else {
-                    ASSERT_LT(getFirstApiLevel(), __ANDROID_API_S__)
+                    std::string codecName = info.mName;
+                    bool isAndroidCodec = (codecName.rfind("OMX.google", 0) != std::string::npos);
+                    if (isAndroidCodec && (getFirstApiLevel() <= __ANDROID_API_S__)) {
+                        // refer b/230582620
+                        // S AOSP build did not remove the OMX.google video codecs
+                        // so it is infeasible to require no OMX.google.* video codecs
+                        // on S launching devices
+                    } else {
+                        ASSERT_LT(getFirstApiLevel(), __ANDROID_API_S__)
                             << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
                             << " not allowed for devices launching with Android S and above";
+                    }
                 }
             }
             if (role.find("audio_decoder") != std::string::npos ||
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 29b31d2..a41f37f 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -90,7 +90,6 @@
         "libneuralnetworks_headers",
     ],
     test_suites: [
-        "general-tests",
         "vts",
     ],
 }
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index e9d4b76..7c1c118 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -58,7 +58,6 @@
         "libneuralnetworks_headers",
     ],
     test_suites: [
-        "general-tests",
         "vts",
     ],
 }
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 2177924..7e4b5bb 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -85,7 +85,6 @@
         "libneuralnetworks_headers",
     ],
     test_suites: [
-        "general-tests",
         "vts",
     ],
 }
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index 9fa0f0a..07071cc 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -92,7 +92,6 @@
         "libneuralnetworks_headers",
     ],
     test_suites: [
-        "general-tests",
         "vts",
     ],
 }
diff --git a/neuralnetworks/TEST_MAPPING b/neuralnetworks/TEST_MAPPING
index d296828..3218206 100644
--- a/neuralnetworks/TEST_MAPPING
+++ b/neuralnetworks/TEST_MAPPING
@@ -17,54 +17,10 @@
     },
     {
       "name": "neuralnetworks_utils_hal_aidl_test"
-    },
-    {
-      "name": "VtsHalNeuralnetworksV1_0TargetTest",
-      "options": [
-        {
-          // Do not use any sample driver except sample-all in order to reduce
-          // testing time. The other sample drivers (fast-float, quant, etc.)
-          // are subsets of sample-all.
-          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
-        }
-      ]
-    },
-    {
-      "name": "VtsHalNeuralnetworksV1_1TargetTest",
-      "options": [
-        {
-          // Do not use any sample driver except sample-all in order to reduce
-          // testing time. The other sample drivers (fast-float, quant, etc.)
-          // are subsets of sample-all.
-          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
-        }
-      ]
     }
   ],
   "presubmit-large": [
     {
-      "name": "VtsHalNeuralnetworksV1_2TargetTest",
-      "options": [
-        {
-          // Do not use any sample driver except sample-all in order to reduce
-          // testing time. The other sample drivers (fast-float, quant, etc.)
-          // are subsets of sample-all.
-          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
-        }
-      ]
-    },
-    {
-      "name": "VtsHalNeuralnetworksV1_3TargetTest",
-      "options": [
-        {
-          // Do not use any sample driver except sample-all in order to reduce
-          // testing time. The other sample drivers (fast-float, quant, etc.)
-          // are subsets of sample-all.
-          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
-        }
-      ]
-    },
-    {
       "name": "VtsHalNeuralnetworksTargetTest",
       "options": [
         {
diff --git a/security/OWNERS b/security/OWNERS
index 54d820a..4142fc1 100644
--- a/security/OWNERS
+++ b/security/OWNERS
@@ -1,3 +1,6 @@
+# Please assign all bugs related to /hardware/interfaces/security to the team alias,
+# android-hardware-security@google.com.  This will get them auto-assigned to the on-call triage
+# engineer, ensuring quickest response.
 drysdale@google.com
 jbires@google.com
 jdanis@google.com
diff --git a/security/keymint/RKP_CHANGELOG.md b/security/keymint/RKP_CHANGELOG.md
new file mode 100644
index 0000000..67d68d4
--- /dev/null
+++ b/security/keymint/RKP_CHANGELOG.md
@@ -0,0 +1,18 @@
+# Remote Provisioning Changelog
+
+This document provides an exact description of which changes have occurred in the
+`IRemotelyProvisionedComponent` HAL interface in each Android release.
+
+## Releases
+* **Android S (12):** IRemotelyProvisionedComponent v1
+* **Android T (13):** IRemotelyProvisionedComponent v2
+
+## IRemotelyProvisionedComponent 1 -> 2
+* DeviceInfo
+ * Most entries are no longer optional.
+ * `att_id_state` is now `fused`. `fused` is used to indicate if SecureBoot is enabled.
+ * `version` is now `2`.
+ * `board` has been removed.
+ * `device` has been added.
+* RpcHardwareInfo
+ * `uniqueId` String added as a field in order to differentiate IRPC instances on device.
\ No newline at end of file
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index b9694e9..2caa4d5 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -336,6 +336,17 @@
      * Only Tag::KEY_SIZE is required to generate an 3DES key, and its value must be 168.  If
      * omitted, generateKey must return ErrorCode::UNSUPPORTED_KEY_SIZE.
      *
+     * == HMAC Keys ==
+     *
+     * Tag::KEY_SIZE must be provided to generate an HMAC key, and its value must be >= 64 and a
+     * multiple of 8.  All devices must support key sizes up to 512 bits, but StrongBox devices must
+     * not support key sizes larger than 512 bits.  If omitted or invalid, generateKey() must return
+     * ErrorCode::UNSUPPORTED_KEY_SIZE.
+     *
+     * Tag::MIN_MAC_LENGTH must be provided, and must be a multiple of 8 in the range 64 to 512
+     * bits (inclusive). If omitted, generateKey must return ErrorCode::MISSING_MIN_MAC_LENGTH; if
+     * invalid, generateKey must return ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH.
+     *
      * @param keyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
      *        provided in params.  See above for detailed specifications of which tags are required
      *        for which types of keys.
@@ -661,19 +672,19 @@
      *   structure, because it cannot add the DigestInfo structure.  Instead, the IKeyMintDevice
      *   must construct 0x00 || 0x01 || PS || 0x00 || M, where M is the provided message and PS is a
      *   random padding string at least eight bytes in length.  The size of the RSA key has to be at
-     *   least 11 bytes larger than the message, otherwise begin() must return
+     *   least 11 bytes larger than the message, otherwise finish() must return
      *   ErrorCode::INVALID_INPUT_LENGTH.
      *
      * o PaddingMode::RSA_PKCS1_1_1_5_ENCRYPT padding does not require a digest.
      *
-     * o PaddingMode::RSA_PSS padding requires a digest, which must match one of the padding values
+     * o PaddingMode::RSA_PSS padding requires a digest, which must match one of the digest values
      *   in the key authorizations, and which may not be Digest::NONE.  begin() must return
      *   ErrorCode::INCOMPATIBLE_DIGEST if this is not the case.  In addition, the size of the RSA
-     *   key must be at least 2 + D bytes larger than the output size of the digest, where D is the
-     *   size of the digest, in bytes.  Otherwise begin() must return
-     *   ErrorCode::INCOMPATIBLE_DIGEST.  The salt size must be D.
+     *   key must be at least (D + S + 9) bits, where D is the size of the digest (in bits) and
+     *   S is the size of the salt (in bits).  The salt size S must equal D, so the RSA key must
+     *   be at least (2*D + 9) bits. Otherwise begin() must return ErrorCode::INCOMPATIBLE_DIGEST.
      *
-     * o PaddingMode::RSA_OAEP padding requires a digest, which must match one of the padding values
+     * o PaddingMode::RSA_OAEP padding requires a digest, which must match one of the digest values
      *   in the key authorizations, and which may not be Digest::NONE.  begin() must return
      *   ErrorCode::INCOMPATIBLE_DIGEST if this is not the case.  RSA_OAEP padding also requires an
      *   MGF1 digest, specified with Tag::RSA_OAEP_MGF_DIGEST, which must match one of the MGF1
@@ -683,9 +694,9 @@
      *
      * -- EC Keys --
      *
-     * Private key operations (KeyPurpose::SIGN) need authorization of digest and padding, which
-     * means that the key authorizations must contain the specified values.  If not, begin() must
-     * return ErrorCode::INCOMPATIBLE_DIGEST.
+     * Private key operations (KeyPurpose::SIGN) need authorization of digest, which means that the
+     * key authorizations must contain the specified values.  If not, begin() must return
+     * ErrorCode::INCOMPATIBLE_DIGEST.
      *
      * -- AES Keys --
      *
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
index fd103ef..32e71a7 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
@@ -23,7 +23,7 @@
 @VintfStability
 @Backing(type="int")
 enum KeyPurpose {
-    /* Usable with RSA, 3DES and AES keys. */
+    /* Usable with 3DES and AES keys. */
     ENCRYPT = 0,
 
     /* Usable with RSA, 3DES and AES keys. */
@@ -32,7 +32,7 @@
     /* Usable with RSA, EC and HMAC keys. */
     SIGN = 2,
 
-    /* Usable with RSA, EC and HMAC keys. */
+    /* Usable with HMAC keys. */
     VERIFY = 3,
 
     /* 4 is reserved */
diff --git a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
index e71a9c9..6ff4b29 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
@@ -26,7 +26,7 @@
 @VintfStability
 @Backing(type="int")
 enum PaddingMode {
-    NONE = 1, /* deprecated */
+    NONE = 1,
     RSA_OAEP = 2,
     RSA_PSS = 3,
     RSA_PKCS1_1_5_ENCRYPT = 4,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index 42dfad5..871a1ac 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -186,10 +186,16 @@
      * Tag::RSA_OAEP_MGF_DIGEST specifies the MGF1 digest algorithms that may be used with RSA
      * encryption/decryption with OAEP padding.  Possible values are defined by the Digest enum.
      *
-     * This tag is repeatable for key generation/import.  RSA cipher operations with OAEP padding
-     * must specify an MGF1 digest in the params argument of begin(). If this tag is missing or the
-     * specified digest is not in the MGF1 digests associated with the key then begin operation must
-     * fail with ErrorCode::INCOMPATIBLE_MGF_DIGEST.
+     * This tag is repeatable for key generation/import.
+     *
+     * If the caller specifies an MGF1 digest in the params argument of begin(), that digest must be
+     * present as an RSA_OAEP_MGF_DIGEST value in the key characteristics (or the begin() operation
+     * must fail with ErrorCode::INCOMPATIBLE_MGF_DIGEST).
+     *
+     * If the caller does not specify an MGF1 digest in the params argument of begin(), a default
+     * MGF1 digest of SHA1 is used.  If the key characteristics have any explicitly specified values
+     * for RSA_OAEP_MGF_DIGEST, then SHA1 must be included (or the begin() operation must fail with
+     * ErrorCode::INCOMPATIBLE_MGF_DIGEST).
      *
      * Must be hardware-enforced.
      */
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 240de35..ca517ac 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "keymint_1_attest_key_test"
 #include <cutils/log.h>
+#include <cutils/properties.h>
 
 #include <keymint_support/key_param_output.h>
 #include <keymint_support/openssl_utils.h>
@@ -33,7 +34,33 @@
 
 }  // namespace
 
-using AttestKeyTest = KeyMintAidlTestBase;
+class AttestKeyTest : public KeyMintAidlTestBase {
+  protected:
+    ErrorCode GenerateAttestKey(const AuthorizationSet& key_desc,
+                                const optional<AttestationKey>& attest_key,
+                                vector<uint8_t>* key_blob,
+                                vector<KeyCharacteristics>* key_characteristics,
+                                vector<Certificate>* cert_chain) {
+        // The original specification for KeyMint v1 required ATTEST_KEY not be combined
+        // with any other key purpose, but the original VTS tests incorrectly did exactly that.
+        // This means that a device that launched prior to Android T (API level 33) may
+        // accept or even require KeyPurpose::SIGN too.
+        if (property_get_int32("ro.board.first_api_level", 0) < 33) {
+            AuthorizationSet key_desc_plus_sign = key_desc;
+            key_desc_plus_sign.push_back(TAG_PURPOSE, KeyPurpose::SIGN);
+
+            auto result = GenerateKey(key_desc_plus_sign, attest_key, key_blob, key_characteristics,
+                                      cert_chain);
+            if (result == ErrorCode::OK) {
+                return result;
+            }
+            // If the key generation failed, it may be because the device is (correctly)
+            // rejecting the combination of ATTEST_KEY+SIGN.  Fall through to try again with
+            // just ATTEST_KEY.
+        }
+        return GenerateKey(key_desc, attest_key, key_blob, key_characteristics, cert_chain);
+    }
+};
 
 /*
  * AttestKeyTest.AllRsaSizes
@@ -49,12 +76,13 @@
         AttestationKey attest_key;
         vector<KeyCharacteristics> attest_key_characteristics;
         vector<Certificate> attest_key_cert_chain;
-        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                     .RsaKey(size, 65537)
-                                                     .AttestKey()
-                                                     .SetDefaultValidity(),
-                                             {} /* attestation signing key */, &attest_key.keyBlob,
-                                             &attest_key_characteristics, &attest_key_cert_chain));
+        ASSERT_EQ(ErrorCode::OK,
+                  GenerateAttestKey(AuthorizationSetBuilder()
+                                            .RsaKey(size, 65537)
+                                            .AttestKey()
+                                            .SetDefaultValidity(),
+                                    {} /* attestation signing key */, &attest_key.keyBlob,
+                                    &attest_key_characteristics, &attest_key_cert_chain));
 
         ASSERT_GT(attest_key_cert_chain.size(), 0);
         EXPECT_EQ(attest_key_cert_chain.size(), 1);
@@ -227,17 +255,17 @@
     AttestationKey attest_key;
     vector<KeyCharacteristics> attest_key_characteristics;
     vector<Certificate> attest_key_cert_chain;
-    auto result = GenerateKey(AuthorizationSetBuilder()
-                                      .RsaKey(2048, 65537)
-                                      .AttestKey()
-                                      .AttestationChallenge(challenge)
-                                      .AttestationApplicationId(app_id)
-                                      .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                      .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                      .Authorization(TAG_NO_AUTH_REQUIRED)
-                                      .SetDefaultValidity(),
-                              {} /* attestation signing key */, &attest_key.keyBlob,
-                              &attest_key_characteristics, &attest_key_cert_chain);
+    auto result = GenerateAttestKey(AuthorizationSetBuilder()
+                                            .RsaKey(2048, 65537)
+                                            .AttestKey()
+                                            .AttestationChallenge(challenge)
+                                            .AttestationApplicationId(app_id)
+                                            .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                            .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                                            .SetDefaultValidity(),
+                                    {} /* attestation signing key */, &attest_key.keyBlob,
+                                    &attest_key_characteristics, &attest_key_cert_chain);
     // Strongbox may not support factory provisioned attestation key.
     if (SecLevel() == SecurityLevel::STRONGBOX) {
         if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
@@ -331,17 +359,17 @@
             attest_key_opt = attest_key;
         }
 
-        auto result = GenerateKey(AuthorizationSetBuilder()
-                                          .RsaKey(2048, 65537)
-                                          .AttestKey()
-                                          .AttestationChallenge("foo")
-                                          .AttestationApplicationId("bar")
-                                          .Authorization(TAG_NO_AUTH_REQUIRED)
-                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                          .SetDefaultValidity(),
-                                  attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                                  &cert_chain_list[i]);
+        auto result = GenerateAttestKey(AuthorizationSetBuilder()
+                                                .RsaKey(2048, 65537)
+                                                .AttestKey()
+                                                .AttestationChallenge("foo")
+                                                .AttestationApplicationId("bar")
+                                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                                .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                                .SetDefaultValidity(),
+                                        attest_key_opt, &key_blob_list[i],
+                                        &attested_key_characteristics, &cert_chain_list[i]);
         // Strongbox may not support factory provisioned attestation key.
         if (SecLevel() == SecurityLevel::STRONGBOX) {
             if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
@@ -408,17 +436,17 @@
             attest_key_opt = attest_key;
         }
 
-        auto result = GenerateKey(AuthorizationSetBuilder()
-                                          .EcdsaKey(EcCurve::P_256)
-                                          .AttestKey()
-                                          .AttestationChallenge("foo")
-                                          .AttestationApplicationId("bar")
-                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                          .Authorization(TAG_NO_AUTH_REQUIRED)
-                                          .SetDefaultValidity(),
-                                  attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                                  &cert_chain_list[i]);
+        auto result = GenerateAttestKey(AuthorizationSetBuilder()
+                                                .EcdsaKey(EcCurve::P_256)
+                                                .AttestKey()
+                                                .AttestationChallenge("foo")
+                                                .AttestationApplicationId("bar")
+                                                .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                                .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                .SetDefaultValidity(),
+                                        attest_key_opt, &key_blob_list[i],
+                                        &attested_key_characteristics, &cert_chain_list[i]);
         // Strongbox may not support factory provisioned attestation key.
         if (SecLevel() == SecurityLevel::STRONGBOX) {
             if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
@@ -513,29 +541,29 @@
         }
         ErrorCode result;
         if ((i & 0x1) == 1) {
-            result = GenerateKey(AuthorizationSetBuilder()
-                                         .EcdsaKey(EcCurve::P_256)
-                                         .AttestKey()
-                                         .AttestationChallenge("foo")
-                                         .AttestationApplicationId("bar")
-                                         .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                         .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                         .Authorization(TAG_NO_AUTH_REQUIRED)
-                                         .SetDefaultValidity(),
-                                 attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                                 &cert_chain_list[i]);
+            result = GenerateAttestKey(AuthorizationSetBuilder()
+                                               .EcdsaKey(EcCurve::P_256)
+                                               .AttestKey()
+                                               .AttestationChallenge("foo")
+                                               .AttestationApplicationId("bar")
+                                               .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                               .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .SetDefaultValidity(),
+                                       attest_key_opt, &key_blob_list[i],
+                                       &attested_key_characteristics, &cert_chain_list[i]);
         } else {
-            result = GenerateKey(AuthorizationSetBuilder()
-                                         .RsaKey(2048, 65537)
-                                         .AttestKey()
-                                         .AttestationChallenge("foo")
-                                         .AttestationApplicationId("bar")
-                                         .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                         .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                         .Authorization(TAG_NO_AUTH_REQUIRED)
-                                         .SetDefaultValidity(),
-                                 attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                                 &cert_chain_list[i]);
+            result = GenerateAttestKey(AuthorizationSetBuilder()
+                                               .RsaKey(2048, 65537)
+                                               .AttestKey()
+                                               .AttestationChallenge("foo")
+                                               .AttestationApplicationId("bar")
+                                               .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                               .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .SetDefaultValidity(),
+                                       attest_key_opt, &key_blob_list[i],
+                                       &attested_key_characteristics, &cert_chain_list[i]);
         }
         // Strongbox may not support factory provisioned attestation key.
         if (SecLevel() == SecurityLevel::STRONGBOX) {
@@ -581,12 +609,13 @@
         AttestationKey attest_key;
         vector<KeyCharacteristics> attest_key_characteristics;
         vector<Certificate> attest_key_cert_chain;
-        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                     .RsaKey(size, 65537)
-                                                     .AttestKey()
-                                                     .SetDefaultValidity(),
-                                             {} /* attestation signing key */, &attest_key.keyBlob,
-                                             &attest_key_characteristics, &attest_key_cert_chain));
+        ASSERT_EQ(ErrorCode::OK,
+                  GenerateAttestKey(AuthorizationSetBuilder()
+                                            .RsaKey(size, 65537)
+                                            .AttestKey()
+                                            .SetDefaultValidity(),
+                                    {} /* attestation signing key */, &attest_key.keyBlob,
+                                    &attest_key_characteristics, &attest_key_cert_chain));
 
         EXPECT_EQ(attest_key_cert_chain.size(), 1);
         EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on size " << size;
@@ -630,7 +659,7 @@
         vector<Certificate> attest_key_cert_chain;
         ASSERT_EQ(
                 ErrorCode::OK,
-                GenerateKey(
+                GenerateAttestKey(
                         AuthorizationSetBuilder().EcdsaKey(curve).AttestKey().SetDefaultValidity(),
                         {} /* attestation signing key */, &attest_key.keyBlob,
                         &attest_key_characteristics, &attest_key_cert_chain));
@@ -752,12 +781,13 @@
     AttestationKey attest_key;
     vector<KeyCharacteristics> attest_key_characteristics;
     vector<Certificate> attest_key_cert_chain;
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .EcdsaKey(EcCurve::P_256)
-                                                 .AttestKey()
-                                                 .SetDefaultValidity(),
-                                         {} /* attestation signing key */, &attest_key.keyBlob,
-                                         &attest_key_characteristics, &attest_key_cert_chain));
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateAttestKey(AuthorizationSetBuilder()
+                                        .EcdsaKey(EcCurve::P_256)
+                                        .AttestKey()
+                                        .SetDefaultValidity(),
+                                {} /* attestation signing key */, &attest_key.keyBlob,
+                                &attest_key_characteristics, &attest_key_cert_chain));
     attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
     ASSERT_GT(attest_key_cert_chain.size(), 0);
     EXPECT_EQ(attest_key_cert_chain.size(), 1);
@@ -816,12 +846,13 @@
     AttestationKey attest_key;
     vector<KeyCharacteristics> attest_key_characteristics;
     vector<Certificate> attest_key_cert_chain;
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .EcdsaKey(EcCurve::P_256)
-                                                 .AttestKey()
-                                                 .SetDefaultValidity(),
-                                         {} /* attestation signing key */, &attest_key.keyBlob,
-                                         &attest_key_characteristics, &attest_key_cert_chain));
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateAttestKey(AuthorizationSetBuilder()
+                                        .EcdsaKey(EcCurve::P_256)
+                                        .AttestKey()
+                                        .SetDefaultValidity(),
+                                {} /* attestation signing key */, &attest_key.keyBlob,
+                                &attest_key_characteristics, &attest_key_cert_chain));
     attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
     ASSERT_GT(attest_key_cert_chain.size(), 0);
     EXPECT_EQ(attest_key_cert_chain.size(), 1);
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 33945fd..46db4f0 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -1461,25 +1461,28 @@
 }
 
 int get_vsr_api_level() {
-    int api_level = ::android::base::GetIntProperty("ro.board.api_level", -1);
-    if (api_level == -1) {
-        api_level = ::android::base::GetIntProperty("ro.board.first_api_level", -1);
+    int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
+    if (vendor_api_level != -1) {
+        return vendor_api_level;
     }
-    if (api_level == -1) {
-        api_level = ::android::base::GetIntProperty("ro.vndk.version", -1);
+
+    // Android S and older devices do not define ro.vendor.api_level
+    vendor_api_level = ::android::base::GetIntProperty("ro.board.api_level", -1);
+    if (vendor_api_level == -1) {
+        vendor_api_level = ::android::base::GetIntProperty("ro.board.first_api_level", -1);
     }
-    // We really should have a VSR API level by now.  But on cuttlefish, and perhaps other weird
-    // devices, we may not.  So, we use the SDK first or current API level if needed.  If this goes
-    // wrong, it should go wrong in the direction of being too strict rather than too lenient, which
-    // should provoke someone to examine why we don't have proper VSR API level properties.
-    if (api_level == -1) {
-        api_level = ::android::base::GetIntProperty("ro.product.first_api_level", -1);
+
+    int product_api_level = ::android::base::GetIntProperty("ro.product.first_api_level", -1);
+    if (product_api_level == -1) {
+        product_api_level = ::android::base::GetIntProperty("ro.build.version.sdk", -1);
+        EXPECT_NE(product_api_level, -1) << "Could not find ro.build.version.sdk";
     }
-    if (api_level == -1) {
-        api_level = ::android::base::GetIntProperty("ro.build.version.sdk", -1);
+
+    // VSR API level is the minimum of vendor_api_level and product_api_level.
+    if (vendor_api_level == -1 || vendor_api_level > product_api_level) {
+        return product_api_level;
     }
-    EXPECT_NE(api_level, -1) << "Could not find a VSR level, or equivalent.";
-    return api_level;
+    return vendor_api_level;
 }
 
 bool is_gsi_image() {
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 371b589..7c398d3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -613,7 +613,7 @@
 class NewKeyGenerationTest : public KeyMintAidlTestBase {
   protected:
     void CheckBaseParams(const vector<KeyCharacteristics>& keyCharacteristics) {
-        AuthorizationSet auths = CheckCommonParams(keyCharacteristics);
+        AuthorizationSet auths = CheckCommonParams(keyCharacteristics, KeyOrigin::GENERATED);
         EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
 
         // Check that some unexpected tags/values are NOT present.
@@ -622,20 +622,21 @@
     }
 
     void CheckSymmetricParams(const vector<KeyCharacteristics>& keyCharacteristics) {
-        AuthorizationSet auths = CheckCommonParams(keyCharacteristics);
+        AuthorizationSet auths = CheckCommonParams(keyCharacteristics, KeyOrigin::GENERATED);
         EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::ENCRYPT));
         EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT));
 
         EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
     }
 
-    AuthorizationSet CheckCommonParams(const vector<KeyCharacteristics>& keyCharacteristics) {
+    AuthorizationSet CheckCommonParams(const vector<KeyCharacteristics>& keyCharacteristics,
+                                       const KeyOrigin expectedKeyOrigin) {
         // TODO(swillden): Distinguish which params should be in which auth list.
         AuthorizationSet auths;
         for (auto& entry : keyCharacteristics) {
             auths.push_back(AuthorizationSet(entry.authorizations));
         }
-        EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+        EXPECT_TRUE(auths.Contains(TAG_ORIGIN, expectedKeyOrigin));
 
         // Verify that App data, ROT and auth timeout are NOT included.
         EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST));
@@ -3801,7 +3802,7 @@
 // TODO(seleneh) add ExportKey to GenerateKey
 // check result
 
-class ImportKeyTest : public KeyMintAidlTestBase {
+class ImportKeyTest : public NewKeyGenerationTest {
   public:
     template <TagType tag_type, Tag tag, typename ValueT>
     void CheckCryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) {
@@ -4511,6 +4512,65 @@
     VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
 }
 
+/*
+ * ImportKeyTest.GetKeyCharacteristics
+ *
+ * Verifies that imported keys have the correct characteristics.
+ */
+TEST_P(ImportKeyTest, GetKeyCharacteristics) {
+    vector<uint8_t> key_blob;
+    vector<KeyCharacteristics> key_characteristics;
+    auto base_builder = AuthorizationSetBuilder()
+                                .Padding(PaddingMode::NONE)
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .SetDefaultValidity();
+    vector<Algorithm> algorithms = {Algorithm::RSA, Algorithm::EC, Algorithm::HMAC, Algorithm::AES,
+                                    Algorithm::TRIPLE_DES};
+    ErrorCode result;
+    string symKey = hex2str("a49d7564199e97cb529d2c9d97bf2f98");                   // 128 bits
+    string tdesKey = hex2str("a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358");  // 192 bits
+    for (auto alg : algorithms) {
+        SCOPED_TRACE(testing::Message() << "Algorithm-" << alg);
+        AuthorizationSetBuilder builder(base_builder);
+        switch (alg) {
+            case Algorithm::RSA:
+                builder.RsaSigningKey(2048, 65537).Digest(Digest::NONE);
+
+                result = ImportKey(builder, KeyFormat::PKCS8, rsa_2048_key, &key_blob,
+                                   &key_characteristics);
+                break;
+            case Algorithm::EC:
+                builder.EcdsaSigningKey(EcCurve::P_256).Digest(Digest::NONE);
+                result = ImportKey(builder, KeyFormat::PKCS8, ec_256_key, &key_blob,
+                                   &key_characteristics);
+                break;
+            case Algorithm::HMAC:
+                builder.HmacKey(128)
+                        .Digest(Digest::SHA_2_256)
+                        .Authorization(TAG_MIN_MAC_LENGTH, 128);
+                result =
+                        ImportKey(builder, KeyFormat::RAW, symKey, &key_blob, &key_characteristics);
+                break;
+            case Algorithm::AES:
+                builder.AesEncryptionKey(128).BlockMode(BlockMode::ECB);
+                result =
+                        ImportKey(builder, KeyFormat::RAW, symKey, &key_blob, &key_characteristics);
+                break;
+            case Algorithm::TRIPLE_DES:
+                builder.TripleDesEncryptionKey(168).BlockMode(BlockMode::ECB);
+                result = ImportKey(builder, KeyFormat::RAW, tdesKey, &key_blob,
+                                   &key_characteristics);
+                break;
+            default:
+                ADD_FAILURE() << "Invalid Algorithm " << uint32_t(alg);
+                continue;
+        }
+        ASSERT_EQ(ErrorCode::OK, result);
+        CheckCharacteristics(key_blob, key_characteristics);
+        CheckCommonParams(key_characteristics, KeyOrigin::IMPORTED);
+    }
+}
+
 INSTANTIATE_KEYMINT_AIDL_TEST(ImportKeyTest);
 
 auto wrapped_key = hex2str(
diff --git a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
index 8144699..b72f0de 100644
--- a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
+++ b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
@@ -33,9 +33,9 @@
     byte[] seed;
 
     /**
-     * A 32-byte value which is guaranteed to be different each time
-     * getSharedSecretParameters() is called.  Probabilistic uniqueness (i.e. random) is acceptable,
-     * though a stronger uniqueness guarantee (e.g. counter) is recommended where possible.
+     * A 32-byte value which is guaranteed to be different each time getSharedSecretParameters() is
+     * called after a restart.  Probabilistic uniqueness (i.e. random) is acceptable, though a
+     * stronger uniqueness guarantee (e.g. counter) is recommended where possible.
      */
     byte[] nonce;
 }
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 3e3a4d4..59b7939 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -144,9 +144,9 @@
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
     ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
     ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId, filterConf.getMqDesc));
-    mDvrTests.startPlaybackInputThread(dvrConf.playbackInputFile, dvrConf.settings.playback());
     ASSERT_TRUE(mDvrTests.startDvrPlayback());
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    mDvrTests.startPlaybackInputThread(dvrConf.playbackInputFile, dvrConf.settings.playback());
     ASSERT_TRUE(filterDataOutputTest());
     mDvrTests.stopPlaybackThread();
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
diff --git a/tv/tuner/aidl/default/Filter.cpp b/tv/tuner/aidl/default/Filter.cpp
index 769ebe2..1d56303 100644
--- a/tv/tuner/aidl/default/Filter.cpp
+++ b/tv/tuner/aidl/default/Filter.cpp
@@ -432,12 +432,12 @@
 
     if (mSharedAvMemHandle != nullptr) {
         *out_avMemory = ::android::dupToAidl(mSharedAvMemHandle);
-        *_aidl_return = BUFFER_SIZE_16M;
+        *_aidl_return = BUFFER_SIZE;
         mUsingSharedAvMem = true;
         return ::ndk::ScopedAStatus::ok();
     }
 
-    int av_fd = createAvIonFd(BUFFER_SIZE_16M);
+    int av_fd = createAvIonFd(BUFFER_SIZE);
     if (av_fd < 0) {
         return ::ndk::ScopedAStatus::fromServiceSpecificError(
                 static_cast<int32_t>(Result::OUT_OF_MEMORY));
@@ -454,7 +454,7 @@
     mUsingSharedAvMem = true;
 
     *out_avMemory = ::android::dupToAidl(mSharedAvMemHandle);
-    *_aidl_return = BUFFER_SIZE_16M;
+    *_aidl_return = BUFFER_SIZE;
     return ::ndk::ScopedAStatus::ok();
 }
 
@@ -1168,7 +1168,7 @@
     mediaEvent.isPesPrivateData = true;
     mediaEvent.extraMetaData.set<DemuxFilterMediaEventExtraMetaData::Tag::audio>(audio);
 
-    int av_fd = createAvIonFd(BUFFER_SIZE_16M);
+    int av_fd = createAvIonFd(BUFFER_SIZE);
     if (av_fd == -1) {
         return;
     }
diff --git a/tv/tuner/aidl/default/Filter.h b/tv/tuner/aidl/default/Filter.h
index e301249..c559862 100644
--- a/tv/tuner/aidl/default/Filter.h
+++ b/tv/tuner/aidl/default/Filter.h
@@ -50,7 +50,9 @@
 using ::android::hardware::EventFlag;
 
 using FilterMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
-const uint32_t BUFFER_SIZE_16M = 0x1000000;
+// Large buffer size can lead to sudden crashes due to being de-allocated
+// by the memory management system. Change the buffer size when needed.
+const uint32_t BUFFER_SIZE = 0x800000;  // 8 MB
 
 class Demux;
 class Dvr;
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index 189f5fd..e0118cd 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -263,6 +263,9 @@
                         break;
                     case FrontendTypeEnum::ATSC:
                         type = FrontendType::ATSC;
+                        frontendMap[id].settings.set<
+                            FrontendSettings::Tag::atsc>(
+                                readAtscFrontendSettings(feConfig));
                         break;
                     case FrontendTypeEnum::ATSC3:
                         type = FrontendType::ATSC3;
@@ -283,6 +286,9 @@
                     }
                     case FrontendTypeEnum::ISDBS:
                         type = FrontendType::ISDBS;
+                        frontendMap[id].settings.set<
+                            FrontendSettings::Tag::isdbs>(
+                                readIsdbsFrontendSettings(feConfig));
                         break;
                     case FrontendTypeEnum::ISDBS3:
                         type = FrontendType::ISDBS3;
@@ -691,6 +697,52 @@
         return dvbsSettings;
     }
 
+    static FrontendAtscSettings readAtscFrontendSettings(Frontend& feConfig) {
+      ALOGW("[ConfigReader] fe type is atsc");
+      FrontendAtscSettings atscSettings{
+          .frequency = (int64_t) feConfig.getFrequency(),
+      };
+      if (feConfig.hasEndFrequency()) {
+        atscSettings.endFrequency = (int64_t) feConfig.getEndFrequency();
+      }
+      if (!feConfig.hasAtscFrontendSettings_optional()) {
+        ALOGW("[ConfigReader] no more atsc settings");
+        return atscSettings;
+      }
+      auto atsc = feConfig.getFirstAtscFrontendSettings_optional();
+      atscSettings.inversion = static_cast<FrontendSpectralInversion>(
+          atsc->getInversion());
+      atscSettings.modulation = static_cast<FrontendAtscModulation>(
+          atsc->getModulation());
+      return atscSettings;
+    }
+
+    static FrontendIsdbsSettings readIsdbsFrontendSettings(Frontend &feConfig) {
+      ALOGW("[ConfigReader] fe type is isdbs");
+      FrontendIsdbsSettings isdbsSettings{
+              .frequency = (int64_t)feConfig.getFrequency()
+      };
+      if (feConfig.hasEndFrequency()) {
+            isdbsSettings.endFrequency = (int64_t)feConfig.getEndFrequency();
+      }
+      if (!feConfig.hasIsdbsFrontendSettings_optional()) {
+            ALOGW("[ConfigReader] no more isdbs settings");
+            return isdbsSettings;
+      }
+      auto isdbs = feConfig.getFirstIsdbsFrontendSettings_optional();
+      isdbsSettings.streamId = (int32_t)isdbs->getStreamId();
+      isdbsSettings.symbolRate = (int32_t)isdbs->getSymbolRate();
+      isdbsSettings.modulation = static_cast<FrontendIsdbsModulation>(
+          isdbs->getModulation());
+      isdbsSettings.coderate = static_cast<FrontendIsdbsCoderate>(
+          isdbs->getCoderate());
+      isdbsSettings.rolloff = static_cast<FrontendIsdbsRolloff>(
+          isdbs->getRolloff());
+      isdbsSettings.streamIdType = static_cast<FrontendIsdbsStreamIdType>(
+          isdbs->getStreamIdType());
+      return isdbsSettings;
+    }
+
     static bool readFilterTypeAndSettings(Filter filterConfig, DemuxFilterType& type,
                                           DemuxFilterSettings& settings) {
         auto mainType = filterConfig.getMainType();
diff --git a/tv/tuner/config/api/current.txt b/tv/tuner/config/api/current.txt
index 383d49f..aa7b88c 100644
--- a/tv/tuner/config/api/current.txt
+++ b/tv/tuner/config/api/current.txt
@@ -1,6 +1,14 @@
 // Signature format: 2.0
 package android.media.tuner.testing.configuration.V1_0 {
 
+  public class AtscFrontendSettings {
+    ctor public AtscFrontendSettings();
+    method @Nullable public java.math.BigInteger getInversion();
+    method @Nullable public java.math.BigInteger getModulation();
+    method public void setInversion(@Nullable java.math.BigInteger);
+    method public void setModulation(@Nullable java.math.BigInteger);
+  }
+
   public class AvFilterSettings {
     ctor public AvFilterSettings();
     method @Nullable public short getAudioStreamType_optional();
@@ -310,6 +318,7 @@
 
   public class Frontend {
     ctor public Frontend();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.AtscFrontendSettings getAtscFrontendSettings_optional();
     method @Nullable public java.math.BigInteger getConnectToCicamId();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.DvbsFrontendSettings getDvbsFrontendSettings_optional();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.DvbtFrontendSettings getDvbtFrontendSettings_optional();
@@ -317,8 +326,10 @@
     method @Nullable public java.math.BigInteger getFrequency();
     method @Nullable public String getId();
     method @Nullable public boolean getIsSoftwareFrontend();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.IsdbsFrontendSettings getIsdbsFrontendSettings_optional();
     method @Nullable public java.math.BigInteger getRemoveOutputPid();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum getType();
+    method public void setAtscFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.AtscFrontendSettings);
     method public void setConnectToCicamId(@Nullable java.math.BigInteger);
     method public void setDvbsFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.DvbsFrontendSettings);
     method public void setDvbtFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.DvbtFrontendSettings);
@@ -326,6 +337,7 @@
     method public void setFrequency(@Nullable java.math.BigInteger);
     method public void setId(@Nullable String);
     method public void setIsSoftwareFrontend(@Nullable boolean);
+    method public void setIsdbsFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.IsdbsFrontendSettings);
     method public void setRemoveOutputPid(@Nullable java.math.BigInteger);
     method public void setType(@Nullable android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum);
   }
@@ -422,6 +434,22 @@
     method public void setSrcPort(@Nullable long);
   }
 
+  public class IsdbsFrontendSettings {
+    ctor public IsdbsFrontendSettings();
+    method @Nullable public java.math.BigInteger getCoderate();
+    method @Nullable public java.math.BigInteger getModulation();
+    method @Nullable public java.math.BigInteger getRolloff();
+    method @Nullable public java.math.BigInteger getStreamId();
+    method @Nullable public java.math.BigInteger getStreamIdType();
+    method @Nullable public java.math.BigInteger getSymbolRate();
+    method public void setCoderate(@Nullable java.math.BigInteger);
+    method public void setModulation(@Nullable java.math.BigInteger);
+    method public void setRolloff(@Nullable java.math.BigInteger);
+    method public void setStreamId(@Nullable java.math.BigInteger);
+    method public void setStreamIdType(@Nullable java.math.BigInteger);
+    method public void setSymbolRate(@Nullable java.math.BigInteger);
+  }
+
   public class Lnb {
     ctor public Lnb();
     method @Nullable public String getId();
diff --git a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
index 59abd9a..282433e 100644
--- a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
+++ b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
@@ -80,6 +80,18 @@
         <xs:attribute name="scanType" type="dvbsScanType" use="optional"/>
         <xs:attribute name="isDiseqcRxMessage" type="xs:boolean" use="optional"/>
     </xs:complexType>
+    <xs:complexType name="atscFrontendSettings">
+        <xs:attribute name="inversion" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="modulation" type="xs:nonNegativeInteger" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="isdbsFrontendSettings">
+        <xs:attribute name="streamId" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="symbolRate" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="streamIdType" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="modulation" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="coderate" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="rolloff" type="xs:nonNegativeInteger" use="required"/>
+    </xs:complexType>
 
     <xs:complexType name="frontend">
         <xs:annotation>
@@ -109,14 +121,14 @@
         </xs:annotation>
         <xs:choice minOccurs="0" maxOccurs="1">
             <!-- TODO: b/182519645 finish all the frontend settings structures. -->
-            <!--xs:element name="analog" type="analogSettings"/>
-            <xs:element name="atsc" type="atscSettings"/>
-            <xs:element name="atsc3" type="atsc3Settings"/>
+            <!--xs:element name="analog" type="analogSettings"/-->
+            <xs:element name="atscFrontendSettings" type="atscFrontendSettings"/>
+            <!--xs:element name="atsc3" type="atsc3Settings"/>
             <xs:element name="dvbc" type="dvbcSettings"/-->
             <xs:element name="dvbsFrontendSettings" type="dvbsFrontendSettings"/>
             <xs:element name="dvbtFrontendSettings" type="dvbtFrontendSettings"/>
-            <!--xs:element name="isdbs" type="isdbsSettings"/>
-            <xs:element name="isdbs3" type="isdbs3Settings"/>
+            <xs:element name="isdbsFrontendSettings" type="isdbsFrontendSettings"/>
+            <!--xs:element name="isdbs3" type="isdbs3Settings"/>
             <xs:element name="isdbt" type="isdbtSettings"/>
             <xs:element name="dtmb" type="dtmbSettings"/-->
         </xs:choice>
diff --git a/uwb/aidl/Android.bp b/uwb/aidl/Android.bp
index 52f0605..7dc2b7f 100755
--- a/uwb/aidl/Android.bp
+++ b/uwb/aidl/Android.bp
@@ -47,6 +47,7 @@
 
 aidl_interface {
     name: "android.hardware.uwb.fira_android",
+    owner: "google",
     vendor_available: true,
     srcs: ["android/hardware/uwb/fira_android/*.aidl"],
     stability: "vintf",
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index cbe2068..cd08671 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -44,4 +44,7 @@
   CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 166,
   CCC_SUPPORTED_RAN_MULTIPLIER = 167,
   SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 227,
+  SUPPORTED_MIN_RANGING_INTERVAL_MS = 228,
+  SUPPORTED_RANGE_DATA_NTF_CONFIG = 229,
+  SUPPORTED_RSSI_REPORTING = 230,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 0140fdd..556bd13 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -150,4 +150,25 @@
      *  0 - Feature not supported.
      */
     SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xE3,
+
+    /**
+     * 4 byte value to indicate supported min ranging interval in ms.
+     */
+    SUPPORTED_MIN_RANGING_INTERVAL_MS = 0xE4,
+
+    /**
+     * 4 byte bitmask to indicate the supported RANGE_DATA_NTF_CONFIG values
+     *
+     * Bitmask where each bit corresponds to values used in
+     * RANGE_DATA_NTF_CONFIG in SET_APP_CFG_CMD
+     */
+    SUPPORTED_RANGE_DATA_NTF_CONFIG = 0xE5,
+
+    /**
+     * 1 byte bitmask to indicate the supported RSSI_REPORTING values
+     * Values:
+     * 1 - Feature supported.
+     * 0 - Feature not supported.
+     */
+    SUPPORTED_RSSI_REPORTING = 0xE6,
 }
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
index eabbf1b..da3ff3a 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
@@ -38,11 +38,12 @@
     : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        // Stop Wi-Fi
-        ASSERT_TRUE(stopWifiFramework());  // stop & wait for wifi to shutdown.
-
         wifi_instance_name_ = std::get<0>(GetParam());
         supplicant_instance_name_ = std::get<1>(GetParam());
+
+        // Stop & wait for wifi to shutdown.
+        ASSERT_TRUE(stopWifiFramework(wifi_instance_name_));
+
         std::system("/system/bin/start");
         ASSERT_TRUE(waitForFrameworkReady());
         isP2pOn_ =
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index 086166a..6760663 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -28,26 +28,42 @@
 
 using ::android::sp;
 using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::joinRpcThreadpool;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::joinRpcThreadpool;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hardware::wifi::V1_0::ChipModeId;
-using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantNetwork;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
-using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
-using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiChip;
 using ::android::wifi_system::InterfaceTool;
 using ::android::wifi_system::SupplicantManager;
 
 namespace {
+
+bool waitForWifiHalStop(const std::string& wifi_instance_name) {
+    sp<IWifi> wifi = getWifi(wifi_instance_name);
+    int count = 50; /* wait at most 5 seconds for completion */
+    while (count-- > 0) {
+        if (wifi != nullptr && !wifi->isStarted()) {
+            return true;
+        }
+        usleep(100000);
+        wifi = getWifi(wifi_instance_name);
+    }
+    LOG(ERROR) << "Wifi HAL was not stopped";
+    return false;
+}
+
 bool waitForSupplicantState(bool is_running) {
     SupplicantManager supplicant_manager;
     int count = 50; /* wait at most 5 seconds for completion */
@@ -113,10 +129,10 @@
     return waitForSupplicantStart();  // wait for wifi to start.
 }
 
-bool stopWifiFramework() {
+bool stopWifiFramework(const std::string& wifi_instance_name) {
     std::system("svc wifi disable");
     std::system("cmd wifi set-scan-always-available disabled");
-    return waitForSupplicantStop();  // wait for wifi to shutdown.
+    return waitForSupplicantStop() && waitForWifiHalStop(wifi_instance_name);
 }
 
 void stopSupplicant() { stopSupplicant(""); }
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
index 7228623..2198d7c 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
@@ -33,7 +33,7 @@
 bool startWifiFramework();
 
 // Used to stop the android wifi framework before every test.
-bool stopWifiFramework();
+bool stopWifiFramework(const std::string& wifi_instance_name);
 
 void stopSupplicant(const std::string& wifi_instance_name);
 // Used to configure the chip, driver and start wpa_supplicant before every
@@ -77,12 +77,13 @@
     : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        // Stop Wi-Fi
-        ASSERT_TRUE(stopWifiFramework());  // stop & wait for wifi to shutdown.
-
-        // should always be v1.0 wifi
-        wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+        wifi_v1_0_instance_name_ =
+            std::get<0>(GetParam());  // should always be v1.0 wifi
         supplicant_instance_name_ = std::get<1>(GetParam());
+
+        // Stop & wait for wifi to shutdown.
+        ASSERT_TRUE(stopWifiFramework(wifi_v1_0_instance_name_));
+
         std::system("/system/bin/start");
         ASSERT_TRUE(waitForFrameworkReady());
         isP2pOn_ =
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
index 17e0394..31042a2 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
@@ -78,7 +78,7 @@
 void stopSupplicantService() { stopSupplicant(getWifiInstanceName()); }
 
 void initializeService() {
-    ASSERT_TRUE(stopWifiFramework());
+    ASSERT_TRUE(stopWifiFramework(getWifiInstanceName()));
     std::system("/system/bin/start");
     ASSERT_TRUE(waitForFrameworkReady());
     stopSupplicantService();