Merge "Revert^2 "Add CAS HAL APEX"" into main
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index 9131935..b9f1131 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -461,6 +461,10 @@
 //    - no profiles specified
 //  * "Test In", IN_AFE_PROXY
 //    - no profiles specified
+//  * "Wired Headset", OUT_HEADSET
+//    - profile PCM 24-bit; STEREO; 48000
+//  * "Wired Headset Mic", IN_HEADSET
+//    - profile PCM 24-bit; MONO; 48000
 //
 // Mix ports:
 //  * "test output", 1 max open, 1 max active stream
@@ -476,7 +480,8 @@
 //
 // Routes:
 //  "test output", "test fast output", "test compressed offload" -> "Test Out"
-//  "Test In" -> "test input"
+//  "test output" -> "Wired Headset"
+//  "Test In", "Wired Headset Mic" -> "test input"
 //
 // Initial port configs:
 //  * "Test Out" device port: PCM 24-bit; STEREO; 48000
@@ -496,6 +501,14 @@
                                  AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
                                  createDeviceExt(AudioDeviceType::OUT_AFE_PROXY, 0)));
 
+        AudioPort headsetOutDevice =
+                createPort(c.nextPortId++, "Wired Headset", 0, false,
+                           createDeviceExt(AudioDeviceType::OUT_HEADSET, 0,
+                                           AudioDeviceDescription::CONNECTION_ANALOG));
+        headsetOutDevice.profiles.push_back(
+                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+        c.ports.push_back(headsetOutDevice);
+
         AudioPort testInDevice = createPort(c.nextPortId++, "Test In", 0, true,
                                             createDeviceExt(AudioDeviceType::IN_AFE_PROXY, 0));
         c.ports.push_back(testInDevice);
@@ -504,6 +517,14 @@
                                  AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
                                  createDeviceExt(AudioDeviceType::IN_AFE_PROXY, 0)));
 
+        AudioPort headsetInDevice =
+                createPort(c.nextPortId++, "Wired Headset Mic", 0, true,
+                           createDeviceExt(AudioDeviceType::IN_HEADSET, 0,
+                                           AudioDeviceDescription::CONNECTION_ANALOG));
+        headsetInDevice.profiles.push_back(
+                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_MONO}, {48000}));
+        c.ports.push_back(headsetInDevice);
+
         // Mix ports
 
         AudioPort testOutMix =
@@ -549,7 +570,8 @@
 
         c.routes.push_back(
                 createRoute({testOutMix, testFastOutMix, compressedOffloadOutMix}, testOutDevice));
-        c.routes.push_back(createRoute({testInDevice}, testInMIx));
+        c.routes.push_back(createRoute({testOutMix}, headsetOutDevice));
+        c.routes.push_back(createRoute({testInDevice, headsetInDevice}, testInMIx));
 
         c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
 
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index b7761bf..3117134 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -517,7 +517,7 @@
 
     connectedPort.id = ++getConfig().nextPortId;
     auto [connectedPortsIt, _] =
-            mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::vector<int32_t>()));
+            mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::set<int32_t>()));
     LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
                << "connected port ID " << connectedPort.id;
     ports.push_back(connectedPort);
@@ -550,9 +550,21 @@
     // of all profiles from all routable dynamic device ports would be more involved.
     for (const auto mixPortId : routablePortIds) {
         auto portsIt = findById<AudioPort>(ports, mixPortId);
-        if (portsIt != ports.end() && portsIt->profiles.empty()) {
-            portsIt->profiles = connectedPort.profiles;
-            connectedPortsIt->second.push_back(portsIt->id);
+        if (portsIt != ports.end()) {
+            if (portsIt->profiles.empty()) {
+                portsIt->profiles = connectedPort.profiles;
+                connectedPortsIt->second.insert(portsIt->id);
+            } else {
+                // Check if profiles are non empty because they were populated by
+                // a previous connection. Otherwise, it means that they are not empty because
+                // the mix port has static profiles.
+                for (const auto cp : mConnectedDevicePorts) {
+                    if (cp.second.count(portsIt->id) > 0) {
+                        connectedPortsIt->second.insert(portsIt->id);
+                        break;
+                    }
+                }
+            }
         }
     }
     *_aidl_return = std::move(connectedPort);
@@ -607,13 +619,20 @@
         }
     }
 
-    for (const auto mixPortId : connectedPortsIt->second) {
+    // Clear profiles for mix ports that are not connected to any other ports.
+    std::set<int32_t> mixPortsToClear = std::move(connectedPortsIt->second);
+    mConnectedDevicePorts.erase(connectedPortsIt);
+    for (const auto& connectedPort : mConnectedDevicePorts) {
+        for (int32_t mixPortId : connectedPort.second) {
+            mixPortsToClear.erase(mixPortId);
+        }
+    }
+    for (int32_t mixPortId : mixPortsToClear) {
         auto mixPortIt = findById<AudioPort>(ports, mixPortId);
         if (mixPortIt != ports.end()) {
             mixPortIt->profiles = {};
         }
     }
-    mConnectedDevicePorts.erase(connectedPortsIt);
 
     return ndk::ScopedAStatus::ok();
 }
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index fb3eef2..bfdab51 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -142,7 +142,7 @@
     // ids of device ports created at runtime via 'connectExternalDevice'.
     // Also stores a list of ids of mix ports with dynamic profiles that were populated from
     // the connected port. This list can be empty, thus an int->int multimap can't be used.
-    using ConnectedDevicePorts = std::map<int32_t, std::vector<int32_t>>;
+    using ConnectedDevicePorts = std::map<int32_t, std::set<int32_t>>;
     // Maps port ids and port config ids to patch ids.
     // Multimap because both ports and configs can be used by multiple patches.
     using Patches = std::multimap<int32_t, int32_t>;
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index f7cf4ce..a2f0260 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -26,7 +26,10 @@
         "libaudioaidlcommon",
         "libaidlcommonsupport",
     ],
-    header_libs: ["libaudioaidl_headers"],
+    header_libs: [
+        "libaudioaidl_headers",
+        "libexpectedutils_headers",
+    ],
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 8fdb155..af3597d 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -21,6 +21,7 @@
 #include <aidl/android/media/audio/common/AudioInputFlags.h>
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <error/expected_utils.h>
 
 #include "ModuleConfig.h"
 
@@ -499,18 +500,13 @@
     return result;
 }
 
-const ndk::ScopedAStatus& ModuleConfig::onExternalDeviceConnected(IModule* module,
-                                                                  const AudioPort& port) {
-    // Update ports and routes
-    mStatus = module->getAudioPorts(&mPorts);
-    if (!mStatus.isOk()) return mStatus;
-    mStatus = module->getAudioRoutes(&mRoutes);
-    if (!mStatus.isOk()) return mStatus;
+ndk::ScopedAStatus ModuleConfig::onExternalDeviceConnected(IModule* module, const AudioPort& port) {
+    RETURN_STATUS_IF_ERROR(module->getAudioPorts(&mPorts));
+    RETURN_STATUS_IF_ERROR(module->getAudioRoutes(&mRoutes));
 
     // Validate port is present in module
     if (std::find(mPorts.begin(), mPorts.end(), port) == mPorts.end()) {
-        mStatus = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-        return mStatus;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 
     if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) {
@@ -518,23 +514,20 @@
     } else {
         mConnectedExternalSinkDevicePorts.insert(port.id);
     }
-    return mStatus;
+    return ndk::ScopedAStatus::ok();
 }
 
-const ndk::ScopedAStatus& ModuleConfig::onExternalDeviceDisconnected(IModule* module,
-                                                                     const AudioPort& port) {
-    // Update ports and routes
-    mStatus = module->getAudioPorts(&mPorts);
-    if (!mStatus.isOk()) return mStatus;
-    mStatus = module->getAudioRoutes(&mRoutes);
-    if (!mStatus.isOk()) return mStatus;
+ndk::ScopedAStatus ModuleConfig::onExternalDeviceDisconnected(IModule* module,
+                                                              const AudioPort& port) {
+    RETURN_STATUS_IF_ERROR(module->getAudioPorts(&mPorts));
+    RETURN_STATUS_IF_ERROR(module->getAudioRoutes(&mRoutes));
 
     if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) {
         mConnectedExternalSourceDevicePorts.erase(port.id);
     } else {
         mConnectedExternalSinkDevicePorts.erase(port.id);
     }
-    return mStatus;
+    return ndk::ScopedAStatus::ok();
 }
 
 bool ModuleConfig::isMmapSupported() const {
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index bce1de1..0cbf24d 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -157,10 +157,10 @@
         return *config.begin();
     }
 
-    const ndk::ScopedAStatus& onExternalDeviceConnected(
+    ndk::ScopedAStatus onExternalDeviceConnected(
             aidl::android::hardware::audio::core::IModule* module,
             const aidl::android::media::audio::common::AudioPort& port);
-    const ndk::ScopedAStatus& onExternalDeviceDisconnected(
+    ndk::ScopedAStatus onExternalDeviceDisconnected(
             aidl::android::hardware::audio::core::IModule* module,
             const aidl::android::media::audio::common::AudioPort& port);
 
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 8958357..cd765d2 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -46,6 +46,7 @@
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 #include <android-base/chrono_utils.h>
 #include <android/binder_enums.h>
+#include <error/expected_utils.h>
 #include <fmq/AidlMessageQueue.h>
 
 #include "AudioHalBinderServiceUtil.h"
@@ -144,28 +145,36 @@
 }
 
 AudioPort GenerateUniqueDeviceAddress(const AudioPort& port) {
+    // Point-to-point connections do not use addresses.
+    static const std::set<std::string> kPointToPointConnections = {
+            AudioDeviceDescription::CONNECTION_ANALOG, AudioDeviceDescription::CONNECTION_HDMI,
+            AudioDeviceDescription::CONNECTION_HDMI_ARC,
+            AudioDeviceDescription::CONNECTION_HDMI_EARC, AudioDeviceDescription::CONNECTION_SPDIF};
     static int nextId = 0;
     using Tag = AudioDeviceAddress::Tag;
+    const auto& deviceDescription = port.ext.get<AudioPortExt::Tag::device>().device.type;
     AudioDeviceAddress address;
-    switch (suggestDeviceAddressTag(port.ext.get<AudioPortExt::Tag::device>().device.type)) {
-        case Tag::id:
-            address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
-            break;
-        case Tag::mac:
-            address = AudioDeviceAddress::make<Tag::mac>(
-                    std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
-            break;
-        case Tag::ipv4:
-            address = AudioDeviceAddress::make<Tag::ipv4>(
-                    std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
-            break;
-        case Tag::ipv6:
-            address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
-                    0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
-            break;
-        case Tag::alsa:
-            address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
-            break;
+    if (kPointToPointConnections.count(deviceDescription.connection) == 0) {
+        switch (suggestDeviceAddressTag(deviceDescription)) {
+            case Tag::id:
+                address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
+                break;
+            case Tag::mac:
+                address = AudioDeviceAddress::make<Tag::mac>(
+                        std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
+                break;
+            case Tag::ipv4:
+                address = AudioDeviceAddress::make<Tag::ipv4>(
+                        std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
+                break;
+            case Tag::ipv6:
+                address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
+                        0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
+                break;
+            case Tag::alsa:
+                address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
+                break;
+        }
     }
     AudioPort result = port;
     result.ext.get<AudioPortExt::Tag::device>().device.address = std::move(address);
@@ -412,9 +421,21 @@
 
     void SetUpImpl(const std::string& moduleName) {
         ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
+        ASSERT_IS_OK(module->getAudioPorts(&initialPorts));
+        ASSERT_IS_OK(module->getAudioRoutes(&initialRoutes));
     }
 
-    void TearDownImpl() { debug.reset(); }
+    void TearDownImpl() {
+        debug.reset();
+        std::vector<AudioPort> finalPorts;
+        ASSERT_IS_OK(module->getAudioPorts(&finalPorts));
+        EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioPort>(initialPorts, finalPorts))
+                << "The list of audio ports was not restored to the initial state";
+        std::vector<AudioRoute> finalRoutes;
+        ASSERT_IS_OK(module->getAudioRoutes(&finalRoutes));
+        EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioRoute>(initialRoutes, finalRoutes))
+                << "The list of audio routes was not restored to the initial state";
+    }
 
     void ConnectToService(const std::string& moduleName) {
         ASSERT_EQ(module, nullptr);
@@ -502,17 +523,24 @@
         }
     }
 
+    // Warning: modifies the vectors!
+    template <typename T>
+    void VerifyVectorsAreEqual(std::vector<T>& v1, std::vector<T>& v2) {
+        ASSERT_EQ(v1.size(), v2.size());
+        std::sort(v1.begin(), v1.end());
+        std::sort(v2.begin(), v2.end());
+        if (v1 != v2) {
+            FAIL() << "Vectors are not equal: v1 = " << ::android::internal::ToString(v1)
+                   << ", v2 = " << ::android::internal::ToString(v2);
+        }
+    }
+
     std::shared_ptr<IModule> module;
     std::unique_ptr<ModuleConfig> moduleConfig;
     AudioHalBinderServiceUtil binderUtil;
     std::unique_ptr<WithDebugFlags> debug;
-};
-
-class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
-  public:
-    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
-
-    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+    std::vector<AudioPort> initialPorts;
+    std::vector<AudioRoute> initialRoutes;
 };
 
 class WithDevicePortConnectedState {
@@ -530,16 +558,19 @@
                     << "when external device disconnected";
         }
     }
+    ScopedAStatus SetUpNoChecks(IModule* module, ModuleConfig* moduleConfig) {
+        RETURN_STATUS_IF_ERROR(module->connectExternalDevice(mIdAndData, &mConnectedPort));
+        RETURN_STATUS_IF_ERROR(moduleConfig->onExternalDeviceConnected(module, mConnectedPort));
+        mModule = module;
+        mModuleConfig = moduleConfig;
+        return ScopedAStatus::ok();
+    }
     void SetUp(IModule* module, ModuleConfig* moduleConfig) {
-        ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
+        ASSERT_NE(moduleConfig, nullptr);
+        ASSERT_IS_OK(SetUpNoChecks(module, moduleConfig))
                 << "when connecting device port ID & data " << mIdAndData.toString();
         ASSERT_NE(mIdAndData.id, getId())
                 << "ID of the connected port must not be the same as the ID of the template port";
-        ASSERT_NE(moduleConfig, nullptr);
-        ASSERT_IS_OK(moduleConfig->onExternalDeviceConnected(module, mConnectedPort))
-                << "when external device connected";
-        mModule = module;
-        mModuleConfig = moduleConfig;
     }
     int32_t getId() const { return mConnectedPort.id; }
     const AudioPort& get() { return mConnectedPort; }
@@ -551,6 +582,13 @@
     AudioPort mConnectedPort;
 };
 
+class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+};
+
 class StreamContext {
   public:
     typedef AidlMessageQueue<StreamDescriptor::Command, SynchronizedReadWrite> CommandMQ;
@@ -1258,11 +1296,8 @@
     ASSERT_IS_OK(module->getAudioPorts(&ports1));
     std::vector<AudioPort> ports2;
     ASSERT_IS_OK(module->getAudioPorts(&ports2));
-    ASSERT_EQ(ports1.size(), ports2.size())
-            << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
-    std::sort(ports1.begin(), ports1.end());
-    std::sort(ports2.begin(), ports2.end());
-    EXPECT_EQ(ports1, ports2);
+    EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioPort>(ports1, ports2))
+            << "Audio port arrays do not match across consequent calls to getAudioPorts";
 }
 
 TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
@@ -1270,11 +1305,8 @@
     ASSERT_IS_OK(module->getAudioRoutes(&routes1));
     std::vector<AudioRoute> routes2;
     ASSERT_IS_OK(module->getAudioRoutes(&routes2));
-    ASSERT_EQ(routes1.size(), routes2.size())
-            << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
-    std::sort(routes1.begin(), routes1.end());
-    std::sort(routes2.begin(), routes2.end());
-    EXPECT_EQ(routes1, routes2);
+    EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioRoute>(routes1, routes2))
+            << " Audio route arrays do not match across consequent calls to getAudioRoutes";
 }
 
 TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
@@ -1792,39 +1824,151 @@
     }
 }
 
+class RoutedPortsProfilesSnapshot {
+  public:
+    explicit RoutedPortsProfilesSnapshot(int32_t portId) : mPortId(portId) {}
+    void Capture(IModule* module) {
+        std::vector<AudioRoute> routes;
+        ASSERT_IS_OK(module->getAudioRoutesForAudioPort(mPortId, &routes));
+        std::vector<AudioPort> allPorts;
+        ASSERT_IS_OK(module->getAudioPorts(&allPorts));
+        ASSERT_NO_FATAL_FAILURE(GetAllRoutedPorts(routes, allPorts));
+        ASSERT_NO_FATAL_FAILURE(GetProfileSizes());
+    }
+    void VerifyNoProfilesChanges(const RoutedPortsProfilesSnapshot& before) {
+        for (const auto& p : before.mRoutedPorts) {
+            auto beforeIt = before.mPortProfileSizes.find(p.id);
+            ASSERT_NE(beforeIt, before.mPortProfileSizes.end())
+                    << "port ID " << p.id << " not found in the initial profile sizes";
+            EXPECT_EQ(beforeIt->second, mPortProfileSizes[p.id])
+                    << " port " << p.toString() << " has an unexpected profile size change"
+                    << " following an external device connection and disconnection";
+        }
+    }
+    void VerifyProfilesNonEmpty() {
+        for (const auto& p : mRoutedPorts) {
+            EXPECT_NE(0UL, mPortProfileSizes[p.id])
+                    << " port " << p.toString() << " must have had its profiles"
+                    << " populated while having a connected external device";
+        }
+    }
+
+    const std::vector<AudioPort>& getRoutedPorts() const { return mRoutedPorts; }
+
+  private:
+    void GetAllRoutedPorts(const std::vector<AudioRoute>& routes,
+                           std::vector<AudioPort>& allPorts) {
+        for (const auto& r : routes) {
+            if (r.sinkPortId == mPortId) {
+                for (const auto& srcPortId : r.sourcePortIds) {
+                    const auto srcPortIt = findById(allPorts, srcPortId);
+                    ASSERT_NE(allPorts.end(), srcPortIt) << "port ID " << srcPortId;
+                    mRoutedPorts.push_back(*srcPortIt);
+                }
+            } else {
+                const auto sinkPortIt = findById(allPorts, r.sinkPortId);
+                ASSERT_NE(allPorts.end(), sinkPortIt) << "port ID " << r.sinkPortId;
+                mRoutedPorts.push_back(*sinkPortIt);
+            }
+        }
+    }
+    void GetProfileSizes() {
+        std::transform(
+                mRoutedPorts.begin(), mRoutedPorts.end(),
+                std::inserter(mPortProfileSizes, mPortProfileSizes.end()),
+                [](const auto& port) { return std::make_pair(port.id, port.profiles.size()); });
+    }
+
+    const int32_t mPortId;
+    std::vector<AudioPort> mRoutedPorts;
+    std::map<int32_t, size_t> mPortProfileSizes;
+};
+
 // Note: This test relies on simulation of external device connections by the HAL module.
 TEST_P(AudioCoreModule, ExternalDeviceMixPortConfigs) {
     // After an external device has been connected, all mix ports that can be routed
     // to the device port for the connected device must have non-empty profiles.
+    // Since the test connects and disconnects a single device each time, the size
+    // of profiles for all mix ports routed to the device port under test must get back
+    // to the original count once the external device is disconnected.
     ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
     std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
     if (externalDevicePorts.empty()) {
         GTEST_SKIP() << "No external devices in the module.";
     }
     for (const auto& port : externalDevicePorts) {
-        WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
-        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
-        std::vector<AudioRoute> routes;
-        ASSERT_IS_OK(module->getAudioRoutesForAudioPort(portConnected.getId(), &routes));
-        std::vector<AudioPort> allPorts;
-        ASSERT_IS_OK(module->getAudioPorts(&allPorts));
-        for (const auto& r : routes) {
-            if (r.sinkPortId == portConnected.getId()) {
-                for (const auto& srcPortId : r.sourcePortIds) {
-                    const auto srcPortIt = findById(allPorts, srcPortId);
-                    ASSERT_NE(allPorts.end(), srcPortIt) << "port ID " << srcPortId;
-                    EXPECT_NE(0UL, srcPortIt->profiles.size())
-                            << " source port " << srcPortIt->toString() << " must have its profiles"
-                            << " populated following external device connection";
-                }
-            } else {
-                const auto sinkPortIt = findById(allPorts, r.sinkPortId);
-                ASSERT_NE(allPorts.end(), sinkPortIt) << "port ID " << r.sinkPortId;
-                EXPECT_NE(0UL, sinkPortIt->profiles.size())
-                        << " source port " << sinkPortIt->toString() << " must have its"
-                        << " profiles populated following external device connection";
+        SCOPED_TRACE(port.toString());
+        RoutedPortsProfilesSnapshot before(port.id);
+        ASSERT_NO_FATAL_FAILURE(before.Capture(module.get()));
+        if (before.getRoutedPorts().empty()) continue;
+        {
+            WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
+            ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
+            RoutedPortsProfilesSnapshot connected(portConnected.getId());
+            ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
+            EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
+        }
+        RoutedPortsProfilesSnapshot after(port.id);
+        ASSERT_NO_FATAL_FAILURE(after.Capture(module.get()));
+        EXPECT_NO_FATAL_FAILURE(after.VerifyNoProfilesChanges(before));
+    }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, TwoExternalDevicesMixPortConfigsNested) {
+    // Ensure that in the case when two external devices are connected to the same
+    // device port, disconnecting one of them does not erase the profiles of routed mix ports.
+    // In this scenario, the connections are "nested."
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
+    if (externalDevicePorts.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : externalDevicePorts) {
+        SCOPED_TRACE(port.toString());
+        WithDevicePortConnectedState portConnected1(GenerateUniqueDeviceAddress(port));
+        ASSERT_NO_FATAL_FAILURE(portConnected1.SetUp(module.get(), moduleConfig.get()));
+        {
+            // Connect and disconnect another device, if possible. It might not be possible
+            // for point-to-point connections, like analog or SPDIF.
+            WithDevicePortConnectedState portConnected2(GenerateUniqueDeviceAddress(port));
+            if (auto status = portConnected2.SetUpNoChecks(module.get(), moduleConfig.get());
+                !status.isOk()) {
+                continue;
             }
         }
+        RoutedPortsProfilesSnapshot connected(portConnected1.getId());
+        ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
+        EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
+    }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, TwoExternalDevicesMixPortConfigsInterleaved) {
+    // Ensure that in the case when two external devices are connected to the same
+    // device port, disconnecting one of them does not erase the profiles of routed mix ports.
+    // In this scenario, the connections are "interleaved."
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
+    if (externalDevicePorts.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : externalDevicePorts) {
+        SCOPED_TRACE(port.toString());
+        auto portConnected1 =
+                std::make_unique<WithDevicePortConnectedState>(GenerateUniqueDeviceAddress(port));
+        ASSERT_NO_FATAL_FAILURE(portConnected1->SetUp(module.get(), moduleConfig.get()));
+        WithDevicePortConnectedState portConnected2(GenerateUniqueDeviceAddress(port));
+        // Connect another device, if possible. It might not be possible for point-to-point
+        // connections, like analog or SPDIF.
+        if (auto status = portConnected2.SetUpNoChecks(module.get(), moduleConfig.get());
+            !status.isOk()) {
+            continue;
+        }
+        portConnected1.reset();
+        RoutedPortsProfilesSnapshot connected(portConnected2.getId());
+        ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
+        EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
     }
 }
 
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index b764ad6..04ae63a 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -241,6 +241,7 @@
         verifyCameraCharacteristics(chars);
         verifyMonochromeCharacteristics(chars);
         verifyRecommendedConfigs(chars);
+        verifyHighSpeedRecordingCharacteristics(name, chars);
         verifyLogicalOrUltraHighResCameraMetadata(name, device, chars, cameraDeviceNames);
 
         ASSERT_TRUE(ret.isOk());
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index ef3ce4f..c8881b8 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -767,6 +767,90 @@
     ASSERT_TRUE(hasBokehStillCaptureMode || hasBokehContinuousMode || hasVendorMode);
 }
 
+void CameraAidlTest::verifyHighSpeedRecordingCharacteristics(const std::string& cameraName,
+                                                             const CameraMetadata& chars) {
+    const camera_metadata_t* metadata =
+            reinterpret_cast<const camera_metadata_t*>(chars.metadata.data());
+
+    // Check capabilities
+    bool hasHighSpeedRecordingCapability = false;
+    bool hasUltraHighResolutionCapability = false;
+    camera_metadata_ro_entry entry;
+    int rc =
+            find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+    if ((0 == rc) && (entry.count > 0)) {
+        hasHighSpeedRecordingCapability =
+                std::find(entry.data.u8, entry.data.u8 + entry.count,
+                          ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO) !=
+                entry.data.u8 + entry.count;
+
+        hasUltraHighResolutionCapability =
+                std::find(entry.data.u8, entry.data.u8 + entry.count,
+                          ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) !=
+                entry.data.u8 + entry.count;
+    }
+
+    // Check high speed video configurations
+    camera_metadata_ro_entry highSpeedEntry;
+    rc = find_camera_metadata_ro_entry(
+            metadata, ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, &highSpeedEntry);
+    bool hasHighSpeedEntry = (0 == rc && highSpeedEntry.count > 0);
+
+    camera_metadata_ro_entry highSpeedMaxResEntry;
+    rc = find_camera_metadata_ro_entry(
+            metadata, ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+            &highSpeedMaxResEntry);
+    bool hasHighSpeedMaxResEntry = (0 == rc && highSpeedMaxResEntry.count > 0);
+
+    // High speed recording configuration entry must be available based on capabilities
+    bool noHighSpeedRecording =
+            !hasHighSpeedRecordingCapability && !hasHighSpeedEntry && !hasHighSpeedMaxResEntry;
+    if (noHighSpeedRecording) {
+        return;
+    }
+    bool hasHighSpeedRecording = hasHighSpeedRecordingCapability && hasHighSpeedEntry &&
+                                 ((hasHighSpeedMaxResEntry && hasUltraHighResolutionCapability) ||
+                                  !hasHighSpeedMaxResEntry);
+    ASSERT_TRUE(hasHighSpeedRecording);
+
+    std::string version, cameraId;
+    ASSERT_TRUE(matchDeviceName(cameraName, mProviderType, &version, &cameraId));
+    bool needBatchSizeCheck = (version != CAMERA_DEVICE_API_VERSION_1);
+
+    // Check each entry item
+    ASSERT_TRUE(highSpeedEntry.count > 0 && highSpeedEntry.count % 5 == 0);
+    for (auto i = 4; i < highSpeedEntry.count; i += 5) {
+        int32_t fps_min = highSpeedEntry.data.i32[i - 2];
+        int32_t fps_max = highSpeedEntry.data.i32[i - 1];
+        int32_t batch_size_max = highSpeedEntry.data.i32[i];
+        int32_t allowedMaxBatchSize = fps_max / 30;
+
+        ASSERT_GE(fps_max, 120);
+        ASSERT_TRUE(fps_min % 30 == 0 && fps_max % 30 == 0);
+        if (needBatchSizeCheck) {
+            ASSERT_LE(batch_size_max, 32);
+            ASSERT_TRUE(allowedMaxBatchSize % batch_size_max == 0);
+        }
+    }
+
+    if (hasHighSpeedMaxResEntry) {
+        ASSERT_TRUE(highSpeedMaxResEntry.count > 0 && highSpeedMaxResEntry.count % 5 == 0);
+        for (auto i = 4; i < highSpeedMaxResEntry.count; i += 5) {
+            int32_t fps_min = highSpeedMaxResEntry.data.i32[i - 2];
+            int32_t fps_max = highSpeedMaxResEntry.data.i32[i - 1];
+            int32_t batch_size_max = highSpeedMaxResEntry.data.i32[i];
+            int32_t allowedMaxBatchSize = fps_max / 30;
+
+            ASSERT_GE(fps_max, 120);
+            ASSERT_TRUE(fps_min % 30 == 0 && fps_max % 30 == 0);
+            if (needBatchSizeCheck) {
+                ASSERT_LE(batch_size_max, 32);
+                ASSERT_TRUE(allowedMaxBatchSize % batch_size_max == 0);
+            }
+        }
+    }
+}
+
 Status CameraAidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
                                                  std::vector<AvailableStream>& outputStreams,
                                                  const AvailableStream* threshold,
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index fdf312e..85ab443 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -222,6 +222,9 @@
 
     static void verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata);
 
+    void verifyHighSpeedRecordingCharacteristics(const std::string& cameraName,
+                                                 const CameraMetadata& chars);
+
     static void verifyZoomCharacteristics(const camera_metadata_t* metadata);
 
     static void verifyRecommendedConfigs(const CameraMetadata& chars);
@@ -543,6 +546,8 @@
 namespace {
 // device@<major>.<minor>/<type>/id
 const char* kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/\\s+/(.+)";
+const std::string CAMERA_DEVICE_API_VERSION_1 = "1.1";
+
 const int32_t kMaxVideoWidth = 4096;
 const int32_t kMaxVideoHeight = 2160;
 
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl
index 460ff97..069b2cf 100644
--- a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl
@@ -35,5 +35,6 @@
 @VintfStability
 union BaseBlock {
   android.hardware.common.NativeHandle nativeBlock;
+  android.hardware.HardwareBuffer hwbBlock;
   android.hardware.media.bufferpool2.BufferStatusMessage pooledBlock;
 }
diff --git a/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl b/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
index 8b8b8e0..7cc041c 100644
--- a/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.media.c2;
 
+import android.hardware.HardwareBuffer;
 import android.hardware.common.NativeHandle;
 
 /**
@@ -32,6 +33,10 @@
      */
     NativeHandle nativeBlock;
     /**
+     * #hwbBlock is the opaque representation of a GraphicBuffer
+     */
+    HardwareBuffer hwbBlock;
+    /**
      * #pooledBlock is a reference to a buffer handled by a BufferPool.
      */
     android.hardware.media.bufferpool2.BufferStatusMessage pooledBlock;
diff --git a/memtrack/aidl/default/Android.bp b/memtrack/aidl/default/Android.bp
index 6c77177..cf95bbb 100644
--- a/memtrack/aidl/default/Android.bp
+++ b/memtrack/aidl/default/Android.bp
@@ -37,3 +37,56 @@
         "Memtrack.cpp",
     ],
 }
+
+cc_binary {
+    name: "android.hardware.memtrack-service.apex",
+    stem: "android.hardware.memtrack-service.example",
+    relative_install_path: "hw",
+    vendor: true,
+
+    stl: "c++_static",
+    static_libs: [
+        "libbase",
+        "android.hardware.memtrack-V1-ndk",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+    ],
+    srcs: [
+        "main.cpp",
+        "Memtrack.cpp",
+    ],
+    installable: false, // installed in APEX
+}
+
+prebuilt_etc {
+    name: "memtrack-default-apex.rc",
+    src: "memtrack-default-apex.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "memtrack-default.xml",
+    src: "memtrack-default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.memtrack",
+    file_contexts: "apex_file_contexts",
+    manifest: "apex_manifest.json",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.memtrack-service.apex",
+    ],
+    prebuilts: [
+        "memtrack-default-apex.rc",
+        "memtrack-default.xml",
+    ],
+}
diff --git a/memtrack/aidl/default/apex_file_contexts b/memtrack/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..40c0af4
--- /dev/null
+++ b/memtrack/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                      u:object_r:vendor_file:s0
+/etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.memtrack-service\.example        u:object_r:hal_memtrack_default_exec:s0
diff --git a/memtrack/aidl/default/apex_manifest.json b/memtrack/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..16d195e
--- /dev/null
+++ b/memtrack/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.memtrack",
+    "version": 1
+}
\ No newline at end of file
diff --git a/memtrack/aidl/default/memtrack-default-apex.rc b/memtrack/aidl/default/memtrack-default-apex.rc
new file mode 100644
index 0000000..53e712a
--- /dev/null
+++ b/memtrack/aidl/default/memtrack-default-apex.rc
@@ -0,0 +1,4 @@
+service vendor.memtrack-default /apex/com.android.hardware.memtrack/bin/hw/android.hardware.memtrack-service.example
+    class hal
+    user nobody
+    group system
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 6423329..303dc77 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -24,6 +24,19 @@
 
 #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
 
+namespace {
+const RadioAccessSpecifierBands EUTRAN_BAND_17 =
+        RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::eutranBands>(
+                {EutranBands::BAND_17});
+const RadioAccessSpecifierBands EUTRAN_BAND_20 =
+        RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::eutranBands>(
+                {EutranBands::BAND_20});
+const RadioAccessSpecifier EUTRAN_SPECIFIER_17 = {
+        .accessNetwork = AccessNetwork::EUTRAN, .bands = EUTRAN_BAND_17, .channels = {1, 2}};
+const RadioAccessSpecifier EUTRAN_SPECIFIER_20 = {
+        .accessNetwork = AccessNetwork::EUTRAN, .bands = EUTRAN_BAND_20, .channels = {128, 129}};
+}  // namespace
+
 void RadioNetworkTest::SetUp() {
     std::string serviceName = GetParam();
 
@@ -291,7 +304,7 @@
     signalThresholdInfo.hysteresisDb = 10;  // hysteresisDb too large given threshold list deltas
     signalThresholdInfo.thresholds = {-109, -103, -97, -89};
     signalThresholdInfo.isEnabled = true;
-    signalThresholdInfo.ran = AccessNetwork::GERAN;
+    signalThresholdInfo.ran = AccessNetwork::EUTRAN;
 
     ndk::ScopedAStatus res =
             radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo});
@@ -316,7 +329,7 @@
     signalThresholdInfo.hysteresisMs = 0;
     signalThresholdInfo.hysteresisDb = 0;
     signalThresholdInfo.isEnabled = true;
-    signalThresholdInfo.ran = AccessNetwork::GERAN;
+    signalThresholdInfo.ran = AccessNetwork::EUTRAN;
 
     ndk::ScopedAStatus res =
             radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo});
@@ -353,7 +366,8 @@
 
     ALOGI("setSignalStrengthReportingCriteria_Geran, rspInfo.error = %s\n",
           toString(radioRsp_network->rspInfo.error).c_str());
-    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
 }
 
 /*
@@ -652,7 +666,7 @@
         ASSERT_OK(res);
         EXPECT_EQ(std::cv_status::no_timeout, wait());
         if (radioRsp_network->rspInfo.error == RadioError::NONE) {
-            supportedSignalThresholdInfos.push_back(signalThresholdInfoGeran);
+            supportedSignalThresholdInfos.push_back(signalThresholdInfoEutran);
         } else {
             // Refer to IRadioNetworkResponse#setSignalStrengthReportingCriteriaResponse
             ASSERT_TRUE(CheckAnyOfErrors(
@@ -686,7 +700,7 @@
     ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria(
             serial, 5000,
             5000,  // hysteresisDlKbps too big for thresholds delta
-            100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::GERAN);
+            100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::EUTRAN);
     ASSERT_OK(res);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -694,11 +708,7 @@
 
     ALOGI("setLinkCapacityReportingCriteria_invalidHysteresisDlKbps, rspInfo.error = %s\n",
           toString(radioRsp_network->rspInfo.error).c_str());
-    // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported
-    // for GERAN
-    ASSERT_TRUE(
-            CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                             {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
 }
 
 /*
@@ -709,7 +719,7 @@
 
     ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria(
             serial, 5000, 500, 1000,  // hysteresisUlKbps too big for thresholds delta
-            {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::GERAN);
+            {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::EUTRAN);
     ASSERT_OK(res);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -717,11 +727,7 @@
 
     ALOGI("setLinkCapacityReportingCriteria_invalidHysteresisUlKbps, rspInfo.error = %s\n",
           toString(radioRsp_network->rspInfo.error).c_str());
-    // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported
-    // for GERAN
-    ASSERT_TRUE(
-            CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                             {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
 }
 
 /*
@@ -731,7 +737,7 @@
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria(
-            serial, 0, 0, 0, {}, {}, AccessNetwork::GERAN);
+            serial, 0, 0, 0, {}, {}, AccessNetwork::EUTRAN);
     ASSERT_OK(res);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -739,10 +745,7 @@
 
     ALOGI("setLinkCapacityReportingCriteria_emptyParams, rspInfo.error = %s\n",
           toString(radioRsp_network->rspInfo.error).c_str());
-    // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported
-    // for GERAN
-    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE}));
 }
 
 /*
@@ -783,19 +786,9 @@
     }
     std::vector<RadioAccessSpecifier> originalSpecifiers = radioRsp_network->specifiers;
 
-    RadioAccessSpecifierBands bandP900 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_P900});
-    RadioAccessSpecifierBands band850 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_850});
-    RadioAccessSpecifier specifierP900 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
-    RadioAccessSpecifier specifier850 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
     serial = GetRandomSerialNumber();
-    res = radio_network->setSystemSelectionChannels(serial, true, {specifierP900, specifier850});
+    res = radio_network->setSystemSelectionChannels(serial, true,
+                                                    {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20});
     ASSERT_OK(res);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -808,8 +801,8 @@
 
     if (radioRsp_network->rspInfo.error == RadioError::NONE) {
         serial = GetRandomSerialNumber();
-        res = radio_network->setSystemSelectionChannels(serial, false,
-                                                        {specifierP900, specifier850});
+        res = radio_network->setSystemSelectionChannels(
+                serial, false, {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20});
         ASSERT_OK(res);
         EXPECT_EQ(std::cv_status::no_timeout, wait());
         EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -832,20 +825,9 @@
 TEST_P(RadioNetworkTest, startNetworkScan) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifierBands band17 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::eutranBands>(
-                    {EutranBands::BAND_17});
-    RadioAccessSpecifierBands band20 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::eutranBands>(
-                    {EutranBands::BAND_20});
-    RadioAccessSpecifier specifier17 = {
-            .accessNetwork = AccessNetwork::EUTRAN, .bands = band17, .channels = {1, 2}};
-    RadioAccessSpecifier specifier20 = {
-            .accessNetwork = AccessNetwork::EUTRAN, .bands = band20, .channels = {128, 129}};
-
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
                                   .interval = 60,
-                                  .specifiers = {specifier17, specifier20},
+                                  .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
                                   .maxSearchTime = 60,
                                   .incrementalResults = false,
                                   .incrementalResultsPeriodicity = 1};
@@ -867,10 +849,9 @@
             ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
                                          {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED}));
         } else {
-            ASSERT_TRUE(CheckAnyOfErrors(
-                    radioRsp_network->rspInfo.error,
-                    {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED, RadioError::NONE,
-                     RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+            ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                         {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED,
+                                          RadioError::INVALID_ARGUMENTS}));
         }
     }
 
@@ -900,9 +881,8 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_network->rspInfo.error,
-                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
     }
 }
 
@@ -912,20 +892,9 @@
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval1) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifierBands bandP900 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_P900});
-    RadioAccessSpecifierBands band850 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_850});
-    RadioAccessSpecifier specifierP900 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
-    RadioAccessSpecifier specifier850 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC,
                                   .interval = 4,
-                                  .specifiers = {specifierP900, specifier850},
+                                  .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
                                   .maxSearchTime = 60,
                                   .incrementalResults = false,
                                   .incrementalResultsPeriodicity = 1};
@@ -941,9 +910,8 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_network->rspInfo.error,
-                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
     }
 }
 
@@ -953,20 +921,9 @@
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval2) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifierBands bandP900 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_P900});
-    RadioAccessSpecifierBands band850 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_850});
-    RadioAccessSpecifier specifierP900 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
-    RadioAccessSpecifier specifier850 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC,
                                   .interval = 301,
-                                  .specifiers = {specifierP900, specifier850},
+                                  .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
                                   .maxSearchTime = 60,
                                   .incrementalResults = false,
                                   .incrementalResultsPeriodicity = 1};
@@ -982,9 +939,8 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_network->rspInfo.error,
-                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
     }
 }
 
@@ -994,20 +950,9 @@
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime1) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifierBands bandP900 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_P900});
-    RadioAccessSpecifierBands band850 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_850});
-    RadioAccessSpecifier specifierP900 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
-    RadioAccessSpecifier specifier850 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
                                   .interval = 60,
-                                  .specifiers = {specifierP900, specifier850},
+                                  .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
                                   .maxSearchTime = 59,
                                   .incrementalResults = false,
                                   .incrementalResultsPeriodicity = 1};
@@ -1023,9 +968,8 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_network->rspInfo.error,
-                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
     }
 }
 
@@ -1035,20 +979,9 @@
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime2) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifierBands bandP900 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_P900});
-    RadioAccessSpecifierBands band850 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_850});
-    RadioAccessSpecifier specifierP900 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
-    RadioAccessSpecifier specifier850 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
                                   .interval = 60,
-                                  .specifiers = {specifierP900, specifier850},
+                                  .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
                                   .maxSearchTime = 3601,
                                   .incrementalResults = false,
                                   .incrementalResultsPeriodicity = 1};
@@ -1064,9 +997,8 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_network->rspInfo.error,
-                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
     }
 }
 
@@ -1076,20 +1008,9 @@
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity1) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifierBands bandP900 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_P900});
-    RadioAccessSpecifierBands band850 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_850});
-    RadioAccessSpecifier specifierP900 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
-    RadioAccessSpecifier specifier850 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
                                   .interval = 60,
-                                  .specifiers = {specifierP900, specifier850},
+                                  .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
                                   .maxSearchTime = 600,
                                   .incrementalResults = true,
                                   .incrementalResultsPeriodicity = 0};
@@ -1105,9 +1026,8 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_network->rspInfo.error,
-                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
     }
 }
 
@@ -1117,20 +1037,9 @@
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity2) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifierBands bandP900 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_P900});
-    RadioAccessSpecifierBands band850 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_850});
-    RadioAccessSpecifier specifierP900 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
-    RadioAccessSpecifier specifier850 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
                                   .interval = 60,
-                                  .specifiers = {specifierP900, specifier850},
+                                  .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
                                   .maxSearchTime = 600,
                                   .incrementalResults = true,
                                   .incrementalResultsPeriodicity = 11};
@@ -1146,9 +1055,8 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_network->rspInfo.error,
-                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
     }
 }
 
@@ -1158,20 +1066,9 @@
 TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest1) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifierBands bandP900 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_P900});
-    RadioAccessSpecifierBands band850 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_850});
-    RadioAccessSpecifier specifierP900 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
-    RadioAccessSpecifier specifier850 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
                                   .interval = 60,
-                                  .specifiers = {specifierP900, specifier850},
+                                  .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
                                   .maxSearchTime = 360,
                                   .incrementalResults = false,
                                   .incrementalResultsPeriodicity = 10};
@@ -1188,8 +1085,7 @@
                                      {RadioError::NONE, RadioError::SIM_ABSENT}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
-                                      RadioError::REQUEST_NOT_SUPPORTED}));
+                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
     }
 
     if (radioRsp_network->rspInfo.error == RadioError::NONE) {
@@ -1204,20 +1100,9 @@
 TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest2) {
     serial = GetRandomSerialNumber();
 
-    RadioAccessSpecifierBands bandP900 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_P900});
-    RadioAccessSpecifierBands band850 =
-            RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
-                    {GeranBands::BAND_850});
-    RadioAccessSpecifier specifierP900 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
-    RadioAccessSpecifier specifier850 = {
-            .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
                                   .interval = 60,
-                                  .specifiers = {specifierP900, specifier850},
+                                  .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
                                   .maxSearchTime = 360,
                                   .incrementalResults = false,
                                   .incrementalResultsPeriodicity = 10,
@@ -1235,8 +1120,7 @@
                                      {RadioError::NONE, RadioError::SIM_ABSENT}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
-                                      RadioError::REQUEST_NOT_SUPPORTED}));
+                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
     }
 
     if (radioRsp_network->rspInfo.error == RadioError::NONE) {
@@ -1253,21 +1137,23 @@
 
     // can't camp on nonexistent MCCMNC, so we expect this to fail.
     ndk::ScopedAStatus res =
-            radio_network->setNetworkSelectionModeManual(serial, "123456", AccessNetwork::GERAN);
+            radio_network->setNetworkSelectionModeManual(serial, "123456", AccessNetwork::EUTRAN);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 
     if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                     {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME,
-                                      RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE},
-                                     CHECK_GENERAL_ERROR));
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_network->rspInfo.error,
+                {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, RadioError::INVALID_ARGUMENTS,
+                 RadioError::INVALID_STATE, RadioError::RADIO_NOT_AVAILABLE, RadioError::NO_MEMORY,
+                 RadioError::INTERNAL_ERR, RadioError::SYSTEM_ERR, RadioError::CANCELLED}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
-                                      RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE},
-                                     CHECK_GENERAL_ERROR));
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_network->rspInfo.error,
+                {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_ARGUMENTS,
+                 RadioError::INVALID_STATE, RadioError::NO_MEMORY, RadioError::INTERNAL_ERR,
+                 RadioError::SYSTEM_ERR, RadioError::CANCELLED}));
     }
 }
 
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 2e4fc15..aeb0163 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -379,6 +379,12 @@
      *   validate it against the key material.  In the event of a mismatch, importKey must return
      *   ErrorCode::IMPORT_PARAMETER_MISMATCH.
      *
+     * o Tag::EC_CURVE is not necessary in the input parameters for import of EC keys. If not
+     *   provided the IKeyMintDevice must deduce the value from the provided key material and add
+     *   the tag and value to the key characteristics.  If Tag::EC_CURVE is provided, the
+     *   IKeyMintDevice must validate it against the key material.  In the event of a mismatch,
+     *   importKey must return ErrorCode::IMPORT_PARAMETER_MISMATCH.
+     *
      * o Tag::RSA_PUBLIC_EXPONENT (for RSA keys only) is not necessary in the input parameters.  If
      *   not provided, the IKeyMintDevice must deduce the value from the provided key material and
      *   add the tag and value to the key characteristics.  If Tag::RSA_PUBLIC_EXPONENT is provided,
diff --git a/security/keymint/aidl/vts/functional/AuthTest.cpp b/security/keymint/aidl/vts/functional/AuthTest.cpp
index d5c6d2a..eb5db68 100644
--- a/security/keymint/aidl/vts/functional/AuthTest.cpp
+++ b/security/keymint/aidl/vts/functional/AuthTest.cpp
@@ -350,14 +350,14 @@
 
     // Wait for long enough that the hardware auth token expires.
     sleep(timeout_secs + 1);
-    if (!timestamp_token_required_) {
-        // KeyMint implementation has its own clock, and can immediately detect timeout.
-        EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
-                  Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat));
-    } else {
-        // KeyMint implementation has no clock, so only detects timeout via timestamp token provided
-        // on update()/finish().
-        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat));
+
+    auto begin_result = Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat);
+    if (begin_result == ErrorCode::OK) {
+        // If begin() succeeds despite the out-of-date HAT, that must mean that the KeyMint
+        // device doesn't have its own clock.  In that case, it only detects timeout via a
+        // timestamp token provided on update()/finish()
+        ASSERT_TRUE(timestamp_token_required_);
+
         secureclock::TimeStampToken time_token;
         EXPECT_EQ(ErrorCode::OK,
                   GetReturnErrorCode(clock_->generateTimeStamp(challenge_, &time_token)));
@@ -365,6 +365,9 @@
         string output;
         EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
                   Finish(message, {} /* signature */, &output, hat, time_token));
+    } else {
+        // The KeyMint implementation may have its own clock that can immediately detect timeout.
+        ASSERT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED, begin_result);
     }
 }
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 022dd3f..5c3d8cc 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -2611,16 +2611,16 @@
 /*
  * NewKeyGenerationTest.EcdsaMissingCurve
  *
- * Verifies that EC key generation fails if EC_CURVE not specified after KeyMint V2.
+ * Verifies that EC key generation fails if EC_CURVE not specified after KeyMint V3.
  */
 TEST_P(NewKeyGenerationTest, EcdsaMissingCurve) {
-    if (AidlVersion() < 2) {
+    if (AidlVersion() < 3) {
         /*
          * The KeyMint V1 spec required that EC_CURVE be specified for EC keys.
          * However, this was not checked at the time so we can only be strict about checking this
-         * for implementations of KeyMint version 2 and above.
+         * for implementations of KeyMint version 3 and above.
          */
-        GTEST_SKIP() << "Requiring EC_CURVE only strict since KeyMint v2";
+        GTEST_SKIP() << "Requiring EC_CURVE only strict since KeyMint v3";
     }
     /* If EC_CURVE not provided, generateKey
      * must return ErrorCode::UNSUPPORTED_KEY_SIZE or ErrorCode::UNSUPPORTED_EC_CURVE.
@@ -4148,6 +4148,42 @@
 }
 
 /*
+ * ImportKeyTest.EcdsaSuccessCurveNotSpecified
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair works correctly
+ * when the EC_CURVE is not explicitly specified.
+ */
+TEST_P(ImportKeyTest, EcdsaSuccessCurveNotSpecified) {
+    if (AidlVersion() < 4) {
+        /*
+         * The KeyMint spec before V4 was not clear as to whether EC_CURVE was optional on import of
+         * EC keys. However, this was not checked at the time so we can only be strict about
+         * checking this for implementations of KeyMint version 4 and above.
+         */
+        GTEST_SKIP() << "Skipping EC_CURVE on import only strict since KeyMint v4";
+    }
+
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .Authorization(TAG_ALGORITHM, Algorithm::EC)
+                                               .SigningKey()
+                                               .Digest(Digest::SHA_2_256)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, ec_256_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    LocalVerifyMessage(message, signature, params);
+}
+
+/*
  * ImportKeyTest.EcdsaP256RFC5915Success
  *
  * Verifies that importing and using an ECDSA P-256 key pair encoded using RFC5915 works