Merge "Audio effect aidl log reduce and level adjust" into 24D1-dev am: 3035c98d27

Original change: https://googleplex-android-review.googlesource.com/c/platform/hardware/interfaces/+/26588428

Change-Id: Ia577cf04652149b4a69f636744945e7ed769ef8e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
index 01db90e..1814b59 100644
--- a/audio/6.0/config/api/current.txt
+++ b/audio/6.0/config/api/current.txt
@@ -116,6 +116,7 @@
     enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_HD;
     enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_TWSP;
     enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_CELT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DEFAULT;
     enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
     enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DSD;
     enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS;
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
index c2b8c5d..177af16 100644
--- a/audio/6.0/config/audio_policy_configuration.xsd
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -302,6 +302,7 @@
          TODO: generate from hidl to avoid manual sync. -->
     <xs:simpleType name="audioFormat">
         <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_FORMAT_DEFAULT" />
             <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
             <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
             <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 94aa4dc..d48729f 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -173,7 +173,8 @@
         std::shared_ptr<IStreamCallback> asyncCallback,
         std::shared_ptr<IStreamOutEventCallback> outEventCallback, StreamContext* out_context) {
     if (in_bufferSizeFrames <= 0) {
-        LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
+        LOG(ERROR) << __func__ << ": " << mType << ": non-positive buffer size "
+                   << in_bufferSizeFrames;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     auto& configs = getConfig().portConfigs;
@@ -184,20 +185,21 @@
     const int32_t minimumStreamBufferSizeFrames =
             calculateBufferSizeFrames(nominalLatencyMs, portConfigIt->sampleRate.value().value);
     if (in_bufferSizeFrames < minimumStreamBufferSizeFrames) {
-        LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
-                   << ", must be at least " << minimumStreamBufferSizeFrames;
+        LOG(ERROR) << __func__ << ": " << mType << ": insufficient buffer size "
+                   << in_bufferSizeFrames << ", must be at least " << minimumStreamBufferSizeFrames;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     const size_t frameSize =
             getFrameSizeInBytes(portConfigIt->format.value(), portConfigIt->channelMask.value());
     if (frameSize == 0) {
-        LOG(ERROR) << __func__ << ": could not calculate frame size for port config "
+        LOG(ERROR) << __func__ << ": " << mType
+                   << ": could not calculate frame size for port config "
                    << portConfigIt->toString();
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    LOG(DEBUG) << __func__ << ": frame size " << frameSize << " bytes";
+    LOG(DEBUG) << __func__ << ": " << mType << ": frame size " << frameSize << " bytes";
     if (frameSize > static_cast<size_t>(kMaximumStreamBufferSizeBytes / in_bufferSizeFrames)) {
-        LOG(ERROR) << __func__ << ": buffer size " << in_bufferSizeFrames
+        LOG(ERROR) << __func__ << ": " << mType << ": buffer size " << in_bufferSizeFrames
                    << " frames is too large, maximum size is "
                    << kMaximumStreamBufferSizeBytes / frameSize;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@@ -256,7 +258,8 @@
     for (auto it = patchIdsRange.first; it != patchIdsRange.second; ++it) {
         auto patchIt = findById<AudioPatch>(patches, it->second);
         if (patchIt == patches.end()) {
-            LOG(FATAL) << __func__ << ": patch with id " << it->second << " taken from mPatches "
+            LOG(FATAL) << __func__ << ": " << mType << ": patch with id " << it->second
+                       << " taken from mPatches "
                        << "not found in the configuration";
         }
         if (std::find(patchIt->sourcePortConfigIds.begin(), patchIt->sourcePortConfigIds.end(),
@@ -273,7 +276,8 @@
     auto& configs = getConfig().portConfigs;
     auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
     if (portConfigIt == configs.end()) {
-        LOG(ERROR) << __func__ << ": existing port config id " << in_portConfigId << " not found";
+        LOG(ERROR) << __func__ << ": " << mType << ": existing port config id " << in_portConfigId
+                   << " not found";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     const int32_t portId = portConfigIt->portId;
@@ -282,23 +286,23 @@
     auto& ports = getConfig().ports;
     auto portIt = findById<AudioPort>(ports, portId);
     if (portIt == ports.end()) {
-        LOG(ERROR) << __func__ << ": port id " << portId << " used by port config id "
-                   << in_portConfigId << " not found";
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << portId
+                   << " used by port config id " << in_portConfigId << " not found";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     if (mStreams.count(in_portConfigId) != 0) {
-        LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+        LOG(ERROR) << __func__ << ": " << mType << ": port config id " << in_portConfigId
                    << " already has a stream opened on it";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     if (portIt->ext.getTag() != AudioPortExt::Tag::mix) {
-        LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+        LOG(ERROR) << __func__ << ": " << mType << ": port config id " << in_portConfigId
                    << " does not correspond to a mix port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     const size_t maxOpenStreamCount = portIt->ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
     if (maxOpenStreamCount != 0 && mStreams.count(portId) >= maxOpenStreamCount) {
-        LOG(ERROR) << __func__ << ": port id " << portId
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << portId
                    << " has already reached maximum allowed opened stream count: "
                    << maxOpenStreamCount;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
@@ -326,7 +330,7 @@
         config->ext = port.ext;
         return true;
     }
-    LOG(ERROR) << __func__ << ": port " << port.id << " only has dynamic profiles";
+    LOG(ERROR) << __func__ << ": " << mType << ": port " << port.id << " only has dynamic profiles";
     return false;
 }
 
@@ -493,7 +497,8 @@
         }
     });
     if (!maybeFailure.isOk()) {
-        LOG(WARNING) << __func__ << ": Due to a failure, disconnecting streams on port config ids "
+        LOG(WARNING) << __func__ << ": " << mType
+                     << ": Due to a failure, disconnecting streams on port config ids "
                      << ::android::internal::ToString(idsToDisconnectOnFailure);
         std::for_each(idsToDisconnectOnFailure.begin(), idsToDisconnectOnFailure.end(),
                       [&](const auto& portConfigId) {
@@ -512,7 +517,8 @@
     if (mDebug.simulateDeviceConnections != in_debug.simulateDeviceConnections &&
         !mConnectedDevicePorts.empty()) {
         LOG(ERROR) << __func__ << ": " << mType
-                   << ": attempting to change device connections simulation while having external "
+                   << ": attempting to change device connections simulation while "
+                      "having external "
                    << "devices connected";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
@@ -527,25 +533,25 @@
 
 ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
     *_aidl_return = nullptr;
-    LOG(DEBUG) << __func__ << ": returning null";
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning null";
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
     *_aidl_return = nullptr;
-    LOG(DEBUG) << __func__ << ": returning null";
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning null";
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
     *_aidl_return = nullptr;
-    LOG(DEBUG) << __func__ << ": returning null";
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning null";
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) {
     *_aidl_return = nullptr;
-    LOG(DEBUG) << __func__ << ": returning null";
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning null";
     return ndk::ScopedAStatus::ok();
 }
 
@@ -557,20 +563,23 @@
     {  // Scope the template port so that we don't accidentally modify it.
         auto templateIt = findById<AudioPort>(ports, templateId);
         if (templateIt == ports.end()) {
-            LOG(ERROR) << __func__ << ": port id " << templateId << " not found";
+            LOG(ERROR) << __func__ << ": " << mType << ": port id " << templateId << " not found";
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
         if (templateIt->ext.getTag() != AudioPortExt::Tag::device) {
-            LOG(ERROR) << __func__ << ": port id " << templateId << " is not a device port";
+            LOG(ERROR) << __func__ << ": " << mType << ": port id " << templateId
+                       << " is not a device port";
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
         auto& templateDevicePort = templateIt->ext.get<AudioPortExt::Tag::device>();
         if (templateDevicePort.device.type.connection.empty()) {
-            LOG(ERROR) << __func__ << ": port id " << templateId << " is permanently attached";
+            LOG(ERROR) << __func__ << ": " << mType << ": port id " << templateId
+                       << " is permanently attached";
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
         if (mConnectedDevicePorts.find(templateId) != mConnectedDevicePorts.end()) {
-            LOG(ERROR) << __func__ << ": port id " << templateId << " is a connected device port";
+            LOG(ERROR) << __func__ << ": " << mType << ": port id " << templateId
+                       << " is a connected device port";
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
         // Postpone id allocation until we ensure that there are no client errors.
@@ -580,14 +589,16 @@
                 in_templateIdAndAdditionalData.ext.get<AudioPortExt::Tag::device>();
         auto& connectedDevicePort = connectedPort.ext.get<AudioPortExt::Tag::device>();
         connectedDevicePort.device.address = inputDevicePort.device.address;
-        LOG(DEBUG) << __func__ << ": device port " << connectedPort.id << " device set to "
-                   << connectedDevicePort.device.toString();
+        LOG(DEBUG) << __func__ << ": " << mType << ": device port " << connectedPort.id
+                   << " device set to " << connectedDevicePort.device.toString();
         // Check if there is already a connected port with for the same external device.
+
         for (auto connectedPortPair : mConnectedDevicePorts) {
             auto connectedPortIt = findById<AudioPort>(ports, connectedPortPair.first);
             if (connectedPortIt->ext.get<AudioPortExt::Tag::device>().device ==
                 connectedDevicePort.device) {
-                LOG(ERROR) << __func__ << ": device " << connectedDevicePort.device.toString()
+                LOG(ERROR) << __func__ << ": " << mType << ": device "
+                           << connectedDevicePort.device.toString()
                            << " is already connected at the device port id "
                            << connectedPortPair.first;
                 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
@@ -639,7 +650,8 @@
                                                             hasDynamicProfilesOnly(p.profiles);
                                                  });
             dynamicMixPortIt != ports.end()) {
-            LOG(ERROR) << __func__ << ": connected port only has dynamic profiles after connecting "
+            LOG(ERROR) << __func__ << ": " << mType
+                       << ": connected port only has dynamic profiles after connecting "
                        << "external device " << connectedPort.toString() << ", and there exist "
                        << "a routable mix port with dynamic profiles: "
                        << dynamicMixPortIt->toString();
@@ -650,7 +662,8 @@
     connectedPort.id = nextPortId;
     auto [connectedPortsIt, _] =
             mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::set<int32_t>()));
-    LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
+    LOG(DEBUG) << __func__ << ": " << mType << ": template port " << templateId
+               << " external device connected, "
                << "connected port ID " << connectedPort.id;
     ports.push_back(connectedPort);
     onExternalDeviceConnectionChanged(connectedPort, true /*connected*/);
@@ -700,16 +713,18 @@
     auto& ports = getConfig().ports;
     auto portIt = findById<AudioPort>(ports, in_portId);
     if (portIt == ports.end()) {
-        LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << in_portId << " not found";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     if (portIt->ext.getTag() != AudioPortExt::Tag::device) {
-        LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a device port";
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << in_portId
+                   << " is not a device port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     auto connectedPortsIt = mConnectedDevicePorts.find(in_portId);
     if (connectedPortsIt == mConnectedDevicePorts.end()) {
-        LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a connected device port";
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << in_portId
+                   << " is not a connected device port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     auto& configs = getConfig().portConfigs;
@@ -723,13 +738,14 @@
         return false;
     });
     if (configIt != configs.end()) {
-        LOG(ERROR) << __func__ << ": port id " << in_portId << " has a non-default config with id "
-                   << configIt->id;
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << in_portId
+                   << " has a non-default config with id " << configIt->id;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     onExternalDeviceConnectionChanged(*portIt, false /*connected*/);
     ports.erase(portIt);
-    LOG(DEBUG) << __func__ << ": connected device port " << in_portId << " released";
+    LOG(DEBUG) << __func__ << ": " << mType << ": connected device port " << in_portId
+               << " released";
 
     auto& routes = getConfig().routes;
     for (auto routesIt = routes.begin(); routesIt != routes.end();) {
@@ -765,16 +781,18 @@
     auto& ports = getConfig().ports;
     auto portIt = findById<AudioPort>(ports, in_portId);
     if (portIt == ports.end()) {
-        LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << in_portId << " not found";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     if (portIt->ext.getTag() != AudioPortExt::Tag::device) {
-        LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a device port";
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << in_portId
+                   << " is not a device port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     auto connectedPortsIt = mConnectedDevicePorts.find(in_portId);
     if (connectedPortsIt == mConnectedDevicePorts.end()) {
-        LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a connected device port";
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << in_portId
+                   << " is not a connected device port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 
@@ -785,7 +803,7 @@
 
 ndk::ScopedAStatus Module::getAudioPatches(std::vector<AudioPatch>* _aidl_return) {
     *_aidl_return = getConfig().patches;
-    LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " patches";
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning " << _aidl_return->size() << " patches";
     return ndk::ScopedAStatus::ok();
 }
 
@@ -794,28 +812,29 @@
     auto portIt = findById<AudioPort>(ports, in_portId);
     if (portIt != ports.end()) {
         *_aidl_return = *portIt;
-        LOG(DEBUG) << __func__ << ": returning port by id " << in_portId;
+        LOG(DEBUG) << __func__ << ": " << mType << ": returning port by id " << in_portId;
         return ndk::ScopedAStatus::ok();
     }
-    LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+    LOG(ERROR) << __func__ << ": " << mType << ": port id " << in_portId << " not found";
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
 }
 
 ndk::ScopedAStatus Module::getAudioPortConfigs(std::vector<AudioPortConfig>* _aidl_return) {
     *_aidl_return = getConfig().portConfigs;
-    LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " port configs";
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning " << _aidl_return->size()
+               << " port configs";
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::getAudioPorts(std::vector<AudioPort>* _aidl_return) {
     *_aidl_return = getConfig().ports;
-    LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " ports";
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning " << _aidl_return->size() << " ports";
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::getAudioRoutes(std::vector<AudioRoute>* _aidl_return) {
     *_aidl_return = getConfig().routes;
-    LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " routes";
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning " << _aidl_return->size() << " routes";
     return ndk::ScopedAStatus::ok();
 }
 
@@ -823,7 +842,7 @@
                                                       std::vector<AudioRoute>* _aidl_return) {
     auto& ports = getConfig().ports;
     if (auto portIt = findById<AudioPort>(ports, in_portId); portIt == ports.end()) {
-        LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << in_portId << " not found";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     std::vector<AudioRoute*> routes = getAudioRoutesForAudioPortImpl(in_portId);
@@ -834,12 +853,12 @@
 
 ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_args,
                                            OpenInputStreamReturn* _aidl_return) {
-    LOG(DEBUG) << __func__ << ": port config id " << in_args.portConfigId << ", buffer size "
-               << in_args.bufferSizeFrames << " frames";
+    LOG(DEBUG) << __func__ << ": " << mType << ": port config id " << in_args.portConfigId
+               << ", buffer size " << in_args.bufferSizeFrames << " frames";
     AudioPort* port = nullptr;
     RETURN_STATUS_IF_ERROR(findPortIdForNewStream(in_args.portConfigId, &port));
     if (port->flags.getTag() != AudioIoFlags::Tag::input) {
-        LOG(ERROR) << __func__ << ": port config id " << in_args.portConfigId
+        LOG(ERROR) << __func__ << ": " << mType << ": port config id " << in_args.portConfigId
                    << " does not correspond to an input mix port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
@@ -864,27 +883,27 @@
 
 ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_args,
                                             OpenOutputStreamReturn* _aidl_return) {
-    LOG(DEBUG) << __func__ << ": port config id " << in_args.portConfigId << ", has offload info? "
-               << (in_args.offloadInfo.has_value()) << ", buffer size " << in_args.bufferSizeFrames
-               << " frames";
+    LOG(DEBUG) << __func__ << ": " << mType << ": port config id " << in_args.portConfigId
+               << ", has offload info? " << (in_args.offloadInfo.has_value()) << ", buffer size "
+               << in_args.bufferSizeFrames << " frames";
     AudioPort* port = nullptr;
     RETURN_STATUS_IF_ERROR(findPortIdForNewStream(in_args.portConfigId, &port));
     if (port->flags.getTag() != AudioIoFlags::Tag::output) {
-        LOG(ERROR) << __func__ << ": port config id " << in_args.portConfigId
+        LOG(ERROR) << __func__ << ": " << mType << ": port config id " << in_args.portConfigId
                    << " does not correspond to an output mix port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     const bool isOffload = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
                                                 AudioOutputFlags::COMPRESS_OFFLOAD);
     if (isOffload && !in_args.offloadInfo.has_value()) {
-        LOG(ERROR) << __func__ << ": port id " << port->id
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << port->id
                    << " has COMPRESS_OFFLOAD flag set, requires offload info";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     const bool isNonBlocking = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
                                                     AudioOutputFlags::NON_BLOCKING);
     if (isNonBlocking && in_args.callback == nullptr) {
-        LOG(ERROR) << __func__ << ": port id " << port->id
+        LOG(ERROR) << __func__ << ": " << mType << ": port id " << port->id
                    << " has NON_BLOCKING flag set, requires async callback";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
@@ -910,27 +929,29 @@
 
 ndk::ScopedAStatus Module::getSupportedPlaybackRateFactors(
         SupportedPlaybackRateFactors* _aidl_return) {
-    LOG(DEBUG) << __func__;
+    LOG(DEBUG) << __func__ << ": " << mType;
     (void)_aidl_return;
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
 ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPatch* _aidl_return) {
-    LOG(DEBUG) << __func__ << ": requested patch " << in_requested.toString();
+    LOG(DEBUG) << __func__ << ": " << mType << ": requested patch " << in_requested.toString();
     if (in_requested.sourcePortConfigIds.empty()) {
-        LOG(ERROR) << __func__ << ": requested patch has empty sources list";
+        LOG(ERROR) << __func__ << ": " << mType << ": requested patch has empty sources list";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     if (!all_unique<int32_t>(in_requested.sourcePortConfigIds)) {
-        LOG(ERROR) << __func__ << ": requested patch has duplicate ids in the sources list";
+        LOG(ERROR) << __func__ << ": " << mType
+                   << ": requested patch has duplicate ids in the sources list";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     if (in_requested.sinkPortConfigIds.empty()) {
-        LOG(ERROR) << __func__ << ": requested patch has empty sinks list";
+        LOG(ERROR) << __func__ << ": " << mType << ": requested patch has empty sinks list";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     if (!all_unique<int32_t>(in_requested.sinkPortConfigIds)) {
-        LOG(ERROR) << __func__ << ": requested patch has duplicate ids in the sinks list";
+        LOG(ERROR) << __func__ << ": " << mType
+                   << ": requested patch has duplicate ids in the sinks list";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 
@@ -939,13 +960,13 @@
     auto sources =
             selectByIds<AudioPortConfig>(configs, in_requested.sourcePortConfigIds, &missingIds);
     if (!missingIds.empty()) {
-        LOG(ERROR) << __func__ << ": following source port config ids not found: "
+        LOG(ERROR) << __func__ << ": " << mType << ": following source port config ids not found: "
                    << ::android::internal::ToString(missingIds);
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     auto sinks = selectByIds<AudioPortConfig>(configs, in_requested.sinkPortConfigIds, &missingIds);
     if (!missingIds.empty()) {
-        LOG(ERROR) << __func__ << ": following sink port config ids not found: "
+        LOG(ERROR) << __func__ << ": " << mType << ": following sink port config ids not found: "
                    << ::android::internal::ToString(missingIds);
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
@@ -966,7 +987,8 @@
     }
     for (auto sink : sinks) {
         if (allowedSinkPorts.count(sink->portId) == 0) {
-            LOG(ERROR) << __func__ << ": there is no route to the sink port id " << sink->portId;
+            LOG(ERROR) << __func__ << ": " << mType << ": there is no route to the sink port id "
+                       << sink->portId;
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
     }
@@ -981,14 +1003,15 @@
             patchesBackup = mPatches;
             cleanUpPatch(existing->id);
         } else {
-            LOG(ERROR) << __func__ << ": not found existing patch id " << in_requested.id;
+            LOG(ERROR) << __func__ << ": " << mType << ": not found existing patch id "
+                       << in_requested.id;
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
     }
     // Validate the requested patch.
     for (const auto& [sinkPortId, nonExclusive] : allowedSinkPorts) {
         if (!nonExclusive && mPatches.count(sinkPortId) != 0) {
-            LOG(ERROR) << __func__ << ": sink port id " << sinkPortId
+            LOG(ERROR) << __func__ << ": " << mType << ": sink port id " << sinkPortId
                        << "is exclusive and is already used by some other patch";
             if (patchesBackup.has_value()) {
                 mPatches = std::move(*patchesBackup);
@@ -1031,8 +1054,8 @@
         return status;
     }
 
-    LOG(DEBUG) << __func__ << ": " << (oldPatch.id == 0 ? "created" : "updated") << " patch "
-               << _aidl_return->toString();
+    LOG(DEBUG) << __func__ << ": " << mType << ": " << (oldPatch.id == 0 ? "created" : "updated")
+               << " patch " << _aidl_return->toString();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -1050,28 +1073,29 @@
                                  ::aidl::android::media::audio::common::AudioPortConfig* config)>&
                 fillPortConfig,
         AudioPortConfig* out_suggested, bool* applied) {
-    LOG(DEBUG) << __func__ << ": requested " << in_requested.toString();
+    LOG(DEBUG) << __func__ << ": " << mType << ": requested " << in_requested.toString();
     auto& configs = getConfig().portConfigs;
     auto existing = configs.end();
     if (in_requested.id != 0) {
         if (existing = findById<AudioPortConfig>(configs, in_requested.id);
             existing == configs.end()) {
-            LOG(ERROR) << __func__ << ": existing port config id " << in_requested.id
-                       << " not found";
+            LOG(ERROR) << __func__ << ": " << mType << ": existing port config id "
+                       << in_requested.id << " not found";
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
     }
 
     const int portId = existing != configs.end() ? existing->portId : in_requested.portId;
     if (portId == 0) {
-        LOG(ERROR) << __func__ << ": requested port config does not specify portId";
+        LOG(ERROR) << __func__ << ": " << mType
+                   << ": requested port config does not specify portId";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     auto& ports = getConfig().ports;
     auto portIt = findById<AudioPort>(ports, portId);
     if (portIt == ports.end()) {
-        LOG(ERROR) << __func__ << ": requested port config points to non-existent portId "
-                   << portId;
+        LOG(ERROR) << __func__ << ": " << mType
+                   << ": requested port config points to non-existent portId " << portId;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     if (existing != configs.end()) {
@@ -1082,7 +1106,8 @@
         if (fillPortConfig(*portIt, &newConfig)) {
             *out_suggested = newConfig;
         } else {
-            LOG(ERROR) << __func__ << ": unable generate a default config for port " << portId;
+            LOG(ERROR) << __func__ << ": " << mType
+                       << ": unable generate a default config for port " << portId;
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
     }
@@ -1099,7 +1124,7 @@
     AudioIoFlags portFlags = portIt->flags;
     if (in_requested.flags.has_value()) {
         if (in_requested.flags.value() != portFlags) {
-            LOG(WARNING) << __func__ << ": requested flags "
+            LOG(WARNING) << __func__ << ": " << mType << ": requested flags "
                          << in_requested.flags.value().toString() << " do not match port's "
                          << portId << " flags " << portFlags.toString();
             requestedIsValid = false;
@@ -1115,7 +1140,7 @@
             findAudioProfile(*portIt, format, &portProfile)) {
             out_suggested->format = format;
         } else {
-            LOG(WARNING) << __func__ << ": requested format " << format.toString()
+            LOG(WARNING) << __func__ << ": " << mType << ": requested format " << format.toString()
                          << " is not found in the profiles of port " << portId;
             requestedIsValid = false;
         }
@@ -1124,8 +1149,9 @@
     }
     if (!(out_suggested->format.value() == AudioFormatDescription{} && allowDynamicConfig) &&
         !findAudioProfile(*portIt, out_suggested->format.value(), &portProfile)) {
-        LOG(ERROR) << __func__ << ": port " << portId << " does not support format "
-                   << out_suggested->format.value().toString() << " anymore";
+        LOG(ERROR) << __func__ << ": " << mType << ": port " << portId
+                   << " does not support format " << out_suggested->format.value().toString()
+                   << " anymore";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 
@@ -1136,9 +1162,9 @@
                     portProfile.channelMasks.end()) {
             out_suggested->channelMask = channelMask;
         } else {
-            LOG(WARNING) << __func__ << ": requested channel mask " << channelMask.toString()
-                         << " is not supported for the format " << portProfile.format.toString()
-                         << " by the port " << portId;
+            LOG(WARNING) << __func__ << ": " << mType << ": requested channel mask "
+                         << channelMask.toString() << " is not supported for the format "
+                         << portProfile.format.toString() << " by the port " << portId;
             requestedIsValid = false;
         }
     } else {
@@ -1152,9 +1178,9 @@
                  sampleRate.value) != portProfile.sampleRates.end()) {
             out_suggested->sampleRate = sampleRate;
         } else {
-            LOG(WARNING) << __func__ << ": requested sample rate " << sampleRate.value
-                         << " is not supported for the format " << portProfile.format.toString()
-                         << " by the port " << portId;
+            LOG(WARNING) << __func__ << ": " << mType << ": requested sample rate "
+                         << sampleRate.value << " is not supported for the format "
+                         << portProfile.format.toString() << " by the port " << portId;
             requestedIsValid = false;
         }
     } else {
@@ -1169,12 +1195,15 @@
     if (in_requested.ext.getTag() != AudioPortExt::Tag::unspecified) {
         if (in_requested.ext.getTag() == out_suggested->ext.getTag()) {
             if (out_suggested->ext.getTag() == AudioPortExt::Tag::mix) {
-                // 'AudioMixPortExt.handle' is set by the client, copy from in_requested
-                out_suggested->ext.get<AudioPortExt::Tag::mix>().handle =
-                        in_requested.ext.get<AudioPortExt::Tag::mix>().handle;
+                // 'AudioMixPortExt.handle' and '.usecase' are set by the client,
+                // copy from in_requested.
+                const auto& src = in_requested.ext.get<AudioPortExt::Tag::mix>();
+                auto& dst = out_suggested->ext.get<AudioPortExt::Tag::mix>();
+                dst.handle = src.handle;
+                dst.usecase = src.usecase;
             }
         } else {
-            LOG(WARNING) << __func__ << ": requested ext tag "
+            LOG(WARNING) << __func__ << ": " << mType << ": requested ext tag "
                          << toString(in_requested.ext.getTag()) << " do not match port's tag "
                          << toString(out_suggested->ext.getTag());
             requestedIsValid = false;
@@ -1185,15 +1214,17 @@
         out_suggested->id = getConfig().nextPortId++;
         configs.push_back(*out_suggested);
         *applied = true;
-        LOG(DEBUG) << __func__ << ": created new port config " << out_suggested->toString();
+        LOG(DEBUG) << __func__ << ": " << mType << ": created new port config "
+                   << out_suggested->toString();
     } else if (existing != configs.end() && requestedIsValid) {
         *existing = *out_suggested;
         *applied = true;
-        LOG(DEBUG) << __func__ << ": updated port config " << out_suggested->toString();
+        LOG(DEBUG) << __func__ << ": " << mType << ": updated port config "
+                   << out_suggested->toString();
     } else {
-        LOG(DEBUG) << __func__ << ": not applied; existing config ? " << (existing != configs.end())
-                   << "; requested is valid? " << requestedIsValid << ", fully specified? "
-                   << requestedIsFullySpecified;
+        LOG(DEBUG) << __func__ << ": " << mType << ": not applied; existing config ? "
+                   << (existing != configs.end()) << "; requested is valid? " << requestedIsValid
+                   << ", fully specified? " << requestedIsFullySpecified;
         *applied = false;
     }
     return ndk::ScopedAStatus::ok();
@@ -1210,10 +1241,10 @@
             return status;
         }
         patches.erase(patchIt);
-        LOG(DEBUG) << __func__ << ": erased patch " << in_patchId;
+        LOG(DEBUG) << __func__ << ": " << mType << ": erased patch " << in_patchId;
         return ndk::ScopedAStatus::ok();
     }
-    LOG(ERROR) << __func__ << ": patch id " << in_patchId << " not found";
+    LOG(ERROR) << __func__ << ": " << mType << ": patch id " << in_patchId << " not found";
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
 }
 
@@ -1222,13 +1253,13 @@
     auto configIt = findById<AudioPortConfig>(configs, in_portConfigId);
     if (configIt != configs.end()) {
         if (mStreams.count(in_portConfigId) != 0) {
-            LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+            LOG(ERROR) << __func__ << ": " << mType << ": port config id " << in_portConfigId
                        << " has a stream opened on it";
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
         }
         auto patchIt = mPatches.find(in_portConfigId);
         if (patchIt != mPatches.end()) {
-            LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+            LOG(ERROR) << __func__ << ": " << mType << ": port config id " << in_portConfigId
                        << " is used by the patch with id " << patchIt->second;
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
         }
@@ -1236,32 +1267,33 @@
         auto initialIt = findById<AudioPortConfig>(initials, in_portConfigId);
         if (initialIt == initials.end()) {
             configs.erase(configIt);
-            LOG(DEBUG) << __func__ << ": erased port config " << in_portConfigId;
+            LOG(DEBUG) << __func__ << ": " << mType << ": erased port config " << in_portConfigId;
         } else if (*configIt != *initialIt) {
             *configIt = *initialIt;
-            LOG(DEBUG) << __func__ << ": reset port config " << in_portConfigId;
+            LOG(DEBUG) << __func__ << ": " << mType << ": reset port config " << in_portConfigId;
         }
         return ndk::ScopedAStatus::ok();
     }
-    LOG(ERROR) << __func__ << ": port config id " << in_portConfigId << " not found";
+    LOG(ERROR) << __func__ << ": " << mType << ": port config id " << in_portConfigId
+               << " not found";
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
 }
 
 ndk::ScopedAStatus Module::getMasterMute(bool* _aidl_return) {
     *_aidl_return = mMasterMute;
-    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning " << *_aidl_return;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::setMasterMute(bool in_mute) {
-    LOG(DEBUG) << __func__ << ": " << in_mute;
+    LOG(DEBUG) << __func__ << ": " << mType << ": " << in_mute;
     auto result = mDebug.simulateDeviceConnections ? ndk::ScopedAStatus::ok()
                                                    : onMasterMuteChanged(in_mute);
     if (result.isOk()) {
         mMasterMute = in_mute;
     } else {
-        LOG(ERROR) << __func__ << ": failed calling onMasterMuteChanged(" << in_mute
-                   << "), error=" << result;
+        LOG(ERROR) << __func__ << ": " << mType << ": failed calling onMasterMuteChanged("
+                   << in_mute << "), error=" << result;
         // Reset master mute if it failed.
         onMasterMuteChanged(mMasterMute);
     }
@@ -1270,12 +1302,12 @@
 
 ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
     *_aidl_return = mMasterVolume;
-    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning " << *_aidl_return;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::setMasterVolume(float in_volume) {
-    LOG(DEBUG) << __func__ << ": " << in_volume;
+    LOG(DEBUG) << __func__ << ": " << mType << ": " << in_volume;
     if (in_volume >= 0.0f && in_volume <= 1.0f) {
         auto result = mDebug.simulateDeviceConnections ? ndk::ScopedAStatus::ok()
                                                        : onMasterVolumeChanged(in_volume);
@@ -1283,51 +1315,52 @@
             mMasterVolume = in_volume;
         } else {
             // Reset master volume if it failed.
-            LOG(ERROR) << __func__ << ": failed calling onMasterVolumeChanged(" << in_volume
-                       << "), error=" << result;
+            LOG(ERROR) << __func__ << ": " << mType << ": failed calling onMasterVolumeChanged("
+                       << in_volume << "), error=" << result;
             onMasterVolumeChanged(mMasterVolume);
         }
         return result;
     }
-    LOG(ERROR) << __func__ << ": invalid master volume value: " << in_volume;
+    LOG(ERROR) << __func__ << ": " << mType << ": invalid master volume value: " << in_volume;
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
 }
 
 ndk::ScopedAStatus Module::getMicMute(bool* _aidl_return) {
     *_aidl_return = mMicMute;
-    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning " << *_aidl_return;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::setMicMute(bool in_mute) {
-    LOG(DEBUG) << __func__ << ": " << in_mute;
+    LOG(DEBUG) << __func__ << ": " << mType << ": " << in_mute;
     mMicMute = in_mute;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::getMicrophones(std::vector<MicrophoneInfo>* _aidl_return) {
     *_aidl_return = getMicrophoneInfos();
-    LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning "
+               << ::android::internal::ToString(*_aidl_return);
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::updateAudioMode(AudioMode in_mode) {
     if (!isValidAudioMode(in_mode)) {
-        LOG(ERROR) << __func__ << ": invalid mode " << toString(in_mode);
+        LOG(ERROR) << __func__ << ": " << mType << ": invalid mode " << toString(in_mode);
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     // No checks for supported audio modes here, it's an informative notification.
-    LOG(DEBUG) << __func__ << ": " << toString(in_mode);
+    LOG(DEBUG) << __func__ << ": " << mType << ": " << toString(in_mode);
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::updateScreenRotation(ScreenRotation in_rotation) {
-    LOG(DEBUG) << __func__ << ": " << toString(in_rotation);
+    LOG(DEBUG) << __func__ << ": " << mType << ": " << toString(in_rotation);
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::updateScreenState(bool in_isTurnedOn) {
-    LOG(DEBUG) << __func__ << ": " << in_isTurnedOn;
+    LOG(DEBUG) << __func__ << ": " << mType << ": " << in_isTurnedOn;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -1336,12 +1369,13 @@
         mSoundDose = ndk::SharedRefBase::make<sounddose::SoundDose>();
     }
     *_aidl_return = mSoundDose.getInstance();
-    LOG(DEBUG) << __func__ << ": returning instance of ISoundDose: " << _aidl_return->get();
+    LOG(DEBUG) << __func__ << ": " << mType
+               << ": returning instance of ISoundDose: " << _aidl_return->get();
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::generateHwAvSyncId(int32_t* _aidl_return) {
-    LOG(DEBUG) << __func__;
+    LOG(DEBUG) << __func__ << ": " << mType;
     (void)_aidl_return;
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
@@ -1351,7 +1385,7 @@
 
 ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
                                                std::vector<VendorParameter>* _aidl_return) {
-    LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
+    LOG(VERBOSE) << __func__ << ": " << mType << ": id count: " << in_ids.size();
     bool allParametersKnown = true;
     for (const auto& id : in_ids) {
         if (id == VendorDebug::kForceTransientBurstName) {
@@ -1364,7 +1398,7 @@
             _aidl_return->push_back(std::move(forceSynchronousDrain));
         } else {
             allParametersKnown = false;
-            LOG(ERROR) << __func__ << ": unrecognized parameter \"" << id << "\"";
+            LOG(VERBOSE) << __func__ << ": " << mType << ": unrecognized parameter \"" << id << "\"";
         }
     }
     if (allParametersKnown) return ndk::ScopedAStatus::ok();
@@ -1390,8 +1424,8 @@
 
 ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter>& in_parameters,
                                                bool in_async) {
-    LOG(DEBUG) << __func__ << ": parameter count " << in_parameters.size()
-               << ", async: " << in_async;
+    LOG(VERBOSE) << __func__ << ": " << mType << ": parameter count " << in_parameters.size()
+                 << ", async: " << in_async;
     bool allParametersKnown = true;
     for (const auto& p : in_parameters) {
         if (p.id == VendorDebug::kForceTransientBurstName) {
@@ -1404,7 +1438,8 @@
             }
         } else {
             allParametersKnown = false;
-            LOG(ERROR) << __func__ << ": unrecognized parameter \"" << p.id << "\"";
+            LOG(VERBOSE) << __func__ << ": " << mType << ": unrecognized parameter \"" << p.id
+                         << "\"";
         }
     }
     if (allParametersKnown) return ndk::ScopedAStatus::ok();
@@ -1415,10 +1450,11 @@
         int32_t in_portConfigId,
         const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
     if (in_effect == nullptr) {
-        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", null effect";
+        LOG(DEBUG) << __func__ << ": " << mType << ": port id " << in_portConfigId
+                   << ", null effect";
     } else {
-        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", effect Binder "
-                   << in_effect->asBinder().get();
+        LOG(DEBUG) << __func__ << ": " << mType << ": port id " << in_portConfigId
+                   << ", effect Binder " << in_effect->asBinder().get();
     }
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
@@ -1427,17 +1463,18 @@
         int32_t in_portConfigId,
         const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
     if (in_effect == nullptr) {
-        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", null effect";
+        LOG(DEBUG) << __func__ << ": " << mType << ": port id " << in_portConfigId
+                   << ", null effect";
     } else {
-        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", effect Binder "
-                   << in_effect->asBinder().get();
+        LOG(DEBUG) << __func__ << ": " << mType << ": port id " << in_portConfigId
+                   << ", effect Binder " << in_effect->asBinder().get();
     }
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
 ndk::ScopedAStatus Module::getMmapPolicyInfos(AudioMMapPolicyType mmapPolicyType,
                                               std::vector<AudioMMapPolicyInfo>* _aidl_return) {
-    LOG(DEBUG) << __func__ << ": mmap policy type " << toString(mmapPolicyType);
+    LOG(DEBUG) << __func__ << ": " << mType << ": mmap policy type " << toString(mmapPolicyType);
     std::set<int32_t> mmapSinks;
     std::set<int32_t> mmapSources;
     auto& ports = getConfig().ports;
@@ -1465,7 +1502,8 @@
                 auto sourcePortIt = findById<AudioPort>(ports, sourcePortId);
                 if (sourcePortIt == ports.end()) {
                     // This must not happen
-                    LOG(ERROR) << __func__ << ": port id " << sourcePortId << " cannot be found";
+                    LOG(ERROR) << __func__ << ": " << mType << ": port id " << sourcePortId
+                               << " cannot be found";
                     continue;
                 }
                 if (sourcePortIt->ext.getTag() != AudioPortExt::Tag::device) {
@@ -1483,7 +1521,8 @@
             auto sinkPortIt = findById<AudioPort>(ports, route.sinkPortId);
             if (sinkPortIt == ports.end()) {
                 // This must not happen
-                LOG(ERROR) << __func__ << ": port id " << route.sinkPortId << " cannot be found";
+                LOG(ERROR) << __func__ << ": " << mType << ": port id " << route.sinkPortId
+                           << " cannot be found";
                 continue;
             }
             if (sinkPortIt->ext.getTag() != AudioPortExt::Tag::device) {
@@ -1504,28 +1543,28 @@
 }
 
 ndk::ScopedAStatus Module::supportsVariableLatency(bool* _aidl_return) {
-    LOG(DEBUG) << __func__;
+    LOG(DEBUG) << __func__ << ": " << mType;
     *_aidl_return = false;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::getAAudioMixerBurstCount(int32_t* _aidl_return) {
     if (!isMmapSupported()) {
-        LOG(DEBUG) << __func__ << ": mmap is not supported ";
+        LOG(DEBUG) << __func__ << ": " << mType << ": mmap is not supported ";
         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
     }
     *_aidl_return = DEFAULT_AAUDIO_MIXER_BURST_COUNT;
-    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning " << *_aidl_return;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) {
     if (!isMmapSupported()) {
-        LOG(DEBUG) << __func__ << ": mmap is not supported ";
+        LOG(DEBUG) << __func__ << ": " << mType << ": mmap is not supported ";
         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
     }
     *_aidl_return = DEFAULT_AAUDIO_HARDWARE_BURST_MIN_DURATION_US;
-    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    LOG(DEBUG) << __func__ << ": " << mType << ": returning " << *_aidl_return;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -1548,45 +1587,45 @@
 
 ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
     if (audioPort->ext.getTag() != AudioPortExt::device) {
-        LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
+        LOG(ERROR) << __func__ << ": " << mType << ": not a device port: " << audioPort->toString();
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     const auto& devicePort = audioPort->ext.get<AudioPortExt::device>();
     if (!devicePort.device.type.connection.empty()) {
-        LOG(ERROR) << __func__
-                   << ": module implementation must override 'populateConnectedDevicePort' "
+        LOG(ERROR) << __func__ << ": " << mType << ": module implementation must override "
+                                                  "'populateConnectedDevicePort' "
                    << "to handle connection of external devices.";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
-    LOG(VERBOSE) << __func__ << ": do nothing and return ok";
+    LOG(VERBOSE) << __func__ << ": " << mType << ": do nothing and return ok";
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::checkAudioPatchEndpointsMatch(
         const std::vector<AudioPortConfig*>& sources __unused,
         const std::vector<AudioPortConfig*>& sinks __unused) {
-    LOG(VERBOSE) << __func__ << ": do nothing and return ok";
+    LOG(VERBOSE) << __func__ << ": " << mType << ": do nothing and return ok";
     return ndk::ScopedAStatus::ok();
 }
 
 void Module::onExternalDeviceConnectionChanged(
         const ::aidl::android::media::audio::common::AudioPort& audioPort __unused,
         bool connected __unused) {
-    LOG(DEBUG) << __func__ << ": do nothing and return";
+    LOG(DEBUG) << __func__ << ": " << mType << ": do nothing and return";
 }
 
 void Module::onPrepareToDisconnectExternalDevice(
         const ::aidl::android::media::audio::common::AudioPort& audioPort __unused) {
-    LOG(DEBUG) << __func__ << ": do nothing and return";
+    LOG(DEBUG) << __func__ << ": " << mType << ": do nothing and return";
 }
 
 ndk::ScopedAStatus Module::onMasterMuteChanged(bool mute __unused) {
-    LOG(VERBOSE) << __func__ << ": do nothing and return ok";
+    LOG(VERBOSE) << __func__ << ": " << mType << ": do nothing and return ok";
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Module::onMasterVolumeChanged(float volume __unused) {
-    LOG(VERBOSE) << __func__ << ": do nothing and return ok";
+    LOG(VERBOSE) << __func__ << ": " << mType << ": do nothing and return ok";
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/audio/aidl/default/apex/com.android.hardware.audio/Android.bp b/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
index ee7e46e..ee92512 100644
--- a/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
+++ b/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
@@ -46,5 +46,6 @@
     prebuilts: [
         "android.hardware.audio.service-aidl.example.rc",
         "android.hardware.audio.service-aidl.xml",
+        "android.hardware.bluetooth.audio.xml",
     ],
 }
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index d219fa4..337089d 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -151,6 +151,9 @@
     name: "VtsHalVirtualizerTargetTest",
     defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalVirtualizerTargetTest.cpp"],
+    shared_libs: [
+        "libaudioutils",
+    ],
 }
 
 cc_test {
diff --git a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
index 0c24f90..b4a2f41 100644
--- a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
@@ -16,11 +16,14 @@
 
 #define LOG_TAG "VtsHalVirtualizerTest"
 #include <android-base/logging.h>
+#include <audio_utils/power.h>
+#include <system/audio.h>
 
 #include "EffectHelper.h"
 
 using namespace android;
 
+using aidl::android::hardware::audio::common::getChannelCount;
 using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::getEffectTypeUuidVirtualizer;
 using aidl::android::hardware::audio::effect::IEffect;
@@ -29,6 +32,82 @@
 using aidl::android::hardware::audio::effect::Virtualizer;
 using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
+class VirtualizerHelper : public EffectHelper {
+  public:
+    void SetUpVirtualizer() {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+        initFrameCount();
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
+                kSamplingFrequency /* oSampleRate */, mInputFrameCount /* iFrameCount */,
+                mInputFrameCount /* oFrameCount */);
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDownVirtualizer() {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+        mOpenEffectReturn = IEffect::OpenEffectReturn{};
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        Virtualizer vr = Virtualizer::make<Virtualizer::strengthPm>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::virtualizer>(vr);
+        return specific;
+    }
+
+    Parameter createVirtualizerStrengthParam(int param) {
+        return Parameter::make<Parameter::specific>(
+                Parameter::Specific::make<Parameter::Specific::virtualizer>(
+                        Virtualizer::make<Virtualizer::strengthPm>(param)));
+    }
+
+    void initFrameCount() {
+        mInputFrameCount = kBufferSize / kChannelCount;
+        mOutputFrameCount = kBufferSize / kChannelCount;
+    }
+
+    bool isStrengthValid(int level) {
+        auto vir = Virtualizer::make<Virtualizer::strengthPm>(level);
+        return isParameterValid<Virtualizer, Range::virtualizer>(vir, mDescriptor);
+    }
+
+    void setAndVerifyStrength(int param, binder_exception_t expected) {
+        auto expectedParam = createVirtualizerStrengthParam(param);
+        EXPECT_STATUS(expected, mEffect->setParameter(expectedParam)) << expectedParam.toString();
+
+        if (expected == EX_NONE) {
+            Virtualizer::Id vrlId =
+                    Virtualizer::Id::make<Virtualizer::Id::commonTag>(Virtualizer::strengthPm);
+
+            auto id = Parameter::Id::make<Parameter::Id::virtualizerTag>(vrlId);
+            // get parameter
+            Parameter getParam;
+            // if set success, then get should match
+            EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+            EXPECT_EQ(expectedParam, getParam) << "\nexpectedParam:" << expectedParam.toString()
+                                               << "\ngetParam:" << getParam.toString();
+        }
+    }
+
+    static constexpr int kSamplingFrequency = 44100;
+    static constexpr int kDefaultChannelLayout = AudioChannelLayout::LAYOUT_STEREO;
+    static constexpr int kDurationMilliSec = 2000;
+    static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
+    int kChannelCount = getChannelCount(
+            AudioChannelLayout::make<AudioChannelLayout::layoutMask>(kDefaultChannelLayout));
+    long mInputFrameCount;
+    long mOutputFrameCount;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    IEffect::OpenEffectReturn mOpenEffectReturn;
+    Descriptor mDescriptor;
+};
+
 /**
  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
  * VtsAudioEffectTargetTest.
@@ -44,89 +123,82 @@
  */
 
 class VirtualizerParamTest : public ::testing::TestWithParam<VirtualizerParamTestParam>,
-                             public EffectHelper {
+                             public VirtualizerHelper {
   public:
     VirtualizerParamTest() : mParamStrength(std::get<PARAM_STRENGTH>(GetParam())) {
         std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
     }
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpVirtualizer()); }
+    void TearDown() override { TearDownVirtualizer(); }
 
-    void SetUp() override {
-        ASSERT_NE(nullptr, mFactory);
-        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
-
-        Parameter::Specific specific = getDefaultParamSpecific();
-        Parameter::Common common = EffectHelper::createParamCommon(
-                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
-                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
-        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
-        ASSERT_NE(nullptr, mEffect);
-    }
-
-    void TearDown() override {
-        ASSERT_NO_FATAL_FAILURE(close(mEffect));
-        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
-    }
-
-    Parameter::Specific getDefaultParamSpecific() {
-        Virtualizer vr = Virtualizer::make<Virtualizer::strengthPm>(0);
-        Parameter::Specific specific =
-                Parameter::Specific::make<Parameter::Specific::virtualizer>(vr);
-        return specific;
-    }
-
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
-    std::shared_ptr<IFactory> mFactory;
-    std::shared_ptr<IEffect> mEffect;
-    Descriptor mDescriptor;
     int mParamStrength = 0;
+};
 
-    void SetAndGetVirtualizerParameters() {
-        for (auto& it : mTags) {
-            auto& tag = it.first;
-            auto& vr = it.second;
+TEST_P(VirtualizerParamTest, SetAndGetStrength) {
+    ASSERT_NO_FATAL_FAILURE(setAndVerifyStrength(
+            mParamStrength, isStrengthValid(mParamStrength) ? EX_NONE : EX_ILLEGAL_ARGUMENT));
+}
 
-            // validate parameter
-            Descriptor desc;
-            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
-            const bool valid = isParameterValid<Virtualizer, Range::virtualizer>(it.second, desc);
-            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+enum ProcessTestParam { PROCESS_INSTANCE_NAME, PROCESS_ZERO_INPUT };
+using VirtualizerProcessTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, bool>;
 
-            // set parameter
-            Parameter expectParam;
-            Parameter::Specific specific;
-            specific.set<Parameter::Specific::virtualizer>(vr);
-            expectParam.set<Parameter::specific>(specific);
-            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+class VirtualizerProcessTest : public ::testing::TestWithParam<VirtualizerProcessTestParam>,
+                               public VirtualizerHelper {
+  public:
+    VirtualizerProcessTest() : mZeroInput(std::get<PROCESS_ZERO_INPUT>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PROCESS_INSTANCE_NAME>(GetParam());
+    }
 
-            // only get if parameter in range and set success
-            if (expected == EX_NONE) {
-                Parameter getParam;
-                Parameter::Id id;
-                Virtualizer::Id vrId;
-                vrId.set<Virtualizer::Id::commonTag>(tag);
-                id.set<Parameter::Id::virtualizerTag>(vrId);
-                // if set success, then get should match
-                EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
-                EXPECT_EQ(expectParam, getParam);
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpVirtualizer()); }
+    void TearDown() override { TearDownVirtualizer(); }
+
+    void generateInput(std::vector<float>& buffer) {
+        if (mZeroInput) {
+            std::fill(buffer.begin(), buffer.end(), 0);
+        } else {
+            int frequency = 100;
+            for (size_t i = 0; i < buffer.size(); i++) {
+                buffer[i] = sin(2 * M_PI * frequency * i / kSamplingFrequency);
             }
         }
     }
 
-    void addStrengthParam(int strength) {
-        Virtualizer vr;
-        vr.set<Virtualizer::strengthPm>(strength);
-        mTags.push_back({Virtualizer::strengthPm, vr});
-    }
-
-  private:
-    std::vector<std::pair<Virtualizer::Tag, Virtualizer>> mTags;
-    void CleanUp() { mTags.clear(); }
+    static constexpr float kAbsError = 0.00001;
+    bool mZeroInput;
 };
 
-TEST_P(VirtualizerParamTest, SetAndGetStrength) {
-    EXPECT_NO_FATAL_FAILURE(addStrengthParam(mParamStrength));
-    SetAndGetVirtualizerParameters();
+TEST_P(VirtualizerProcessTest, IncreasingStrength) {
+    std::vector<float> input(kBufferSize);
+    std::vector<float> output(kBufferSize);
+    std::vector<int> strengths = {250, 500, 750, 1000};
+
+    generateInput(input);
+
+    const float inputRmse =
+            audio_utils_compute_energy_mono(input.data(), AUDIO_FORMAT_PCM_FLOAT, input.size());
+
+    for (int strength : strengths) {
+        // Skipping the further steps for unnsupported Strength values
+        if (!isStrengthValid(strength)) {
+            continue;
+        }
+        setAndVerifyStrength(strength, EX_NONE);
+        ASSERT_NO_FATAL_FAILURE(
+                processAndWriteToOutput(input, output, mEffect, &mOpenEffectReturn));
+
+        const float outputRmse = audio_utils_compute_energy_mono(
+                output.data(), AUDIO_FORMAT_PCM_FLOAT, output.size());
+
+        if (inputRmse != 0) {
+            EXPECT_NE(outputRmse, 0);
+            if (strength != 0) {
+                EXPECT_GT(abs(outputRmse - inputRmse), kAbsError);
+            }
+        } else {
+            EXPECT_NEAR(outputRmse, inputRmse, kAbsError);
+        }
+    }
 }
 
 std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
@@ -149,6 +221,22 @@
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VirtualizerParamTest);
 
+INSTANTIATE_TEST_SUITE_P(
+        VirtualizerTest, VirtualizerProcessTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, getEffectTypeUuidVirtualizer())),
+                           testing::Bool()),
+        [](const testing::TestParamInfo<VirtualizerProcessTest::ParamType>& info) {
+            auto descriptor = std::get<PROCESS_INSTANCE_NAME>(info.param).second;
+            std::string isInputZero = std::to_string(std::get<PROCESS_ZERO_INPUT>(info.param));
+            std::string name = getPrefix(descriptor) + "_isInputZero_" + isInputZero;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VirtualizerProcessTest);
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
diff --git a/audio/common/2.0/Android.bp b/audio/common/2.0/Android.bp
index 450e04f..679d6b0 100644
--- a/audio/common/2.0/Android.bp
+++ b/audio/common/2.0/Android.bp
@@ -15,9 +15,6 @@
     root: "android.hardware",
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "types.hal",
     ],
diff --git a/automotive/evs/aidl/Android.bp b/automotive/evs/aidl/Android.bp
index 3bfe8f3..dfb15c6 100644
--- a/automotive/evs/aidl/Android.bp
+++ b/automotive/evs/aidl/Android.bp
@@ -42,9 +42,6 @@
             enabled: false,
         },
         ndk: {
-            vndk: {
-                enabled: false,
-            },
             min_sdk_version: "29",
         },
     },
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 4846bfb..f021f7b 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
@@ -449,7 +449,8 @@
         {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
                     .access = VehiclePropertyAccess::READ_WRITE,
                     .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_FRONT_ROW},
+                                    VehicleAreaConfig{.areaId = HVAC_REAR_ROW}}},
          .initialValue = {.int32Values = {0}}},
 
         {.config = {.prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h
index f58e09a..e866f70 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h
@@ -50,6 +50,9 @@
           VehicleAreaWheel::LEFT_REAR | VehicleAreaWheel::RIGHT_REAR);
 constexpr int SEAT_1_LEFT = (int)(VehicleAreaSeat::ROW_1_LEFT);
 constexpr int SEAT_1_RIGHT = (int)(VehicleAreaSeat::ROW_1_RIGHT);
+constexpr int HVAC_FRONT_ROW = (int)(VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_1_RIGHT);
+constexpr int HVAC_REAR_ROW = (int)(VehicleAreaSeat::ROW_2_LEFT | VehicleAreaSeat::ROW_2_CENTER |
+                                    VehicleAreaSeat::ROW_2_RIGHT);
 constexpr int HVAC_LEFT = (int)(VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_2_LEFT |
                                 VehicleAreaSeat::ROW_2_CENTER);
 constexpr int HVAC_RIGHT = (int)(VehicleAreaSeat::ROW_1_RIGHT | VehicleAreaSeat::ROW_2_RIGHT);
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/.hash b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/.hash
index b04a6b5..aae94d1 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/.hash
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/.hash
@@ -1 +1,2 @@
 a741c2814ba6e9852e106bc26e820d741f66ebb8
+2e101035a8abf667295ca2106bebb8850b9bdc9c
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/GetValueRequest.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/GetValueRequest.aidl
index d88cd8b..15a2024 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/GetValueRequest.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/GetValueRequest.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable GetValueRequest {
   long requestId;
   android.hardware.automotive.vehicle.VehiclePropValue prop;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/GetValueResult.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/GetValueResult.aidl
index 25f3575..a8e0ac8 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/GetValueResult.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/GetValueResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable GetValueResult {
   long requestId;
   android.hardware.automotive.vehicle.StatusCode status = android.hardware.automotive.vehicle.StatusCode.OK;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/RawPropValues.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/RawPropValues.aidl
index e7b0a13..80e81b2 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/RawPropValues.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/RawPropValues.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable RawPropValues {
   int[] int32Values = {};
   float[] floatValues;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SetValueRequest.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SetValueRequest.aidl
index 6a65307..9b392f5 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SetValueRequest.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SetValueRequest.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable SetValueRequest {
   long requestId;
   android.hardware.automotive.vehicle.VehiclePropValue value;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SetValueResult.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SetValueResult.aidl
index ec5fabb..57aa11f 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SetValueResult.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SetValueResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable SetValueResult {
   long requestId;
   android.hardware.automotive.vehicle.StatusCode status = android.hardware.automotive.vehicle.StatusCode.OK;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SubscribeOptions.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SubscribeOptions.aidl
index 91e7c14..1f89a01 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SubscribeOptions.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/SubscribeOptions.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable SubscribeOptions {
   int propId;
   int[] areaIds;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index 6960894..c8887d9 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehicleAreaConfig {
   int areaId;
   int minInt32Value;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropConfig.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
index 8602d2d..32dac44 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehiclePropConfig {
   int prop;
   android.hardware.automotive.vehicle.VehiclePropertyAccess access = android.hardware.automotive.vehicle.VehiclePropertyAccess.NONE;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropError.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropError.aidl
index 9835295..9d49f1d 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropError.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropError.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehiclePropError {
   int propId;
   int areaId;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropValue.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropValue.aidl
index c87379f..f9feff5 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropValue.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/2/android/hardware/automotive/vehicle/VehiclePropValue.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehiclePropValue {
   long timestamp;
   int areaId;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/.hash b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/.hash
index 312f858..ce35dbb 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/.hash
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/.hash
@@ -1 +1,2 @@
 c6f1cc74f83dc53c6a5c08e6dbbb6e25e83e3a6b
+c046ced69d333e4470cd211e2159cce84faae233
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/GetValueRequest.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/GetValueRequest.aidl
index d88cd8b..15a2024 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/GetValueRequest.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/GetValueRequest.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable GetValueRequest {
   long requestId;
   android.hardware.automotive.vehicle.VehiclePropValue prop;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/GetValueResult.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/GetValueResult.aidl
index 25f3575..a8e0ac8 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/GetValueResult.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/GetValueResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable GetValueResult {
   long requestId;
   android.hardware.automotive.vehicle.StatusCode status = android.hardware.automotive.vehicle.StatusCode.OK;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/RawPropValues.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/RawPropValues.aidl
index e7b0a13..80e81b2 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/RawPropValues.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/RawPropValues.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable RawPropValues {
   int[] int32Values = {};
   float[] floatValues;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SetValueRequest.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SetValueRequest.aidl
index 6a65307..9b392f5 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SetValueRequest.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SetValueRequest.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable SetValueRequest {
   long requestId;
   android.hardware.automotive.vehicle.VehiclePropValue value;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SetValueResult.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SetValueResult.aidl
index ec5fabb..57aa11f 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SetValueResult.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SetValueResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable SetValueResult {
   long requestId;
   android.hardware.automotive.vehicle.StatusCode status = android.hardware.automotive.vehicle.StatusCode.OK;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SubscribeOptions.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SubscribeOptions.aidl
index 1b1696b..3e19ede 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SubscribeOptions.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/SubscribeOptions.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable SubscribeOptions {
   int propId;
   int[] areaIds;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index 08d4ee4..eb3028e 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehicleAreaConfig {
   int areaId;
   int minInt32Value;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropConfig.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
index 8602d2d..32dac44 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehiclePropConfig {
   int prop;
   android.hardware.automotive.vehicle.VehiclePropertyAccess access = android.hardware.automotive.vehicle.VehiclePropertyAccess.NONE;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropError.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropError.aidl
index 9835295..9d49f1d 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropError.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropError.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehiclePropError {
   int propId;
   int areaId;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropValue.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropValue.aidl
index c87379f..f9feff5 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropValue.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/3/android/hardware/automotive/vehicle/VehiclePropValue.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehiclePropValue {
   long timestamp;
   int areaId;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequest.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequest.aidl
index d88cd8b..15a2024 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequest.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequest.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable GetValueRequest {
   long requestId;
   android.hardware.automotive.vehicle.VehiclePropValue prop;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueResult.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueResult.aidl
index 25f3575..a8e0ac8 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueResult.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable GetValueResult {
   long requestId;
   android.hardware.automotive.vehicle.StatusCode status = android.hardware.automotive.vehicle.StatusCode.OK;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/RawPropValues.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/RawPropValues.aidl
index e7b0a13..80e81b2 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/RawPropValues.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/RawPropValues.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable RawPropValues {
   int[] int32Values = {};
   float[] floatValues;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl
index 6a65307..9b392f5 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable SetValueRequest {
   long requestId;
   android.hardware.automotive.vehicle.VehiclePropValue value;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueResult.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueResult.aidl
index ec5fabb..57aa11f 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueResult.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable SetValueResult {
   long requestId;
   android.hardware.automotive.vehicle.StatusCode status = android.hardware.automotive.vehicle.StatusCode.OK;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SubscribeOptions.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SubscribeOptions.aidl
index 1b1696b..3e19ede 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SubscribeOptions.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SubscribeOptions.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable SubscribeOptions {
   int propId;
   int[] areaIds;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index 08d4ee4..eb3028e 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehicleAreaConfig {
   int areaId;
   int minInt32Value;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropConfig.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
index 8602d2d..32dac44 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehiclePropConfig {
   int prop;
   android.hardware.automotive.vehicle.VehiclePropertyAccess access = android.hardware.automotive.vehicle.VehiclePropertyAccess.NONE;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropError.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropError.aidl
index 9835295..9d49f1d 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropError.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropError.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehiclePropError {
   int propId;
   int areaId;
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropValue.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropValue.aidl
index c87379f..f9feff5 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropValue.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehiclePropValue.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.automotive.vehicle;
-@JavaDerive(equals=true, toString=true) @VintfStability
+@JavaDerive(equals=true, toString=true) @RustDerive(Clone=true) @VintfStability
 parcelable VehiclePropValue {
   long timestamp;
   int areaId;
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequest.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequest.aidl
index e5b3929..1989b3e 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequest.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequest.aidl
@@ -20,6 +20,7 @@
 
 @VintfStability
 @JavaDerive(equals=true, toString=true)
+@RustDerive(Clone=true)
 parcelable GetValueRequest {
     // A unique request ID. For every client, the request ID must start with 1
     // and monotonically increase for every SetValueRequest. If it hits
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueResult.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueResult.aidl
index 24c5757..208c882 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueResult.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueResult.aidl
@@ -21,6 +21,7 @@
 
 @VintfStability
 @JavaDerive(equals=true, toString=true)
+@RustDerive(Clone=true)
 parcelable GetValueResult {
     // The ID for the request this response is for.
     long requestId;
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/RawPropValues.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/RawPropValues.aidl
index 28ccc1d..032882d 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/RawPropValues.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/RawPropValues.aidl
@@ -18,6 +18,7 @@
 
 @VintfStability
 @JavaDerive(equals=true, toString=true)
+@RustDerive(Clone=true)
 parcelable RawPropValues {
     /**
      * This is used for properties of types VehiclePropertyType#INT32,
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl
index 625f901..c8d413d 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl
@@ -20,6 +20,7 @@
 
 @VintfStability
 @JavaDerive(equals=true, toString=true)
+@RustDerive(Clone=true)
 parcelable SetValueRequest {
     // A unique request ID. For every client, the request ID must start with 1
     // and monotonically increase for every SetValueRequest. If it hits
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueResult.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueResult.aidl
index b3feeaa..673f812 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueResult.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueResult.aidl
@@ -20,6 +20,7 @@
 
 @VintfStability
 @JavaDerive(equals=true, toString=true)
+@RustDerive(Clone=true)
 parcelable SetValueResult {
     // The ID for the request this response is for.
     long requestId;
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl
index 14469b5..decd859 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl
@@ -21,6 +21,7 @@
  */
 @VintfStability
 @JavaDerive(equals=true, toString=true)
+@RustDerive(Clone=true)
 parcelable SubscribeOptions {
     /** Property to subscribe */
     int propId;
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index 96c4a74..726d419 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -20,6 +20,7 @@
 
 @VintfStability
 @JavaDerive(equals=true, toString=true)
+@RustDerive(Clone=true)
 parcelable VehicleAreaConfig {
     /**
      * Area id is always 0 for VehicleArea#GLOBAL properties.
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropConfig.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
index c629b82..3109621 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
@@ -22,6 +22,7 @@
 
 @VintfStability
 @JavaDerive(equals=true, toString=true)
+@RustDerive(Clone=true)
 parcelable VehiclePropConfig {
     /** Property identifier */
     int prop;
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropError.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropError.aidl
index 2c31c72..7c38b91 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropError.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropError.aidl
@@ -20,6 +20,7 @@
 
 @VintfStability
 @JavaDerive(equals=true, toString=true)
+@RustDerive(Clone=true)
 parcelable VehiclePropError {
     // Property ID.
     int propId;
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropValue.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropValue.aidl
index 289f270..c78c635 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropValue.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropValue.aidl
@@ -26,6 +26,7 @@
  */
 @VintfStability
 @JavaDerive(equals=true, toString=true)
+@RustDerive(Clone=true)
 parcelable VehiclePropValue {
     /** Time is elapsed nanoseconds since boot */
     long timestamp;
diff --git a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
index c812326..1cfeb72 100644
--- a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
+++ b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
@@ -124,7 +124,7 @@
                 "value": 290521862
             },
             {
-                "name": "FUEL_LEVEL",
+                "name": "Fuel level in milliliters",
                 "value": 291504903
             },
             {
@@ -277,7 +277,7 @@
                 "value": 358614274
             },
             {
-                "name": "HVAC, target temperature set.",
+                "name": "HVAC_TEMPERATURE_SET",
                 "value": 358614275
             },
             {
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/VersionForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/VersionForVehicleProperty.h
index 1c1035d..0e80bd8 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/VersionForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/VersionForVehicleProperty.h
@@ -84,7 +84,7 @@
         {VehicleProperty::TRACTION_CONTROL_ACTIVE, 2},
         {VehicleProperty::EV_STOPPING_MODE, 2},
         {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_ENABLED, 3},
-        {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE, 2},
+        {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE, 3},
         {VehicleProperty::HVAC_FAN_SPEED, 2},
         {VehicleProperty::HVAC_FAN_DIRECTION, 2},
         {VehicleProperty::HVAC_TEMPERATURE_CURRENT, 2},
@@ -172,8 +172,8 @@
         {VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, 2},
         {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, 2},
         {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, 2},
-        {VehicleProperty::SEAT_AIRBAG_ENABLED, 3},
-        {VehicleProperty::SEAT_AIRBAGS_DEPLOYED, 2},
+        {VehicleProperty::SEAT_AIRBAG_ENABLED, 2},
+        {VehicleProperty::SEAT_AIRBAGS_DEPLOYED, 3},
         {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, 2},
         {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE, 2},
         {VehicleProperty::SEAT_LUMBAR_VERTICAL_POS, 2},
@@ -293,7 +293,7 @@
         {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING, 3},
         {VehicleProperty::DRIVER_DISTRACTION_SYSTEM_ENABLED, 3},
         {VehicleProperty::DRIVER_DISTRACTION_STATE, 3},
-        {VehicleProperty::DRIVER_DISTRACTION_WARNING_ENABLED, 2},
+        {VehicleProperty::DRIVER_DISTRACTION_WARNING_ENABLED, 3},
         {VehicleProperty::DRIVER_DISTRACTION_WARNING, 3},
         {VehicleProperty::LOW_SPEED_COLLISION_WARNING_ENABLED, 3},
         {VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE, 3},
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index ea1437e..57af04c 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -104,6 +104,8 @@
         {"HVAC_ALL", HVAC_ALL},
         {"HVAC_LEFT", HVAC_LEFT},
         {"HVAC_RIGHT", HVAC_RIGHT},
+        {"HVAC_FRONT_ROW", HVAC_FRONT_ROW},
+        {"HVAC_REAR_ROW", HVAC_REAR_ROW},
         {"WINDOW_1_LEFT", WINDOW_1_LEFT},
         {"WINDOW_1_RIGHT", WINDOW_1_RIGHT},
         {"WINDOW_2_LEFT", WINDOW_2_LEFT},
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 0a859af..2d1e9ab 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -2033,19 +2033,10 @@
             },
             "areas": [
                 {
-                    "areaId": "Constants::SEAT_1_LEFT"
+                    "areaId": "Constants::HVAC_FRONT_ROW"
                 },
                 {
-                    "areaId": "Constants::SEAT_1_RIGHT"
-                },
-                {
-                    "areaId": "Constants::SEAT_2_LEFT"
-                },
-                {
-                    "areaId": "Constants::SEAT_2_RIGHT"
-                },
-                {
-                    "areaId": "Constants::SEAT_2_CENTER"
+                    "areaId": "Constants::HVAC_REAR_ROW"
                 }
             ]
         },
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
index 78b61f7..f2327e1 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
@@ -97,6 +97,8 @@
 constexpr int HVAC_LEFT = SEAT_1_LEFT | SEAT_2_LEFT | SEAT_2_CENTER;
 constexpr int HVAC_RIGHT = SEAT_1_RIGHT | SEAT_2_RIGHT;
 constexpr int HVAC_ALL = HVAC_LEFT | HVAC_RIGHT;
+constexpr int HVAC_FRONT_ROW = SEAT_1_LEFT | SEAT_1_RIGHT;
+constexpr int HVAC_REAR_ROW = SEAT_2_LEFT | SEAT_2_CENTER | SEAT_2_RIGHT;
 
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 6a2a695..97efdf6 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -153,10 +153,9 @@
                 propValue->status = oldStatus;
             }
 
+            // areaId and propId must be the same between valueToUpdate and propValue.
             valueUpdated = (valueToUpdate->value != propValue->value ||
-                            valueToUpdate->status != propValue->status ||
-                            valueToUpdate->prop != propValue->prop ||
-                            valueToUpdate->areaId != propValue->areaId);
+                            valueToUpdate->status != propValue->status);
         } else if (!updateStatus) {
             propValue->status = VehiclePropertyStatus::AVAILABLE;
         }
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 6f5c0c1..9081fdc 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -87,6 +87,11 @@
     /**
      * Fuel capacity of the vehicle in milliliters
      *
+     * This property must communicate the maximum amount of the fuel that can be stored in the
+     * vehicle in milliliters. This property does not apply to electric vehicles. That is, if
+     * INFO_FUEL_TYPE only contains FuelType::FUEL_TYPE_ELECTRIC, this property must not be
+     * implemented. For EVs, implement INFO_EV_BATTERY_CAPACITY.
+     *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit.MILLILITER
@@ -102,7 +107,7 @@
      *   An FHEV (Fully Hybrid Electric Vehicle) must not include FuelType::FUEL_TYPE_ELECTRIC in
      *   INFO_FUEL_TYPE's INT32_VEC value. So INFO_FUEL_TYPE can be populated as such:
      *     int32Values = { FuelType::FUEL_TYPE_UNLEADED }
-     *   On the other hand, a PHEV (Partially Hybrid Electric Vehicle) is plug in rechargeable, and
+     *   On the other hand, a PHEV (Plug-in Hybrid Electric Vehicle) is plug in rechargeable, and
      *   hence should include FuelType::FUEL_TYPE_ELECTRIC in INFO_FUEL_TYPE's INT32_VEC value. So
      *   INFO_FUEL_TYPE can be populated as such:
      *     int32Values = { FuelType::FUEL_TYPE_UNLEADED, FuelType::FUEL_TYPE_ELECTRIC }
@@ -115,12 +120,13 @@
     INFO_FUEL_TYPE = 0x0105 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
     /**
-     * Nominal battery capacity for EV or hybrid vehicle
+     * Nominal usable battery capacity for EV or hybrid vehicle
      *
-     * Returns the nominal battery capacity, if EV or hybrid. This is the battery capacity when the
-     * vehicle is new. This value might be different from EV_CURRENT_BATTERY_CAPACITY because
-     * EV_CURRENT_BATTERY_CAPACITY returns the real-time battery capacity taking into account
-     * factors such as battery aging and temperature dependency.
+     * Returns the nominal battery capacity, if EV or hybrid. This is the total usable battery
+     * capacity when the vehicle is new. This value might be different from
+     * EV_CURRENT_BATTERY_CAPACITY because EV_CURRENT_BATTERY_CAPACITY returns the real-time usable
+     * battery capacity taking into account factors such as battery aging and temperature
+     * dependency.
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
@@ -142,6 +148,11 @@
     /**
      * Fuel door location
      *
+     * This property must communicate the location of the fuel door on the vehicle. This property
+     * does not apply to electric vehicles. That is, if INFO_FUEL_TYPE only contains
+     * FuelType::FUEL_TYPE_ELECTRIC, this property must not be implemented. For EVs, implement
+     * INFO_EV_PORT_LOCATION or INFO_MULTI_EV_PORT_LOCATIONS.
+     *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @data_enum PortLocationType
      * @access VehiclePropertyAccess.READ
@@ -350,9 +361,14 @@
     WHEEL_TICK = 0x0306 + 0x10000000 + 0x01000000
             + 0x00510000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT64_VEC
     /**
-     * Fuel remaining in the vehicle, in milliliters
+     * Fuel level in milliliters
      *
-     * Value may not exceed INFO_FUEL_CAPACITY
+     * This property must communicate the current amount of fuel remaining in the vehicle in
+     * milliliters. This property does not apply to electric vehicles. That is, if INFO_FUEL_TYPE
+     * only contains FuelType::FUEL_TYPE_ELECTRIC, this property must not be implemented. For EVs,
+     * implement EV_BATTERY_LEVEL.
+     *
+     * Value may not exceed INFO_FUEL_CAPACITY.
      *
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
@@ -364,6 +380,11 @@
     /**
      * Fuel door open
      *
+     * This property must communicate whether the fuel door on the vehicle is open or not. This
+     * property does not apply to electric vehicles. That is, if INFO_FUEL_TYPE only contains
+     * FuelType::FUEL_TYPE_ELECTRIC, this property must not be implemented. For EVs, implement
+     * EV_CHARGE_PORT_OPEN.
+     *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
      * implement it as VehiclePropertyAccess.READ only.
      *
@@ -389,12 +410,13 @@
     EV_BATTERY_LEVEL = 0x0309 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
     /**
-     * Current battery capacity for EV or hybrid vehicle
+     * Current usable battery capacity for EV or hybrid vehicle
      *
      * Returns the actual value of battery capacity, if EV or hybrid. This property captures the
-     * real-time battery capacity taking into account factors such as battery aging and temperature
-     * dependency. Therefore, this value might be different from INFO_EV_BATTERY_CAPACITY because
-     * INFO_EV_BATTERY_CAPACITY returns the nominal battery capacity from when the vehicle was new.
+     * real-time usable battery capacity taking into account factors such as battery aging and
+     * temperature dependency. Therefore, this value might be different from
+     * INFO_EV_BATTERY_CAPACITY because INFO_EV_BATTERY_CAPACITY returns the nominal battery
+     * capacity from when the vehicle was new.
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
@@ -772,7 +794,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum ElectronicStabilityControlState
      * @data_enum ErrorState
-     * @version 2
+     * @version 3
      */
     ELECTRONIC_STABILITY_CONTROL_STATE =
             0x040F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -868,10 +890,18 @@
     HVAC_TEMPERATURE_CURRENT = 0x0502 + 0x10000000 + 0x05000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:FLOAT
     /**
-     * HVAC, target temperature set.
+     * HVAC target temperature set in Celsius.
      *
-     * The configArray is used to indicate the valid values for HVAC in Fahrenheit and Celsius.
-     * Android might use it in the HVAC app UI.
+     * The minFloatValue and maxFloatValue in VehicleAreaConfig must be defined.
+     *
+     * The minFloatValue indicates the minimum temperature setting in Celsius.
+     * The maxFloatValue indicates the maximum temperature setting in Celsius.
+     *
+     * If all the values between minFloatValue and maxFloatValue are not supported, the configArray
+     * can be used to list the valid temperature values that can be set. It also describes a lookup
+     * table to convert the temperature from Celsius to Fahrenheit and vice versa for this vehicle.
+     * The configArray must be defined if standard unit conversion is not supported on this vehicle.
+     *
      * The configArray is set as follows:
      *      configArray[0] = [the lower bound of the supported temperature in Celsius] * 10.
      *      configArray[1] = [the upper bound of the supported temperature in Celsius] * 10.
@@ -879,14 +909,35 @@
      *      configArray[3] = [the lower bound of the supported temperature in Fahrenheit] * 10.
      *      configArray[4] = [the upper bound of the supported temperature in Fahrenheit] * 10.
      *      configArray[5] = [the increment in Fahrenheit] * 10.
+     *
+     * The minFloatValue and maxFloatValue in VehicleAreaConfig must be equal to configArray[0] and
+     * configArray[1] respectively.
+     *
      * For example, if the vehicle supports temperature values as:
      *      [16.0, 16.5, 17.0 ,..., 28.0] in Celsius
-     *      [60.5, 61.5, 62.5 ,..., 85.5] in Fahrenheit.
-     * The configArray should be configArray = {160, 280, 5, 605, 825, 10}.
+     *      [60.5, 61.5, 62.5 ,..., 84.5] in Fahrenheit
+     * The configArray should be configArray = {160, 280, 5, 605, 845, 10}.
      *
-     * If the vehicle supports HVAC_TEMPERATURE_VALUE_SUGGESTION, the application can use
-     * that property to get the suggested value before setting HVAC_TEMPERATURE_SET. Otherwise,
-     * the application may choose the value in HVAC_TEMPERATURE_SET configArray by itself.
+     * Ideally, the ratio of the Celsius increment to the Fahrenheit increment should be as close to
+     * the actual ratio of 1 degree Celsius to 1.8 degrees Fahrenheit.
+     *
+     * There must be a one to one mapping of all Celsius values to Fahrenheit values defined by the
+     * configArray. The configArray will be used by clients to convert this property's temperature
+     * from Celsius to Fahrenheit. Also, it will let clients know what Celsius value to set the
+     * property to achieve their desired Fahreneheit value for the system. If the ECU does not have
+     * a one to one mapping of all Celsius values to Fahrenheit values, then the config array should
+     * only define the list of Celsius and Fahrenheit values that do have a one to one mapping.
+     *
+     * For example, if the ECU supports Celsius values from 16 to 28 and Fahrenheit values from 60
+     * to 85 both with an increment of 1, then one possible configArray would be {160, 280, 10, 600,
+     * 840, 20}. In this case, 85 would not be a supported temperature.
+     *
+     * Any value set in between a valid value should be rounded to the closest valid value.
+     *
+     * It is highly recommended that the OEM also implement the HVAC_TEMPERATURE_VALUE_SUGGESTION
+     * vehicle property because it provides applications a simple method for determining temperature
+     * values that can be set for this vehicle and for converting values between Celsius and
+     * Fahrenheit.
      *
      * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
      * implement it as VehiclePropertyAccess.READ only.
@@ -1295,7 +1346,22 @@
      *
      * An application calls set(VehiclePropValue propValue) with the requested value and unit for
      * the value. OEMs need to return the suggested values in floatValues[2] and floatValues[3] by
-     * onPropertyEvent() callbacks.
+     * onPropertyEvent() callbacks. The suggested values must conform to the values that can be
+     * derived from the HVAC_TEMPERATURE_SET configArray. In other words, the suggested values and
+     * the table of values from the configArray should be the same. It is recommended for the OEM to
+     * add custom logic in their VHAL implementation in order to avoid making requests to the HVAC
+     * ECU.
+     *
+     * The logic can be as follows:
+     * For converting the temperature from celsius to fahrenheit use the following:
+     * // Given tempC and the configArray
+     * float minTempC = configArray[0] / 10.0;
+     * float temperatureIncrementCelsius = configArray[2] / 10.0;
+     * float minTempF = configArray[3] / 10.0;
+     * float temperatureIncrementFahrenheit = configArray[5] / 10.0;
+     * // Round to the closest increment
+     * int numIncrements = round((tempC - minTempC) / temperatureIncrementCelsius);
+     * tempF = temperatureIncrementFahrenheit * numIncrements + minTempF;
      *
      * For example, when a user uses the voice assistant to set HVAC temperature to 66.2 in
      * Fahrenheit.
@@ -1557,6 +1623,11 @@
     /**
      * Outside temperature
      *
+     * This property must communicate the temperature reading of the environment outside the
+     * vehicle. If there are multiple sensors for measuring the outside temperature, this property
+     * should be populated with the mean or a meaningful weighted average of the readings that will
+     * best represent the temperature of the outside environment.
+     *
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit.CELSIUS
@@ -2909,7 +2980,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
-     * @version 3
+     * @version 2
      */
     SEAT_AIRBAG_ENABLED =
             0x0B9E + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -2932,7 +3003,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleAirbagLocation
-     * @version 2
+     * @version 3
      */
     SEAT_AIRBAGS_DEPLOYED =
             0x0BA5 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -5868,7 +5939,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
      * @access VehiclePropertyAccess.READ
-     * @version 2
+     * @version 3
      */
     DRIVER_DISTRACTION_WARNING_ENABLED =
             0x101F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
diff --git a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
index 24eb4d0..395e4cc 100644
--- a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
+++ b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
@@ -75,7 +75,7 @@
 static constexpr size_t kNumHciCommandsBandwidth = 100;
 static constexpr size_t kNumScoPacketsBandwidth = 100;
 static constexpr size_t kNumAclPacketsBandwidth = 100;
-static constexpr std::chrono::milliseconds kWaitForInitTimeout(2000);
+static constexpr std::chrono::milliseconds kWaitForInitTimeout(1000);
 static constexpr std::chrono::milliseconds kWaitForHciEventTimeout(2000);
 static constexpr std::chrono::milliseconds kWaitForScoDataTimeout(1000);
 static constexpr std::chrono::milliseconds kWaitForAclDataTimeout(1000);
@@ -150,6 +150,9 @@
 
 // The main test class for Bluetooth HAL.
 class BluetoothAidlTest : public ::testing::TestWithParam<std::string> {
+  std::chrono::time_point<std::chrono::system_clock>
+      time_after_initialize_complete;
+
  public:
   void SetUp() override {
     // currently test passthrough mode only
@@ -180,12 +183,16 @@
     event_cb_count = 0;
     acl_cb_count = 0;
     sco_cb_count = 0;
+    std::chrono::time_point<std::chrono::system_clock>
+        timeout_after_initialize =
+            std::chrono::system_clock::now() + kWaitForInitTimeout;
 
     ASSERT_TRUE(hci->initialize(hci_cb).isOk());
     auto future = initialized_promise.get_future();
     auto timeout_status = future.wait_for(kWaitForInitTimeout);
     ASSERT_EQ(timeout_status, std::future_status::ready);
     ASSERT_TRUE(future.get());
+    ASSERT_GE(timeout_after_initialize, time_after_initialize_complete);
   }
 
   void TearDown() override {
@@ -237,6 +244,10 @@
     ~BluetoothHciCallbacks() override = default;
 
     ndk::ScopedAStatus initializationComplete(Status status) override {
+      if (status == Status::SUCCESS) {
+        parent_.time_after_initialize_complete =
+            std::chrono::system_clock::now();
+      }
       parent_.initialized_promise.set_value(status == Status::SUCCESS);
       ALOGV("%s (status = %d)", __func__, static_cast<int>(status));
       return ScopedAStatus::ok();
diff --git a/bluetooth/audio/aidl/default/Android.bp b/bluetooth/audio/aidl/default/Android.bp
index 69db1b3..af6bf86 100644
--- a/bluetooth/audio/aidl/default/Android.bp
+++ b/bluetooth/audio/aidl/default/Android.bp
@@ -40,3 +40,10 @@
         "libbluetooth_audio_session_aidl",
     ],
 }
+
+prebuilt_etc {
+    name: "android.hardware.bluetooth.audio.xml",
+    src: "bluetooth_audio.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
index 584640b..dc36ac0 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
@@ -39,6 +39,9 @@
 static const std::string kLeAudioOffloadProviderName =
     "LE_AUDIO_OFFLOAD_HARDWARE_OFFLOAD_PROVIDER";
 
+static const std::string kHfpOffloadProviderName =
+    "HFP_OFFLOAD_HARDWARE_OFFLOAD_PROVIDER";
+
 BluetoothAudioProviderFactory::BluetoothAudioProviderFactory() {}
 
 ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider(
@@ -170,6 +173,7 @@
     provider_info.name = a2dp_offload_codec_factory_.name;
     for (auto codec : a2dp_offload_codec_factory_.codecs)
       provider_info.codecInfos.push_back(codec->info);
+    return ndk::ScopedAStatus::ok();
   }
 
   if (session_type ==
@@ -184,12 +188,23 @@
       auto& provider_info = _aidl_return->emplace();
       provider_info.name = kLeAudioOffloadProviderName;
       provider_info.codecInfos = db_codec_info;
-      *_aidl_return = provider_info;
       return ndk::ScopedAStatus::ok();
     }
   }
 
-  return ndk::ScopedAStatus::ok();
+  if (session_type == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH) {
+    std::vector<CodecInfo> db_codec_info =
+        BluetoothAudioCodecs::GetHfpOffloadCodecInfo();
+    if (!db_codec_info.empty()) {
+      auto& provider_info = _aidl_return->emplace();
+      provider_info.name = kHfpOffloadProviderName;
+      provider_info.codecInfos = db_codec_info;
+      return ndk::ScopedAStatus::ok();
+    }
+  }
+
+  // Unsupported for other sessions
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
 }  // namespace audio
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index 789e8a1..c313fb7 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -1944,6 +1944,7 @@
         BluetoothAudioHalVersion::VERSION_AIDL_V4) {
       GTEST_SKIP();
     }
+    GetProviderInfoHelper(SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH);
     OpenProviderHelper(SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH);
     // Can open or empty capability
     ASSERT_TRUE(temp_provider_capabilities_.empty() ||
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index c0817f5..cecf8f0 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -42,6 +42,7 @@
         "aidl_session/BluetoothAudioSession.cpp",
         "aidl_session/HidlToAidlMiddleware.cpp",
         "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
+        "aidl_session/BluetoothHfpCodecsProvider.cpp",
         "aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp",
     ],
     export_include_dirs: ["aidl_session/"],
@@ -68,9 +69,13 @@
     static_libs: [
         "btaudiohal_flags_c_lib",
     ],
-    generated_sources: ["le_audio_codec_capabilities"],
+    generated_sources: [
+        "le_audio_codec_capabilities",
+        "hfp_codec_capabilities",
+    ],
     generated_headers: [
         "le_audio_codec_capabilities",
+        "hfp_codec_capabilities",
         "AIDLLeAudioSetConfigSchemas_h",
     ],
     required: [
@@ -78,6 +83,7 @@
         "aidl_audio_set_configurations_json",
         "aidl_audio_set_scenarios_bfbs",
         "aidl_audio_set_scenarios_json",
+        "hfp_codec_capabilities_xml",
     ],
 }
 
@@ -106,6 +112,35 @@
     generated_headers: ["le_audio_codec_capabilities"],
 }
 
+cc_test {
+    name: "BluetoothHfpCodecsProviderTest",
+    defaults: [
+        "latest_android_hardware_audio_common_ndk_static",
+        "latest_android_hardware_bluetooth_audio_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
+    ],
+    srcs: [
+        "aidl_session/BluetoothHfpCodecsProvider.cpp",
+        "aidl_session/BluetoothHfpCodecsProviderTest.cpp",
+    ],
+    header_libs: [
+        "libxsdc-utils",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libxml2",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+    test_options: {
+        unit_test: false,
+    },
+    generated_sources: ["hfp_codec_capabilities"],
+    generated_headers: ["hfp_codec_capabilities"],
+}
+
 xsd_config {
     name: "le_audio_codec_capabilities",
     srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"],
@@ -114,6 +149,14 @@
     root_elements: ["leAudioOffloadSetting"],
 }
 
+xsd_config {
+    name: "hfp_codec_capabilities",
+    srcs: ["hfp_codec_capabilities/hfp_codec_capabilities.xsd"],
+    package_name: "aidl.android.hardware.bluetooth.audio.hfp.setting",
+    api_dir: "hfp_codec_capabilities/schema",
+    root_elements: ["hfpOffloadSetting"],
+}
+
 genrule {
     name: "AIDLLeAudioSetConfigSchemas_h",
     tools: [
@@ -177,6 +220,14 @@
 }
 
 prebuilt_etc {
+    name: "hfp_codec_capabilities_xml",
+    src: "hfp_codec_capabilities/hfp_codec_capabilities.xml",
+    filename: "hfp_codec_capabilities.xml",
+    sub_dir: "aidl/hfp",
+    vendor: true,
+}
+
+prebuilt_etc {
     name: "aidl_audio_set_configurations_bfbs",
     src: ":AIDLLeAudioSetConfigsSchema_bfbs",
     filename: "aidl_audio_set_configurations.bfbs",
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index d37825a..c25b102 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -32,6 +32,7 @@
 #include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
 #include <android-base/logging.h>
 
+#include "BluetoothHfpCodecsProvider.h"
 #include "BluetoothLeAudioAseConfigurationSettingProvider.h"
 #include "BluetoothLeAudioCodecsProvider.h"
 
@@ -100,6 +101,7 @@
 std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
 std::unordered_map<SessionType, std::vector<CodecInfo>>
     kDefaultOffloadLeAudioCodecInfoMap;
+std::vector<CodecInfo> kDefaultOffloadHfpCodecInfo;
 
 template <class T>
 bool BluetoothAudioCodecs::ContainedInVector(
@@ -439,6 +441,17 @@
   return codec_info_map_iter->second;
 }
 
+std::vector<CodecInfo> BluetoothAudioCodecs::GetHfpOffloadCodecInfo() {
+  if (kDefaultOffloadHfpCodecInfo.empty()) {
+    auto hfp_offload_setting =
+        BluetoothHfpCodecsProvider::ParseFromHfpOffloadSettingFile();
+    // Load file into list
+    kDefaultOffloadHfpCodecInfo =
+        BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo(hfp_offload_setting);
+  }
+  return kDefaultOffloadHfpCodecInfo;
+}
+
 std::vector<LeAudioAseConfigurationSetting>
 BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings() {
   return AudioSetConfigurationProviderJson::
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
index 057b9a7..0a1f708 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
@@ -57,6 +57,8 @@
   static std::vector<LeAudioAseConfigurationSetting>
   GetLeAudioAseConfigurationSettings();
 
+  static std::vector<CodecInfo> GetHfpOffloadCodecInfo();
+
  private:
   template <typename T>
   struct identity {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.cpp
new file mode 100644
index 0000000..d61ec5a
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2024 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 "BluetoothHfpCodecsProvider.h"
+
+#include <unordered_map>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using hfp::setting::CodecType;
+using hfp::setting::PathConfiguration;
+
+static const char* kHfpCodecCapabilitiesFile =
+    "/vendor/etc/aidl/hfp/hfp_codec_capabilities.xml";
+
+std::optional<HfpOffloadSetting>
+BluetoothHfpCodecsProvider::ParseFromHfpOffloadSettingFile() {
+  auto hfp_offload_setting =
+      hfp::setting::readHfpOffloadSetting(kHfpCodecCapabilitiesFile);
+  if (!hfp_offload_setting.has_value()) {
+    LOG(ERROR) << __func__ << ": Failed to read " << kHfpCodecCapabilitiesFile;
+  }
+  return hfp_offload_setting;
+}
+
+std::vector<CodecInfo> BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo(
+    const std::optional<HfpOffloadSetting>& hfp_offload_setting) {
+  std::vector<CodecInfo> result;
+  if (!hfp_offload_setting.has_value()) return result;
+
+  // Convert path configuration into map
+  // Currently transport configuration is unused
+  if (!hfp_offload_setting.value().hasPathConfiguration() ||
+      hfp_offload_setting.value().getPathConfiguration().empty()) {
+    LOG(WARNING) << __func__ << ": path configurations is empty";
+    return result;
+  }
+  auto path_configurations = hfp_offload_setting.value().getPathConfiguration();
+  std::unordered_map<std::string, PathConfiguration> path_config_map;
+  for (const auto& path_cfg : path_configurations)
+    if (path_cfg.hasName() && path_cfg.hasDataPath())
+      path_config_map.insert(make_pair(path_cfg.getName(), path_cfg));
+
+  for (const auto& cfg : hfp_offload_setting.value().getConfiguration()) {
+    auto input_path_cfg = path_config_map.find(cfg.getInputPathConfiguration());
+    auto output_path_cfg =
+        path_config_map.find(cfg.getOutputPathConfiguration());
+    if (input_path_cfg == path_config_map.end()) {
+      LOG(WARNING) << __func__ << ": Input path configuration not found: "
+                   << cfg.getInputPathConfiguration();
+      continue;
+    }
+
+    if (output_path_cfg == path_config_map.end()) {
+      LOG(WARNING) << __func__ << ": Output path configuration not found: "
+                   << cfg.getOutputPathConfiguration();
+      continue;
+    }
+
+    CodecInfo codec_info;
+
+    switch (cfg.getCodec()) {
+      case CodecType::LC3:
+        codec_info.id = CodecId::Core::LC3;
+        break;
+      case CodecType::MSBC:
+        codec_info.id = CodecId::Core::MSBC;
+        break;
+      case CodecType::CVSD:
+        codec_info.id = CodecId::Core::CVSD;
+        break;
+      default:
+        LOG(WARNING) << __func__ << ": Unknown codec from " << cfg.getName();
+        codec_info.id = CodecId::Vendor();
+        break;
+    }
+    codec_info.name = cfg.getName();
+
+    codec_info.transport =
+        CodecInfo::Transport::make<CodecInfo::Transport::Tag::hfp>();
+
+    auto& transport =
+        codec_info.transport.get<CodecInfo::Transport::Tag::hfp>();
+    transport.useControllerCodec = cfg.getUseControllerCodec();
+    transport.inputDataPath = input_path_cfg->second.getDataPath();
+    transport.outputDataPath = output_path_cfg->second.getDataPath();
+
+    result.push_back(codec_info);
+  }
+  LOG(INFO) << __func__ << ": Has " << result.size() << " codec info";
+  return result;
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.h
new file mode 100644
index 0000000..642ee02
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+
+#include <vector>
+
+#include "aidl/android/hardware/bluetooth/audio/CodecInfo.h"
+#include "aidl_android_hardware_bluetooth_audio_hfp_setting.h"
+#include "aidl_android_hardware_bluetooth_audio_hfp_setting_enums.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using hfp::setting::HfpOffloadSetting;
+
+class BluetoothHfpCodecsProvider {
+ public:
+  static std::optional<HfpOffloadSetting> ParseFromHfpOffloadSettingFile();
+
+  static std::vector<CodecInfo> GetHfpAudioCodecInfo(
+      const std::optional<HfpOffloadSetting>& hfp_offload_setting);
+};
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProviderTest.cpp
new file mode 100644
index 0000000..b08c3eb
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProviderTest.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2024 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 <gtest/gtest.h>
+
+#include <optional>
+#include <tuple>
+
+#include "BluetoothHfpCodecsProvider.h"
+#include "gtest/gtest.h"
+
+using aidl::android::hardware::bluetooth::audio::BluetoothHfpCodecsProvider;
+using aidl::android::hardware::bluetooth::audio::CodecInfo;
+using aidl::android::hardware::bluetooth::audio::hfp::setting::CodecType;
+using aidl::android::hardware::bluetooth::audio::hfp::setting::Configuration;
+using aidl::android::hardware::bluetooth::audio::hfp::setting::
+    HfpOffloadSetting;
+using aidl::android::hardware::bluetooth::audio::hfp::setting::
+    PathConfiguration;
+using aidl::android::hardware::bluetooth::audio::hfp::setting::
+    TransportConfiguration;
+
+typedef std::tuple<std::vector<PathConfiguration>,
+                   std::vector<TransportConfiguration>,
+                   std::vector<Configuration>>
+    HfpOffloadSettingTuple;
+
+// Define valid components for each list
+// PathConfiguration
+static const PathConfiguration kValidPathConfigurationCVSD("CVSD_IO", 16000,
+                                                           CodecType::CVSD, 16,
+                                                           2, 0, 1, 0);
+static const PathConfiguration kInvalidPathConfigurationNULL(std::nullopt,
+                                                             16000,
+                                                             CodecType::CVSD,
+                                                             16, 2, 0, 1, 0);
+static const PathConfiguration kInvalidPathConfigurationNoPath(
+    "CVSD_NULL", 16000, CodecType::CVSD, 16, 2, 0, std::nullopt, 0);
+
+// Configuration
+static const Configuration kValidConfigurationCVSD("CVSD", CodecType::CVSD,
+                                                   65535, 7, 0, true, "CVSD_IO",
+                                                   "CVSD_IO", std::nullopt,
+                                                   std::nullopt);
+static const Configuration kInvalidConfigurationCVSDNoPath(
+    "CVSD", CodecType::CVSD, 65535, 7, 0, true, "CVSD_NULL", "CVSD_NULL",
+    std::nullopt, std::nullopt);
+static const Configuration kInvalidConfigurationCVSDNotFound(
+    "CVSD", CodecType::CVSD, 65535, 7, 0, true, "CVSD_N", "CVSD_N",
+    std::nullopt, std::nullopt);
+
+class BluetoothHfpCodecsProviderTest : public ::testing::Test {
+ public:
+  static std::vector<HfpOffloadSettingTuple> CreateTestCases(
+      const std::vector<std::vector<PathConfiguration>> path_configs_list,
+      const std::vector<std::vector<TransportConfiguration>>
+          transport_configs_list,
+      const std::vector<std::vector<Configuration>> configs_list) {
+    std::vector<HfpOffloadSettingTuple> test_cases;
+    for (const auto& path_configs : path_configs_list) {
+      for (const auto& transport_configs : transport_configs_list) {
+        for (const auto& configs : configs_list)
+          test_cases.push_back(
+              CreateTestCase(path_configs, transport_configs, configs));
+      }
+    }
+    return test_cases;
+  }
+
+ protected:
+  std::vector<CodecInfo> RunTestCase(HfpOffloadSettingTuple test_case) {
+    auto& [path_configuration_list, transport_configuration_list,
+           configuration_list] = test_case;
+    HfpOffloadSetting hfp_offload_setting(path_configuration_list,
+                                          transport_configuration_list,
+                                          configuration_list);
+    auto capabilities =
+        BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo(hfp_offload_setting);
+    return capabilities;
+  }
+
+ private:
+  static inline HfpOffloadSettingTuple CreateTestCase(
+      const std::vector<PathConfiguration> path_config_list,
+      const std::vector<TransportConfiguration> transport_config_list,
+      const std::vector<Configuration> config_list) {
+    return std::make_tuple(path_config_list, transport_config_list,
+                           config_list);
+  }
+};
+
+class GetHfpCodecInfoTest : public BluetoothHfpCodecsProviderTest {
+ public:
+  static std::vector<std::vector<PathConfiguration>>
+  GetInvalidPathConfigurationLists() {
+    std::vector<std::vector<PathConfiguration>> result;
+    result.push_back({kInvalidPathConfigurationNULL});
+    result.push_back({kInvalidPathConfigurationNoPath});
+    result.push_back({});
+    return result;
+  }
+
+  static std::vector<std::vector<Configuration>>
+  GetInvalidConfigurationLists() {
+    std::vector<std::vector<Configuration>> result;
+    result.push_back({kInvalidConfigurationCVSDNotFound});
+    result.push_back({kInvalidConfigurationCVSDNoPath});
+    result.push_back({});
+    return result;
+  }
+};
+
+TEST_F(GetHfpCodecInfoTest, InvalidPathConfiguration) {
+  auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases(
+      GetHfpCodecInfoTest::GetInvalidPathConfigurationLists(), {{}},
+      {{kValidConfigurationCVSD}});
+  for (auto& test_case : test_cases) {
+    auto hfp_codec_capabilities = RunTestCase(test_case);
+    ASSERT_TRUE(hfp_codec_capabilities.empty());
+  }
+}
+
+TEST_F(GetHfpCodecInfoTest, InvalidConfigurationName) {
+  auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases(
+      GetHfpCodecInfoTest::GetInvalidPathConfigurationLists(), {{}},
+      {GetHfpCodecInfoTest::GetInvalidConfigurationLists()});
+  for (auto& test_case : test_cases) {
+    auto hfp_codec_capabilities = RunTestCase(test_case);
+    ASSERT_TRUE(hfp_codec_capabilities.empty());
+  }
+}
+
+TEST_F(GetHfpCodecInfoTest, ValidConfiguration) {
+  auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases(
+      {{kValidPathConfigurationCVSD}}, {{}}, {{kValidConfigurationCVSD}});
+  for (auto& test_case : test_cases) {
+    auto hfp_codec_capabilities = RunTestCase(test_case);
+    ASSERT_FALSE(hfp_codec_capabilities.empty());
+  }
+}
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xml b/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xml
new file mode 100644
index 0000000..c94843f
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!---
+  This is an example to configure HFP hardware offload supported capability settings
+  There are 3 list in this file. Add element into each list as needed.
+
+  pathConfiguration: input / output path configuration
+  transportConfiguration: transmit / receive configuration
+
+  configuration:
+    For each configuration, there are attributes:
+      - name
+      - codec
+      - useControllerCodec
+      - maxLatencyMs
+      - packetTypes
+      - retransmissionEffort
+      - input and output path configuration (reference by name)
+      - transmit and receive configuration (reference by name)
+-->
+<hfpOffloadSetting>
+
+  <pathConfiguration name="CVSD_IO" bandwidth="16000" codec="CVSD" codedDataSize="16" pcmDataFormat="2" pcmPayloadMsbPosition="0" dataPath="1" transportUnitSize="0" />
+  <pathConfiguration name="MSBC_IO" bandwidth="32000" codec="MSBC" codedDataSize="16" pcmDataFormat="2" pcmPayloadMsbPosition="0" dataPath="1" transportUnitSize="0" />
+  <pathConfiguration name="LC3_IO" bandwidth="64000" codec="MSBC" codedDataSize="16" pcmDataFormat="2" pcmPayloadMsbPosition="0" dataPath="1" transportUnitSize="0" />
+
+  <transportConfiguration name="CVSD_TXRX" bandwidth="8000" codec="CVSD" codedFrameSize="60" />
+  <transportConfiguration name="MSBC_TXRX" bandwidth="8000" codec="MSBC" codedFrameSize="60" />
+  <transportConfiguration name="LC3_TXRX" bandwidth="8000" codec="LC3" codedFrameSize="60" />
+
+  <configuration name="CVSD_D1_controller" codec="CVSD" maxLatencyMs="65535" packetTypes="7" retransmissionEffort="0" useControllerCodec="true" inputPathConfiguration="CVSD_IO" outputPathConfiguration="CVSD_IO" inputTransportConfiguration="CVSD_TXRX" outTransportConfiguration="CVSD_TXRX" />
+  <configuration name="CVSD_S3_controller" codec="CVSD" maxLatencyMs="10" packetTypes="959" retransmissionEffort="1" useControllerCodec="true" inputPathConfiguration="CVSD_IO" outputPathConfiguration="CVSD_IO" inputTransportConfiguration="CVSD_TXRX" outTransportConfiguration="CVSD_TXRX" />
+  <configuration name="CVSD_S4_controller" codec="CVSD" maxLatencyMs="12" packetTypes="959" retransmissionEffort="2" useControllerCodec="true" inputPathConfiguration="CVSD_IO" outputPathConfiguration="CVSD_IO" inputTransportConfiguration="CVSD_TXRX" outTransportConfiguration="CVSD_TXRX" />
+
+  <configuration name="MSBC_T1_controller" codec="MSBC" maxLatencyMs="8" packetTypes="968" retransmissionEffort="2" useControllerCodec="true" inputPathConfiguration="MSBC_IO" outputPathConfiguration="MSBC_IO" inputTransportConfiguration="MSBC_TXRX" outTransportConfiguration="MSBC_TXRX" />
+  <configuration name="MSBC_T2_controller" codec="MSBC" maxLatencyMs="13" packetTypes="904" retransmissionEffort="2" useControllerCodec="true" inputPathConfiguration="MSBC_IO" outputPathConfiguration="MSBC_IO" inputTransportConfiguration="MSBC_TXRX" outTransportConfiguration="MSBC_TXRX" />
+
+  <configuration name="LC3_T1_controller" codec="LC3" maxLatencyMs="8" packetTypes="968" retransmissionEffort="2" useControllerCodec="true" inputPathConfiguration="LC3_IO" outputPathConfiguration="LC3_IO" inputTransportConfiguration="LC3_TXRX" outTransportConfiguration="LC3_TXRX" />
+  <configuration name="LC3_T2_controller" codec="LC3" maxLatencyMs="13" packetTypes="896" retransmissionEffort="2" useControllerCodec="true" inputPathConfiguration="LC3_IO" outputPathConfiguration="LC3_IO" inputTransportConfiguration="LC3_TXRX" outTransportConfiguration="LC3_TXRX" />
+
+</hfpOffloadSetting>
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xsd b/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xsd
new file mode 100644
index 0000000..c4787b9
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xsd
@@ -0,0 +1,51 @@
+<!-- HFP Offload Codec Capability Schema -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+  <xs:element name="hfpOffloadSetting">
+    <xs:complexType>
+      <xs:element ref="pathConfiguration" minOccurs="1" maxOccurs="unbounded"/>
+      <xs:element ref="transportConfiguration" minOccurs="1" maxOccurs="unbounded"/>
+      <xs:element ref="configuration" minOccurs="1" maxOccurs="unbounded"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="pathConfiguration">
+    <xs:complexType>
+      <xs:attribute name="name" type="xs:string"/>
+      <xs:attribute name="bandwidth" type="xs:unsignedInt"/>
+      <xs:attribute name="codec" type="codecType"/>
+      <xs:attribute name="codedDataSize" type="xs:unsignedShort"/>
+      <xs:attribute name="pcmDataFormat" type="xs:unsignedByte"/>
+      <xs:attribute name="pcmPayloadMsbPosition" type="xs:unsignedByte"/>
+      <xs:attribute name="dataPath" type="xs:unsignedByte"/>
+      <xs:attribute name="transportUnitSize" type="xs:unsignedByte"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="transportConfiguration">
+    <xs:complexType>
+      <xs:attribute name="name" type="xs:string"/>
+      <xs:attribute name="bandwidth" type="xs:unsignedInt"/>
+      <xs:attribute name="codec" type="codecType"/>
+      <xs:attribute name="codedFrameSize" type="xs:unsignedShort"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="configuration">
+    <xs:complexType>
+      <xs:attribute name="name" type="xs:string"/>
+      <xs:attribute name="codec" type="codecType"/>
+      <xs:attribute name="maxLatencyMs" type="xs:unsignedShort"/>
+      <xs:attribute name="packetTypes" type="xs:unsignedShort"/>
+      <xs:attribute name="retransmissionEffort" type="xs:unsignedByte"/>
+      <xs:attribute name="useControllerCodec" type="xs:boolean"/>
+      <xs:attribute name="inputPathConfiguration" type="xs:string"/>
+      <xs:attribute name="outputPathConfiguration" type="xs:string"/>
+      <xs:attribute name="inputTransportConfiguration" type="xs:string"/>
+      <xs:attribute name="outputTransportConfiguration" type="xs:string"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:simpleType name="codecType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="LC3"/>
+      <xs:enumeration value="CVSD"/>
+      <xs:enumeration value="MSBC"/>
+    </xs:restriction>
+  </xs:simpleType>
+</xs:schema>
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/schema/current.txt b/bluetooth/audio/utils/hfp_codec_capabilities/schema/current.txt
new file mode 100644
index 0000000..4b49929
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/schema/current.txt
@@ -0,0 +1,82 @@
+// Signature format: 2.0
+package aidl.android.hardware.bluetooth.audio.hfp.setting {
+
+  public enum CodecType {
+    method public String getRawName();
+    enum_constant public static final aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType CVSD;
+    enum_constant public static final aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType LC3;
+    enum_constant public static final aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType MSBC;
+  }
+
+  public class Configuration {
+    ctor public Configuration();
+    method public aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType getCodec();
+    method public String getInputPathConfiguration();
+    method public String getInputTransportConfiguration();
+    method public int getMaxLatencyMs();
+    method public String getName();
+    method public String getOutputPathConfiguration();
+    method public String getOutputTransportConfiguration();
+    method public int getPacketTypes();
+    method public short getRetransmissionEffort();
+    method public boolean getUseControllerCodec();
+    method public void setCodec(aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType);
+    method public void setInputPathConfiguration(String);
+    method public void setInputTransportConfiguration(String);
+    method public void setMaxLatencyMs(int);
+    method public void setName(String);
+    method public void setOutputPathConfiguration(String);
+    method public void setOutputTransportConfiguration(String);
+    method public void setPacketTypes(int);
+    method public void setRetransmissionEffort(short);
+    method public void setUseControllerCodec(boolean);
+  }
+
+  public class HfpOffloadSetting {
+    ctor public HfpOffloadSetting();
+    method public java.util.List<aidl.android.hardware.bluetooth.audio.hfp.setting.Configuration> getConfiguration();
+    method public java.util.List<aidl.android.hardware.bluetooth.audio.hfp.setting.PathConfiguration> getPathConfiguration();
+    method public java.util.List<aidl.android.hardware.bluetooth.audio.hfp.setting.TransportConfiguration> getTransportConfiguration();
+  }
+
+  public class PathConfiguration {
+    ctor public PathConfiguration();
+    method public long getBandwidth();
+    method public aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType getCodec();
+    method public int getCodedDataSize();
+    method public short getDataPath();
+    method public String getName();
+    method public short getPcmDataFormat();
+    method public short getPcmPayloadMsbPosition();
+    method public short getTransportUnitSize();
+    method public void setBandwidth(long);
+    method public void setCodec(aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType);
+    method public void setCodedDataSize(int);
+    method public void setDataPath(short);
+    method public void setName(String);
+    method public void setPcmDataFormat(short);
+    method public void setPcmPayloadMsbPosition(short);
+    method public void setTransportUnitSize(short);
+  }
+
+  public class TransportConfiguration {
+    ctor public TransportConfiguration();
+    method public long getBandwidth();
+    method public aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType getCodec();
+    method public int getCodedFrameSize();
+    method public String getName();
+    method public void setBandwidth(long);
+    method public void setCodec(aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType);
+    method public void setCodedFrameSize(int);
+    method public void setName(String);
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static aidl.android.hardware.bluetooth.audio.hfp.setting.HfpOffloadSetting readHfpOffloadSetting(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_current.txt b/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_current.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_current.txt
@@ -0,0 +1 @@
+
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_removed.txt b/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_removed.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_removed.txt
@@ -0,0 +1 @@
+
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/schema/removed.txt b/bluetooth/audio/utils/hfp_codec_capabilities/schema/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/schema/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
index 4a95a41..4d29743 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
@@ -174,7 +174,7 @@
      * - 13 bit: Fractional bits of longitude
      * - 8 bit: Integer bits of longitude
      * - 1 bit: 0 for east and 1 for west for longitude
-     * - 1 bit: 0, representing latitude
+     * - 1 bit: 0, representing longitude
      * - 5 bit: pad of zeros separating longitude and latitude
      * - 4 bit: Bits 4:7 of altitude
      * - 13 bit: Fractional bits of latitude
diff --git a/broadcastradio/common/utilsaidl/src/Utils.cpp b/broadcastradio/common/utilsaidl/src/Utils.cpp
index ddc5b8d..4ab04d2 100644
--- a/broadcastradio/common/utilsaidl/src/Utils.cpp
+++ b/broadcastradio/common/utilsaidl/src/Utils.cpp
@@ -296,7 +296,12 @@
          sel.primaryId.type > IdentifierType::VENDOR_END)) {
         return false;
     }
-    return isValid(sel.primaryId);
+    for (auto it = begin(sel); it != end(sel); it++) {
+        if (!isValid(*it)) {
+            return false;
+        }
+    }
+    return true;
 }
 
 ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
diff --git a/broadcastradio/common/utilsaidl/src/UtilsV2.cpp b/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
index 6c75759..56365c5 100644
--- a/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
+++ b/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
@@ -102,15 +102,16 @@
             expect(val < 1000u, "SXM channel < 1000");
             break;
         case IdentifierType::HD_STATION_LOCATION: {
+            val >>= 26;
             uint64_t latitudeBit = val & 0x1;
-            expect(latitudeBit == 1u, "Latitude comes first");
-            val >>= 27;
+            expect(latitudeBit == 0u, "Longitude comes first");
+            val >>= 1;
             uint64_t latitudePad = val & 0x1Fu;
-            expect(latitudePad == 0u, "Latitude padding");
-            val >>= 5;
+            expect(latitudePad == 0u, "Longitude padding");
+            val >>= 31;
             uint64_t longitudeBit = val & 0x1;
-            expect(longitudeBit == 1u, "Longitude comes next");
-            val >>= 27;
+            expect(longitudeBit == 1u, "Latitude comes next");
+            val >>= 1;
             uint64_t longitudePad = val & 0x1Fu;
             expect(longitudePad == 0u, "Latitude padding");
             break;
@@ -135,7 +136,12 @@
          sel.primaryId.type > IdentifierType::VENDOR_END)) {
         return false;
     }
-    return isValidV2(sel.primaryId);
+    for (auto it = begin(sel); it != end(sel); it++) {
+        if (!isValidV2(*it)) {
+            return false;
+        }
+    }
+    return true;
 }
 
 bool isValidMetadataV2(const Metadata& metadata) {
diff --git a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsCommonTest.cpp b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsCommonTest.cpp
new file mode 100644
index 0000000..b71bf03
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsCommonTest.cpp
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2024 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 <broadcastradio-utils-aidl/Utils.h>
+#include <broadcastradio-utils-aidl/UtilsV2.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace {
+constexpr int64_t kFmFrequencyKHz = 97900;
+constexpr uint32_t kDabSid = 0x0000C221u;
+constexpr int kDabEccCode = 0xE1u;
+constexpr int kDabSCIdS = 0x1u;
+constexpr uint64_t kDabSidExt = static_cast<uint64_t>(kDabSid) |
+                                (static_cast<uint64_t>(kDabEccCode) << 32) |
+                                (static_cast<uint64_t>(kDabSCIdS) << 40);
+constexpr uint32_t kDabEnsemble = 0xCE15u;
+constexpr uint64_t kDabFrequencyKhz = 225648u;
+constexpr uint64_t kHdStationId = 0xA0000001u;
+constexpr uint64_t kHdSubChannel = 1u;
+constexpr uint64_t kHdStationLocation = 0x44E647003665CF6u;
+constexpr uint64_t kHdStationLocationInvalid = 0x4E647007665CF6u;
+constexpr uint64_t kHdFrequency = 97700u;
+constexpr int64_t kRdsValue = 0xBEEF;
+
+struct IsValidIdentifierTestCase {
+    std::string name;
+    ProgramIdentifier id;
+    bool valid;
+};
+
+std::vector<IsValidIdentifierTestCase> getIsValidIdentifierTestCases() {
+    return std::vector<IsValidIdentifierTestCase>({
+            IsValidIdentifierTestCase{.name = "invalid_id_type",
+                                      .id = utils::makeIdentifier(IdentifierType::INVALID, 0),
+                                      .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_dab_frequency_high",
+                    .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 10000000u),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_dab_frequency_low",
+                    .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 100000u),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "valid_dab_frequency",
+                    .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 1000000u),
+                    .valid = true},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_am_fm_frequency_high",
+                    .id = utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 10000000u),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_am_fm_frequency_low",
+                    .id = utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 100u),
+                    .valid = false},
+            IsValidIdentifierTestCase{.name = "valid_am_fm_frequency",
+                                      .id = utils::makeIdentifier(
+                                              IdentifierType::AMFM_FREQUENCY_KHZ, kFmFrequencyKHz),
+                                      .valid = true},
+            IsValidIdentifierTestCase{
+                    .name = "drmo_frequency_high",
+                    .id = utils::makeIdentifier(IdentifierType::DRMO_FREQUENCY_KHZ, 10000000u),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "drmo_frequency_low",
+                    .id = utils::makeIdentifier(IdentifierType::DRMO_FREQUENCY_KHZ, 100u),
+                    .valid = false},
+            IsValidIdentifierTestCase{.name = "valid_drmo_frequency",
+                                      .id = utils::makeIdentifier(
+                                              IdentifierType::DRMO_FREQUENCY_KHZ, kFmFrequencyKHz),
+                                      .valid = true},
+            IsValidIdentifierTestCase{.name = "invalid_rds_low",
+                                      .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x0),
+                                      .valid = false},
+            IsValidIdentifierTestCase{.name = "invalid_rds_high",
+                                      .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x10000),
+                                      .valid = false},
+            IsValidIdentifierTestCase{.name = "valid_rds",
+                                      .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x1000),
+                                      .valid = true},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_hd_id_zero",
+                    .id = utils::makeSelectorHd(/* stationId= */ 0u, kHdSubChannel, kHdFrequency)
+                                  .primaryId,
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_hd_suchannel",
+                    .id = utils::makeSelectorHd(kHdStationId, /* subChannel= */ 8u, kHdFrequency)
+                                  .primaryId,
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_hd_frequency_low",
+                    .id = utils::makeSelectorHd(kHdStationId, kHdSubChannel, /* frequency= */ 100u)
+                                  .primaryId,
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "valid_hd_id",
+                    .id = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency)
+                                  .primaryId,
+                    .valid = true},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_hd_station_name",
+                    .id = utils::makeIdentifier(IdentifierType::HD_STATION_NAME, 0x41422D464D),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "valid_hd_station_name",
+                    .id = utils::makeIdentifier(IdentifierType::HD_STATION_NAME, 0x414231464D),
+                    .valid = true},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_dab_sid",
+                    .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x0E100000000u),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_dab_ecc_low",
+                    .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x0F700000221u),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_dab_ecc_high",
+                    .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x09900000221u),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "valid_dab_sid_ext",
+                    .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, kDabSidExt),
+                    .valid = true},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_dab_ensemble_zero",
+                    .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, 0x0),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_dab_ensemble_high",
+                    .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, 0x10000),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "valid_dab_ensemble",
+                    .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, kDabEnsemble),
+                    .valid = true},
+            IsValidIdentifierTestCase{.name = "invalid_dab_scid_low",
+                                      .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0xF),
+                                      .valid = false},
+            IsValidIdentifierTestCase{.name = "invalid_dab_scid_high",
+                                      .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0x1000),
+                                      .valid = false},
+            IsValidIdentifierTestCase{.name = "valid_dab_scid",
+                                      .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0x100),
+                                      .valid = true},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_drmo_id_zero",
+                    .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x0),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "invalid_drmo_id_high",
+                    .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x1000000),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "valid_drmo_id",
+                    .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000),
+                    .valid = true},
+    });
+}
+
+std::vector<IsValidIdentifierTestCase> getIsValidIdentifierV2TestCases() {
+    std::vector<IsValidIdentifierTestCase> testcases = getIsValidIdentifierTestCases();
+    std::vector<IsValidIdentifierTestCase> testcasesNew = std::vector<IsValidIdentifierTestCase>({
+            IsValidIdentifierTestCase{
+                    .name = "invalid_hd_station_location_id",
+                    .id = utils::makeIdentifier(IdentifierType::HD_STATION_LOCATION,
+                                                kHdStationLocationInvalid),
+                    .valid = false},
+            IsValidIdentifierTestCase{
+                    .name = "valid_hd_station_location_id",
+                    .id = utils::makeIdentifier(IdentifierType::HD_STATION_LOCATION,
+                                                kHdStationLocation),
+                    .valid = true},
+    });
+    testcases.insert(testcases.end(), testcasesNew.begin(), testcasesNew.end());
+    return testcases;
+}
+
+struct IsValidSelectorTestCase {
+    std::string name;
+    ProgramSelector sel;
+    bool valid;
+};
+
+std::vector<IsValidSelectorTestCase> getIsValidSelectorTestCases() {
+    return std::vector<IsValidSelectorTestCase>({
+            IsValidSelectorTestCase{.name = "valid_am_fm_selector",
+                                    .sel = utils::makeSelectorAmfm(kFmFrequencyKHz),
+                                    .valid = true},
+            IsValidSelectorTestCase{
+                    .name = "valid_hd_selector",
+                    .sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency),
+                    .valid = true},
+            IsValidSelectorTestCase{
+                    .name = "valid_dab_selector",
+                    .sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz),
+                    .valid = true},
+            IsValidSelectorTestCase{.name = "valid_rds_selector",
+                                    .sel = ProgramSelector{.primaryId = utils::makeIdentifier(
+                                                                   IdentifierType::RDS_PI, 0x1000)},
+                                    .valid = true},
+            IsValidSelectorTestCase{.name = "selector_with_invalid_id",
+                                    .sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel,
+                                                                 /* frequency= */ 100u),
+                                    .valid = false},
+            IsValidSelectorTestCase{
+                    .name = "selector_with_invalid_primary_id_type",
+                    .sel = ProgramSelector{.primaryId = utils::makeIdentifier(
+                                                   IdentifierType::DAB_ENSEMBLE, kDabEnsemble)},
+                    .valid = false},
+            IsValidSelectorTestCase{
+                    .name = "selector_with_invalid_secondary_id",
+                    .sel = ProgramSelector{.primaryId = utils::makeIdentifier(
+                                                   IdentifierType::DAB_SID_EXT, kDabSidExt),
+                                           .secondaryIds = {utils::makeIdentifier(
+                                                   IdentifierType::DAB_ENSEMBLE, 0x0)}},
+                    .valid = false},
+    });
+}
+
+std::vector<IsValidSelectorTestCase> getIsValidSelectorV2TestCases() {
+    ProgramSelector validHdSel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
+    validHdSel.secondaryIds = {
+            utils::makeIdentifier(IdentifierType::HD_STATION_LOCATION, kHdStationLocation)};
+    ProgramSelector invalidHdSel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
+    invalidHdSel.secondaryIds = {
+            utils::makeIdentifier(IdentifierType::HD_STATION_LOCATION, kHdStationLocationInvalid)};
+    std::vector<IsValidSelectorTestCase> testcasesNew = std::vector<IsValidSelectorTestCase>(
+            {IsValidSelectorTestCase{.name = "hd_selector_with_valid_station_location",
+                                     .sel = validHdSel,
+                                     .valid = true},
+             IsValidSelectorTestCase{.name = "hd_selector_with_invalid_station_location",
+                                     .sel = invalidHdSel,
+                                     .valid = false}});
+    std::vector<IsValidSelectorTestCase> testcases = getIsValidSelectorTestCases();
+    testcases.insert(testcases.end(), testcasesNew.begin(), testcasesNew.end());
+    return testcases;
+}
+
+struct IsValidMetadataTestCase {
+    std::string name;
+    Metadata metadata;
+    bool valid;
+};
+
+std::vector<IsValidMetadataTestCase> getIsValidMetadataTestCases() {
+    return std::vector<IsValidMetadataTestCase>({
+            IsValidMetadataTestCase{.name = "valid_rds_pty",
+                                    .metadata = Metadata::make<Metadata::rdsPty>(1),
+                                    .valid = true},
+            IsValidMetadataTestCase{.name = "negative_rds_pty",
+                                    .metadata = Metadata::make<Metadata::rdsPty>(-1),
+                                    .valid = false},
+            IsValidMetadataTestCase{.name = "large_rds_pty",
+                                    .metadata = Metadata::make<Metadata::rdsPty>(256),
+                                    .valid = false},
+            IsValidMetadataTestCase{.name = "valid_rbds_pty",
+                                    .metadata = Metadata::make<Metadata::rbdsPty>(1),
+                                    .valid = true},
+            IsValidMetadataTestCase{.name = "negative_rbds_pty",
+                                    .metadata = Metadata::make<Metadata::rbdsPty>(-1),
+                                    .valid = false},
+            IsValidMetadataTestCase{.name = "large_rbds_pty",
+                                    .metadata = Metadata::make<Metadata::rbdsPty>(256),
+                                    .valid = false},
+            IsValidMetadataTestCase{
+                    .name = "valid_dab_ensemble_name_short",
+                    .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name"),
+                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "too_long_dab_ensemble_name_short",
+                    .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name_long"),
+                    .valid = false},
+            IsValidMetadataTestCase{
+                    .name = "valid_dab_service_name_short",
+                    .metadata = Metadata::make<Metadata::dabServiceNameShort>("name"),
+                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "too_long_dab_service_name_short",
+                    .metadata = Metadata::make<Metadata::dabServiceNameShort>("name_long"),
+                    .valid = false},
+            IsValidMetadataTestCase{
+                    .name = "valid_dab_component_name_short",
+                    .metadata = Metadata::make<Metadata::dabComponentNameShort>("name"),
+                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "too_long_dab_component_name_short",
+                    .metadata = Metadata::make<Metadata::dabComponentNameShort>("name_long"),
+                    .valid = false},
+    });
+}
+
+std::vector<IsValidMetadataTestCase> getIsValidMetadataV2TestCases() {
+    std::vector<IsValidMetadataTestCase> testcases = getIsValidMetadataTestCases();
+    std::vector<IsValidMetadataTestCase> testcasesNew = std::vector<IsValidMetadataTestCase>({
+            IsValidMetadataTestCase{
+                    .name = "valid_hd_station_name_short",
+                    .metadata = Metadata::make<Metadata::hdStationNameShort>("name_short"),
+                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "too_long_hd_station_name_short",
+                    .metadata = Metadata::make<Metadata::hdStationNameShort>("name_too_long"),
+                    .valid = false},
+            IsValidMetadataTestCase{.name = "valid_hd_subchannel_available",
+                                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(1),
+                                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "negative_subchannel_available",
+                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(-1),
+                    .valid = false},
+            IsValidMetadataTestCase{
+                    .name = "large_subchannel_available",
+                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(256),
+                    .valid = false},
+    });
+    testcases.insert(testcases.end(), testcasesNew.begin(), testcasesNew.end());
+    return testcases;
+}
+}  // namespace
+
+class IsValidIdentifierTest : public testing::TestWithParam<IsValidIdentifierTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidIdentifierTests, IsValidIdentifierTest,
+                         testing::ValuesIn(getIsValidIdentifierTestCases()),
+                         [](const testing::TestParamInfo<IsValidIdentifierTest::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(IsValidIdentifierTest, IsValid) {
+    IsValidIdentifierTestCase testcase = GetParam();
+
+    ASSERT_EQ(utils::isValid(testcase.id), testcase.valid);
+}
+
+class IsValidIdentifierV2Test : public testing::TestWithParam<IsValidIdentifierTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(
+        IsValidIdentifierV2Tests, IsValidIdentifierV2Test,
+        testing::ValuesIn(getIsValidIdentifierV2TestCases()),
+        [](const testing::TestParamInfo<IsValidIdentifierV2Test::ParamType>& info) {
+            return info.param.name;
+        });
+
+TEST_P(IsValidIdentifierV2Test, IsValidV2) {
+    IsValidIdentifierTestCase testcase = GetParam();
+
+    ASSERT_EQ(utils::isValidV2(testcase.id), testcase.valid);
+}
+
+class IsValidSelectorTest : public testing::TestWithParam<IsValidSelectorTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidSelectorTests, IsValidSelectorTest,
+                         testing::ValuesIn(getIsValidSelectorTestCases()),
+                         [](const testing::TestParamInfo<IsValidSelectorTest::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(IsValidSelectorTest, IsValid) {
+    IsValidSelectorTestCase testcase = GetParam();
+
+    ASSERT_EQ(utils::isValid(testcase.sel), testcase.valid);
+}
+
+class IsValidSelectorV2Test : public testing::TestWithParam<IsValidSelectorTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidSelectorV2Tests, IsValidSelectorV2Test,
+                         testing::ValuesIn(getIsValidSelectorV2TestCases()),
+                         [](const testing::TestParamInfo<IsValidSelectorV2Test::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(IsValidSelectorV2Test, IsValidV2) {
+    IsValidSelectorTestCase testcase = GetParam();
+
+    ASSERT_EQ(utils::isValidV2(testcase.sel), testcase.valid);
+}
+
+class IsValidMetadataTest : public testing::TestWithParam<IsValidMetadataTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidMetadataTests, IsValidMetadataTest,
+                         testing::ValuesIn(getIsValidMetadataTestCases()),
+                         [](const testing::TestParamInfo<IsValidMetadataTest::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(IsValidMetadataTest, IsValidMetadata) {
+    IsValidMetadataTestCase testParam = GetParam();
+
+    ASSERT_EQ(utils::isValidMetadata(testParam.metadata), testParam.valid);
+}
+
+class IsValidMetadataV2Test : public testing::TestWithParam<IsValidMetadataTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidMetadataV2Tests, IsValidMetadataV2Test,
+                         testing::ValuesIn(getIsValidMetadataV2TestCases()),
+                         [](const testing::TestParamInfo<IsValidMetadataV2Test::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(IsValidMetadataV2Test, IsValidMetadataV2) {
+    IsValidMetadataTestCase testParam = GetParam();
+
+    ASSERT_EQ(utils::isValidMetadataV2(testParam.metadata), testParam.valid);
+}
+
+}  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
index a5c9073..b633ff0 100644
--- a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
+++ b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
@@ -66,230 +66,6 @@
                              .frequency = 110000,
                              .bandResult = utils::FrequencyBand::UNKNOWN}});
 }
-
-struct IsValidIdentifierTestCase {
-    std::string name;
-    ProgramIdentifier id;
-    bool valid;
-};
-
-std::vector<IsValidIdentifierTestCase> getIsValidIdentifierTestCases() {
-    return std::vector<IsValidIdentifierTestCase>({
-            IsValidIdentifierTestCase{.name = "invalid_id_type",
-                                      .id = utils::makeIdentifier(IdentifierType::INVALID, 0),
-                                      .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_dab_frequency_high",
-                    .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 10000000u),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_dab_frequency_low",
-                    .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 100000u),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "valid_dab_frequency",
-                    .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 1000000u),
-                    .valid = true},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_am_fm_frequency_high",
-                    .id = utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 10000000u),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_am_fm_frequency_low",
-                    .id = utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 100u),
-                    .valid = false},
-            IsValidIdentifierTestCase{.name = "valid_am_fm_frequency",
-                                      .id = utils::makeIdentifier(
-                                              IdentifierType::AMFM_FREQUENCY_KHZ, kFmFrequencyKHz),
-                                      .valid = true},
-            IsValidIdentifierTestCase{
-                    .name = "drmo_frequency_high",
-                    .id = utils::makeIdentifier(IdentifierType::DRMO_FREQUENCY_KHZ, 10000000u),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "drmo_frequency_low",
-                    .id = utils::makeIdentifier(IdentifierType::DRMO_FREQUENCY_KHZ, 100u),
-                    .valid = false},
-            IsValidIdentifierTestCase{.name = "valid_drmo_frequency",
-                                      .id = utils::makeIdentifier(
-                                              IdentifierType::DRMO_FREQUENCY_KHZ, kFmFrequencyKHz),
-                                      .valid = true},
-            IsValidIdentifierTestCase{.name = "invalid_rds_low",
-                                      .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x0),
-                                      .valid = false},
-            IsValidIdentifierTestCase{.name = "invalid_rds_high",
-                                      .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x10000),
-                                      .valid = false},
-            IsValidIdentifierTestCase{.name = "valid_rds",
-                                      .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x1000),
-                                      .valid = true},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_hd_id_zero",
-                    .id = utils::makeSelectorHd(/* stationId= */ 0u, kHdSubChannel, kHdFrequency)
-                                  .primaryId,
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_hd_suchannel",
-                    .id = utils::makeSelectorHd(kHdStationId, /* subChannel= */ 8u, kHdFrequency)
-                                  .primaryId,
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_hd_frequency_low",
-                    .id = utils::makeSelectorHd(kHdStationId, kHdSubChannel, /* frequency= */ 100u)
-                                  .primaryId,
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "valid_hd_id",
-                    .id = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency)
-                                  .primaryId,
-                    .valid = true},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_hd_station_name",
-                    .id = utils::makeIdentifier(IdentifierType::HD_STATION_NAME, 0x41422D464D),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "valid_hd_station_name",
-                    .id = utils::makeIdentifier(IdentifierType::HD_STATION_NAME, 0x414231464D),
-                    .valid = true},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_dab_sid",
-                    .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x0E100000000u),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_dab_ecc_low",
-                    .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x0F700000221u),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_dab_ecc_high",
-                    .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x09900000221u),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "valid_dab_sid_ext",
-                    .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, kDabSidExt),
-                    .valid = true},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_dab_ensemble_zero",
-                    .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, 0x0),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_dab_ensemble_high",
-                    .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, 0x10000),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "valid_dab_ensemble",
-                    .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, kDabEnsemble),
-                    .valid = true},
-            IsValidIdentifierTestCase{.name = "invalid_dab_scid_low",
-                                      .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0xF),
-                                      .valid = false},
-            IsValidIdentifierTestCase{.name = "invalid_dab_scid_high",
-                                      .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0x1000),
-                                      .valid = false},
-            IsValidIdentifierTestCase{.name = "valid_dab_scid",
-                                      .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0x100),
-                                      .valid = true},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_drmo_id_zero",
-                    .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x0),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "invalid_drmo_id_high",
-                    .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x1000000),
-                    .valid = false},
-            IsValidIdentifierTestCase{
-                    .name = "valid_drmo_id",
-                    .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000),
-                    .valid = true},
-    });
-}
-
-struct IsValidSelectorTestCase {
-    std::string name;
-    ProgramSelector sel;
-    bool valid;
-};
-
-std::vector<IsValidSelectorTestCase> getIsValidSelectorTestCases() {
-    return std::vector<IsValidSelectorTestCase>({
-            IsValidSelectorTestCase{.name = "valid_am_fm_selector",
-                                    .sel = utils::makeSelectorAmfm(kFmFrequencyKHz),
-                                    .valid = true},
-            IsValidSelectorTestCase{
-                    .name = "valid_hd_selector",
-                    .sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency),
-                    .valid = true},
-            IsValidSelectorTestCase{
-                    .name = "valid_dab_selector",
-                    .sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz),
-                    .valid = true},
-            IsValidSelectorTestCase{.name = "valid_rds_selector",
-                                    .sel = ProgramSelector{.primaryId = utils::makeIdentifier(
-                                                                   IdentifierType::RDS_PI, 0x1000)},
-                                    .valid = true},
-            IsValidSelectorTestCase{.name = "selector_with_invalid_id",
-                                    .sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel,
-                                                                 /* frequency= */ 100u),
-                                    .valid = false},
-            IsValidSelectorTestCase{
-                    .name = "selector_with_invalid_primary_id_type",
-                    .sel = ProgramSelector{.primaryId = utils::makeIdentifier(
-                                                   IdentifierType::DAB_ENSEMBLE, kDabEnsemble)},
-                    .valid = false},
-    });
-}
-
-struct IsValidMetadataTestCase {
-    std::string name;
-    Metadata metadata;
-    bool valid;
-};
-
-std::vector<IsValidMetadataTestCase> getIsValidMetadataTestCases() {
-    return std::vector<IsValidMetadataTestCase>({
-            IsValidMetadataTestCase{.name = "valid_rds_pty",
-                                    .metadata = Metadata::make<Metadata::rdsPty>(1),
-                                    .valid = true},
-            IsValidMetadataTestCase{.name = "negative_rds_pty",
-                                    .metadata = Metadata::make<Metadata::rdsPty>(-1),
-                                    .valid = false},
-            IsValidMetadataTestCase{.name = "large_rds_pty",
-                                    .metadata = Metadata::make<Metadata::rdsPty>(256),
-                                    .valid = false},
-            IsValidMetadataTestCase{.name = "valid_rbds_pty",
-                                    .metadata = Metadata::make<Metadata::rbdsPty>(1),
-                                    .valid = true},
-            IsValidMetadataTestCase{.name = "negative_rbds_pty",
-                                    .metadata = Metadata::make<Metadata::rbdsPty>(-1),
-                                    .valid = false},
-            IsValidMetadataTestCase{.name = "large_rbds_pty",
-                                    .metadata = Metadata::make<Metadata::rbdsPty>(256),
-                                    .valid = false},
-            IsValidMetadataTestCase{
-                    .name = "valid_dab_ensemble_name_short",
-                    .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name"),
-                    .valid = true},
-            IsValidMetadataTestCase{
-                    .name = "too_long_dab_ensemble_name_short",
-                    .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name_long"),
-                    .valid = false},
-            IsValidMetadataTestCase{
-                    .name = "valid_dab_service_name_short",
-                    .metadata = Metadata::make<Metadata::dabServiceNameShort>("name"),
-                    .valid = true},
-            IsValidMetadataTestCase{
-                    .name = "too_long_dab_service_name_short",
-                    .metadata = Metadata::make<Metadata::dabServiceNameShort>("name_long"),
-                    .valid = false},
-            IsValidMetadataTestCase{
-                    .name = "valid_dab_component_name_short",
-                    .metadata = Metadata::make<Metadata::dabComponentNameShort>("name"),
-                    .valid = true},
-            IsValidMetadataTestCase{
-                    .name = "too_long_dab_component_name_short",
-                    .metadata = Metadata::make<Metadata::dabComponentNameShort>("name_long"),
-                    .valid = false},
-    });
-}
 }  // namespace
 
 class GetBandTest : public testing::TestWithParam<GetBandTestCase> {};
@@ -305,48 +81,6 @@
     ASSERT_EQ(utils::getBand(testcase.frequency), testcase.bandResult);
 }
 
-class IsValidMetadataTest : public testing::TestWithParam<IsValidMetadataTestCase> {};
-
-INSTANTIATE_TEST_SUITE_P(IsValidMetadataTests, IsValidMetadataTest,
-                         testing::ValuesIn(getIsValidMetadataTestCases()),
-                         [](const testing::TestParamInfo<IsValidMetadataTest::ParamType>& info) {
-                             return info.param.name;
-                         });
-
-TEST_P(IsValidMetadataTest, IsValidMetadata) {
-    IsValidMetadataTestCase testParam = GetParam();
-
-    ASSERT_EQ(utils::isValidMetadata(testParam.metadata), testParam.valid);
-}
-
-class IsValidIdentifierTest : public testing::TestWithParam<IsValidIdentifierTestCase> {};
-
-INSTANTIATE_TEST_SUITE_P(IsValidIdentifierTests, IsValidIdentifierTest,
-                         testing::ValuesIn(getIsValidIdentifierTestCases()),
-                         [](const testing::TestParamInfo<IsValidIdentifierTest::ParamType>& info) {
-                             return info.param.name;
-                         });
-
-TEST_P(IsValidIdentifierTest, IsValid) {
-    IsValidIdentifierTestCase testcase = GetParam();
-
-    ASSERT_EQ(utils::isValid(testcase.id), testcase.valid);
-}
-
-class IsValidSelectorTest : public testing::TestWithParam<IsValidSelectorTestCase> {};
-
-INSTANTIATE_TEST_SUITE_P(IsValidSelectorTests, IsValidSelectorTest,
-                         testing::ValuesIn(getIsValidSelectorTestCases()),
-                         [](const testing::TestParamInfo<IsValidSelectorTest::ParamType>& info) {
-                             return info.param.name;
-                         });
-
-TEST_P(IsValidSelectorTest, IsValid) {
-    IsValidSelectorTestCase testcase = GetParam();
-
-    ASSERT_EQ(utils::isValid(testcase.sel), testcase.valid);
-}
-
 TEST(BroadcastRadioUtilsTest, IdentifierIteratorBegin) {
     ProgramSelector sel = {
             .primaryId = utils::makeIdentifier(IdentifierType::RDS_PI, kRdsValue),
diff --git a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp
deleted file mode 100644
index cf9f9e9..0000000
--- a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2024 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 <broadcastradio-utils-aidl/UtilsV2.h>
-#include <gtest/gtest.h>
-
-namespace aidl::android::hardware::broadcastradio {
-
-namespace {
-struct IsValidMetadataV2TestCase {
-    std::string name;
-    Metadata metadata;
-    bool valid;
-};
-
-std::vector<IsValidMetadataV2TestCase> getIsValidMetadataV2TestCases() {
-    return std::vector<IsValidMetadataV2TestCase>({
-            IsValidMetadataV2TestCase{.name = "valid_rds_pty",
-                                      .metadata = Metadata::make<Metadata::rdsPty>(1),
-                                      .valid = true},
-            IsValidMetadataV2TestCase{.name = "negative_rds_pty",
-                                      .metadata = Metadata::make<Metadata::rdsPty>(-1),
-                                      .valid = false},
-            IsValidMetadataV2TestCase{
-                    .name = "valid_hd_station_name_short",
-                    .metadata = Metadata::make<Metadata::hdStationNameShort>("name_short"),
-                    .valid = true},
-            IsValidMetadataV2TestCase{
-                    .name = "too_long_hd_station_name_short",
-                    .metadata = Metadata::make<Metadata::hdStationNameShort>("name_too_long"),
-                    .valid = false},
-            IsValidMetadataV2TestCase{
-                    .name = "valid_hd_subchannel_available",
-                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(1),
-                    .valid = true},
-            IsValidMetadataV2TestCase{
-                    .name = "negative_subchannel_available",
-                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(-1),
-                    .valid = false},
-            IsValidMetadataV2TestCase{
-                    .name = "large_subchannel_available",
-                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(256),
-                    .valid = false},
-    });
-}
-}  // namespace
-
-class IsValidMetadataV2Test : public testing::TestWithParam<IsValidMetadataV2TestCase> {};
-
-INSTANTIATE_TEST_SUITE_P(IsValidMetadataV2Tests, IsValidMetadataV2Test,
-                         testing::ValuesIn(getIsValidMetadataV2TestCases()),
-                         [](const testing::TestParamInfo<IsValidMetadataV2Test::ParamType>& info) {
-                             return info.param.name;
-                         });
-
-TEST_P(IsValidMetadataV2Test, IsValidMetadataV2) {
-    IsValidMetadataV2TestCase testParam = GetParam();
-
-    ASSERT_EQ(utils::isValidMetadataV2(testParam.metadata), testParam.valid);
-}
-
-}  // namespace aidl::android::hardware::broadcastradio
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 1457b8a..11de087 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -11,10 +11,7 @@
     name: "android.hardware.common",
     host_supported: true,
     vendor_available: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
+    double_loadable: true,
     vndk_use_version: "2",
     srcs: [
         "android/hardware/common/*.aidl",
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 6c37213..17c11ab 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -11,10 +11,7 @@
     name: "android.hardware.common.fmq",
     host_supported: true,
     vendor_available: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
+    double_loadable: true,
     srcs: [
         "android/hardware/common/fmq/*.aidl",
     ],
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 2b69442..951ca85 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -88,8 +88,7 @@
     stem: "compatibility_matrix.202504.xml",
     srcs: ["compatibility_matrix.202504.xml"],
     kernel_configs: [
-        "kernel_config_w_6.1",
-        "kernel_config_w_6.6",
+        "kernel_config_w_6.next",
     ],
 
 }
diff --git a/configstore/1.0/Android.bp b/configstore/1.0/Android.bp
index 51fc44c..ef781d2 100644
--- a/configstore/1.0/Android.bp
+++ b/configstore/1.0/Android.bp
@@ -12,9 +12,6 @@
 hidl_interface {
     name: "android.hardware.configstore@1.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "types.hal",
         "ISurfaceFlingerConfigs.hal",
diff --git a/configstore/1.1/Android.bp b/configstore/1.1/Android.bp
index ec745dd..c8c3f5e 100644
--- a/configstore/1.1/Android.bp
+++ b/configstore/1.1/Android.bp
@@ -12,9 +12,6 @@
 hidl_interface {
     name: "android.hardware.configstore@1.1",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "types.hal",
         "ISurfaceFlingerConfigs.hal",
diff --git a/configstore/utils/Android.bp b/configstore/utils/Android.bp
index 7ed3f68..b62f1bc 100644
--- a/configstore/utils/Android.bp
+++ b/configstore/utils/Android.bp
@@ -26,13 +26,10 @@
 cc_library_shared {
     name: "android.hardware.configstore-utils",
     vendor_available: true,
-    vndk: {
-        enabled: true,
-    },
     double_loadable: true,
     defaults: ["hidl_defaults"],
 
-    srcs: [ "ConfigStoreUtils.cpp" ],
+    srcs: ["ConfigStoreUtils.cpp"],
 
     export_include_dirs: ["include"],
 
@@ -40,12 +37,12 @@
         "android.hardware.configstore@1.0",
         "android.hardware.configstore@1.1",
         "libbase",
-        "libhidlbase"
+        "libhidlbase",
     ],
     export_shared_lib_headers: [
         "android.hardware.configstore@1.0",
         "android.hardware.configstore@1.1",
         "libbase",
-        "libhidlbase"
+        "libhidlbase",
     ],
 }
diff --git a/confirmationui/support/Android.bp b/confirmationui/support/Android.bp
index 1200115..67cc04b 100644
--- a/confirmationui/support/Android.bp
+++ b/confirmationui/support/Android.bp
@@ -27,9 +27,6 @@
     name: "android.hardware.confirmationui-support-lib",
     vendor_available: true,
     host_supported: true,
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "src/cbor.cpp",
         "src/confirmationui_utils.cpp",
diff --git a/graphics/allocator/2.0/Android.bp b/graphics/allocator/2.0/Android.bp
index 36158e9..5d3f883 100644
--- a/graphics/allocator/2.0/Android.bp
+++ b/graphics/allocator/2.0/Android.bp
@@ -13,9 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.allocator@2.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "IAllocator.hal",
     ],
diff --git a/graphics/allocator/3.0/Android.bp b/graphics/allocator/3.0/Android.bp
index 0100f6f..767a79f 100644
--- a/graphics/allocator/3.0/Android.bp
+++ b/graphics/allocator/3.0/Android.bp
@@ -13,9 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.allocator@3.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "IAllocator.hal",
     ],
diff --git a/graphics/allocator/4.0/Android.bp b/graphics/allocator/4.0/Android.bp
index 5d7a4a9..590ecf4 100644
--- a/graphics/allocator/4.0/Android.bp
+++ b/graphics/allocator/4.0/Android.bp
@@ -13,9 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.allocator@4.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "IAllocator.hal",
     ],
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
index 6e24edc..0b916bf 100644
--- a/graphics/allocator/aidl/Android.bp
+++ b/graphics/allocator/aidl/Android.bp
@@ -11,10 +11,7 @@
 aidl_interface {
     name: "android.hardware.graphics.allocator",
     vendor_available: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
+    double_loadable: true,
     vndk_use_version: "2",
     srcs: ["android/hardware/graphics/allocator/*.aidl"],
     imports: [
@@ -34,9 +31,6 @@
                 "//apex_available:platform",
                 "com.android.media.swcodec",
             ],
-            vndk: {
-                enabled: true,
-            },
             min_sdk_version: "29",
         },
     },
diff --git a/graphics/bufferqueue/1.0/Android.bp b/graphics/bufferqueue/1.0/Android.bp
index fe46b5e..c7c6453 100644
--- a/graphics/bufferqueue/1.0/Android.bp
+++ b/graphics/bufferqueue/1.0/Android.bp
@@ -13,9 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.bufferqueue@1.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "IGraphicBufferProducer.hal",
         "IProducerListener.hal",
diff --git a/graphics/bufferqueue/2.0/Android.bp b/graphics/bufferqueue/2.0/Android.bp
index c2b0985..e9f75c1 100644
--- a/graphics/bufferqueue/2.0/Android.bp
+++ b/graphics/bufferqueue/2.0/Android.bp
@@ -13,9 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.bufferqueue@2.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "types.hal",
         "IGraphicBufferProducer.hal",
diff --git a/graphics/common/1.0/Android.bp b/graphics/common/1.0/Android.bp
index 786953b..b876bf3 100644
--- a/graphics/common/1.0/Android.bp
+++ b/graphics/common/1.0/Android.bp
@@ -13,10 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.common@1.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     srcs: [
         "types.hal",
     ],
diff --git a/graphics/common/1.1/Android.bp b/graphics/common/1.1/Android.bp
index d857f80..ff6c9b7 100644
--- a/graphics/common/1.1/Android.bp
+++ b/graphics/common/1.1/Android.bp
@@ -13,10 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.common@1.1",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     srcs: [
         "types.hal",
     ],
diff --git a/graphics/common/1.2/Android.bp b/graphics/common/1.2/Android.bp
index 17d0c20..b4663e5 100644
--- a/graphics/common/1.2/Android.bp
+++ b/graphics/common/1.2/Android.bp
@@ -13,10 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.common@1.2",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     srcs: [
         "types.hal",
     ],
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 570f735..33d0938 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -12,10 +12,7 @@
     name: "android.hardware.graphics.common",
     host_supported: true,
     vendor_available: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
+    double_loadable: true,
     vndk_use_version: "5",
     srcs: [
         "android/hardware/graphics/common/*.aidl",
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index 87ecb16..fad70d8 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -28,10 +28,7 @@
     name: "android.hardware.graphics.composer3",
     host_supported: true,
     vendor_available: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
+    double_loadable: true,
     frozen: true,
     vndk_use_version: "1",
     srcs: [
@@ -51,9 +48,6 @@
             enabled: false,
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
         },
         rust: {
             enabled: true,
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
index 106fd87..99c91aa 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
@@ -28,6 +28,10 @@
 union CommandResultPayload {
     /**
      * Indicates an error generated by a command.
+     *
+     * If there is an error from a command, the composer should only respond
+     * with the CommandError, and not with other results
+     * (e.g. ChangedCompositionTypes).
      */
     CommandError error;
 
diff --git a/graphics/mapper/2.0/Android.bp b/graphics/mapper/2.0/Android.bp
index 81040ab..07ca1cb 100644
--- a/graphics/mapper/2.0/Android.bp
+++ b/graphics/mapper/2.0/Android.bp
@@ -13,10 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.mapper@2.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     srcs: [
         "types.hal",
         "IMapper.hal",
diff --git a/graphics/mapper/2.1/Android.bp b/graphics/mapper/2.1/Android.bp
index 1308a6c..f6e089a 100644
--- a/graphics/mapper/2.1/Android.bp
+++ b/graphics/mapper/2.1/Android.bp
@@ -13,10 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.mapper@2.1",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     srcs: [
         "IMapper.hal",
     ],
diff --git a/graphics/mapper/3.0/Android.bp b/graphics/mapper/3.0/Android.bp
index b49806f..0e15af9 100644
--- a/graphics/mapper/3.0/Android.bp
+++ b/graphics/mapper/3.0/Android.bp
@@ -13,10 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.mapper@3.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     srcs: [
         "types.hal",
         "IMapper.hal",
diff --git a/graphics/mapper/4.0/Android.bp b/graphics/mapper/4.0/Android.bp
index c07f73c..b2dd7d2 100644
--- a/graphics/mapper/4.0/Android.bp
+++ b/graphics/mapper/4.0/Android.bp
@@ -13,10 +13,6 @@
 hidl_interface {
     name: "android.hardware.graphics.mapper@4.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     srcs: [
         "types.hal",
         "IMapper.hal",
diff --git a/media/1.0/Android.bp b/media/1.0/Android.bp
index 22a6d59..d5ef95a 100644
--- a/media/1.0/Android.bp
+++ b/media/1.0/Android.bp
@@ -12,9 +12,6 @@
 hidl_interface {
     name: "android.hardware.media@1.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "types.hal",
     ],
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index fd6f08b..470a11f 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -13,9 +13,6 @@
 hidl_interface {
     name: "android.hardware.media.bufferpool@2.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "types.hal",
         "IAccessor.hal",
diff --git a/media/bufferpool/aidl/default/BufferPool.cpp b/media/bufferpool/aidl/default/BufferPool.cpp
index ed4574f..57716db 100644
--- a/media/bufferpool/aidl/default/BufferPool.cpp
+++ b/media/bufferpool/aidl/default/BufferPool.cpp
@@ -102,11 +102,11 @@
         if (it->isInvalidated(bufferId)) {
             uint32_t msgId = 0;
             if (it->mNeedsAck) {
-                msgId = ++mInvalidationId;
-                if (msgId == 0) {
-                    // wrap happens
-                    msgId = ++mInvalidationId;
+                if (mInvalidationId == UINT_MAX) {
+                    // wrap happens;
+                    mInvalidationId = 0;
                 }
+                msgId = ++mInvalidationId;
             }
             channel.postInvalidation(msgId, it->mFrom, it->mTo);
             it = mPendings.erase(it);
@@ -125,11 +125,11 @@
         const std::shared_ptr<Accessor> &impl) {
         uint32_t msgId = 0;
     if (needsAck) {
-        msgId = ++mInvalidationId;
-        if (msgId == 0) {
-            // wrap happens
-            msgId = ++mInvalidationId;
+        if (mInvalidationId == UINT_MAX) {
+            //wrap happens
+            mInvalidationId = 0;
         }
+        msgId = ++mInvalidationId;
     }
     ALOGV("bufferpool2 invalidation requested and queued");
     if (left == 0) {
diff --git a/media/bufferpool/aidl/default/BufferStatus.cpp b/media/bufferpool/aidl/default/BufferStatus.cpp
index 19caa1e..fecbe3f 100644
--- a/media/bufferpool/aidl/default/BufferStatus.cpp
+++ b/media/bufferpool/aidl/default/BufferStatus.cpp
@@ -26,8 +26,17 @@
 
 using aidl::android::hardware::media::bufferpool2::BufferStatus;
 
+uint32_t wrappedMinus(uint32_t a, uint32_t b) {
+    if (a >= b) {
+        return a - b;
+    } else {
+        return ~(b - a) + 1;
+    }
+}
+
 bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId) {
-    return curMsgId != prevMsgId && curMsgId - prevMsgId < prevMsgId - curMsgId;
+    return curMsgId != prevMsgId &&
+            wrappedMinus(curMsgId, prevMsgId) < wrappedMinus(prevMsgId, curMsgId);
 }
 
 bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId) {
diff --git a/media/omx/1.0/Android.bp b/media/omx/1.0/Android.bp
index ea63467..cd1b9b6 100644
--- a/media/omx/1.0/Android.bp
+++ b/media/omx/1.0/Android.bp
@@ -12,9 +12,6 @@
 hidl_interface {
     name: "android.hardware.media.omx@1.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "types.hal",
         "IGraphicBufferSource.hal",
diff --git a/memtrack/1.0/Android.bp b/memtrack/1.0/Android.bp
index bf8db3f..1aeec59 100644
--- a/memtrack/1.0/Android.bp
+++ b/memtrack/1.0/Android.bp
@@ -12,9 +12,6 @@
 hidl_interface {
     name: "android.hardware.memtrack@1.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "types.hal",
         "IMemtrack.hal",
diff --git a/memtrack/aidl/Android.bp b/memtrack/aidl/Android.bp
index 0d1c241..4973d1e 100644
--- a/memtrack/aidl/Android.bp
+++ b/memtrack/aidl/Android.bp
@@ -34,9 +34,6 @@
             enabled: false,
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
         },
     },
     frozen: true,
diff --git a/nfc/aidl/vts/functional/Android.bp b/nfc/aidl/vts/functional/Android.bp
index 0dab2d8..fcaaf33 100644
--- a/nfc/aidl/vts/functional/Android.bp
+++ b/nfc/aidl/vts/functional/Android.bp
@@ -45,3 +45,45 @@
         "vts",
     ],
 }
+
+cc_test {
+    name: "VtsNfcBehaviorChangesTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsNfcBehaviorChangesTest.cpp",
+        "CondVar.cpp",
+    ],
+    include_dirs: [
+        "system/nfc/src/gki/common",
+        "system/nfc/src/gki/ulinux",
+        "system/nfc/src/include",
+        "system/nfc/src/nfa/include",
+        "system/nfc/src/nfc/include",
+        "system/nfc/utils/include",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libnativehelper",
+        "libstatssocket",
+    ],
+    static_libs: [
+        "android.hardware.nfc-V1-ndk",
+        "android.hardware.nfc@1.0",
+        "android.hardware.nfc@1.1",
+        "android.hardware.nfc@1.2",
+        "android_nfc_flags_aconfig_c_lib",
+        "libnfc-nci",
+        "libnfc-nci_flags",
+        "libnfcutils",
+        "libstatslog_nfc",
+        "server_configurable_flags",
+    ],
+    require_root: true,
+    test_suites: [
+        "vts",
+    ],
+}
diff --git a/nfc/aidl/vts/functional/CondVar.cpp b/nfc/aidl/vts/functional/CondVar.cpp
new file mode 100644
index 0000000..59e5b51
--- /dev/null
+++ b/nfc/aidl/vts/functional/CondVar.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ *  Encapsulate a condition variable for thread synchronization.
+ */
+
+#include "CondVar.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <errno.h>
+#include <string.h>
+
+using android::base::StringPrintf;
+
+/*******************************************************************************
+**
+** Function:        CondVar
+**
+** Description:     Initialize member variables.
+**
+** Returns:         None.
+**
+*******************************************************************************/
+CondVar::CondVar() {
+    pthread_condattr_t attr;
+    pthread_condattr_init(&attr);
+    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+    memset(&mCondition, 0, sizeof(mCondition));
+    int const res = pthread_cond_init(&mCondition, &attr);
+    if (res) {
+        LOG(ERROR) << StringPrintf("CondVar::CondVar: fail init; error=0x%X", res);
+    }
+}
+
+/*******************************************************************************
+**
+** Function:        ~CondVar
+**
+** Description:     Cleanup all resources.
+**
+** Returns:         None.
+**
+*******************************************************************************/
+CondVar::~CondVar() {
+    int const res = pthread_cond_destroy(&mCondition);
+    if (res) {
+        LOG(ERROR) << StringPrintf("CondVar::~CondVar: fail destroy; error=0x%X", res);
+    }
+}
+
+/*******************************************************************************
+**
+** Function:        wait
+**
+** Description:     Block the caller and wait for a condition.
+**
+** Returns:         None.
+**
+*******************************************************************************/
+void CondVar::wait(std::mutex& mutex) {
+    int const res = pthread_cond_wait(&mCondition, mutex.native_handle());
+    if (res) {
+        LOG(ERROR) << StringPrintf("CondVar::wait: fail wait; error=0x%X", res);
+    }
+}
+
+/*******************************************************************************
+**
+** Function:        wait
+**
+** Description:     Block the caller and wait for a condition.
+**                  millisec: Timeout in milliseconds.
+**
+** Returns:         True if wait is successful; false if timeout occurs.
+**
+*******************************************************************************/
+bool CondVar::wait(std::mutex& mutex, long millisec) {
+    bool retVal = false;
+    struct timespec absoluteTime;
+
+    if (clock_gettime(CLOCK_MONOTONIC, &absoluteTime) == -1) {
+        LOG(ERROR) << StringPrintf("CondVar::wait: fail get time; errno=0x%X", errno);
+    } else {
+        absoluteTime.tv_sec += millisec / 1000;
+        long ns = absoluteTime.tv_nsec + ((millisec % 1000) * 1000000);
+        if (ns > 1000000000) {
+            absoluteTime.tv_sec++;
+            absoluteTime.tv_nsec = ns - 1000000000;
+        } else
+            absoluteTime.tv_nsec = ns;
+    }
+
+    int waitResult = pthread_cond_timedwait(&mCondition, mutex.native_handle(), &absoluteTime);
+    if ((waitResult != 0) && (waitResult != ETIMEDOUT))
+        LOG(ERROR) << StringPrintf("CondVar::wait: fail timed wait; error=0x%X", waitResult);
+    retVal = (waitResult == 0);  // waited successfully
+    return retVal;
+}
+
+/*******************************************************************************
+**
+** Function:        notifyOne
+**
+** Description:     Unblock the waiting thread.
+**
+** Returns:         None.
+**
+*******************************************************************************/
+void CondVar::notifyOne() {
+    int const res = pthread_cond_signal(&mCondition);
+    if (res) {
+        LOG(ERROR) << StringPrintf("CondVar::notifyOne: fail signal; error=0x%X", res);
+    }
+}
diff --git a/nfc/aidl/vts/functional/CondVar.h b/nfc/aidl/vts/functional/CondVar.h
new file mode 100644
index 0000000..5e0dcf7
--- /dev/null
+++ b/nfc/aidl/vts/functional/CondVar.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ *  Encapsulate a condition variable for thread synchronization.
+ */
+
+#pragma once
+#include <pthread.h>
+
+#include <mutex>
+
+class CondVar {
+  public:
+    /*******************************************************************************
+    **
+    ** Function:        CondVar
+    **
+    ** Description:     Initialize member variables.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    CondVar();
+
+    /*******************************************************************************
+    **
+    ** Function:        ~CondVar
+    **
+    ** Description:     Cleanup all resources.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    ~CondVar();
+
+    /*******************************************************************************
+    **
+    ** Function:        wait
+    **
+    ** Description:     Block the caller and wait for a condition.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    void wait(std::mutex& mutex);
+
+    /*******************************************************************************
+    **
+    ** Function:        wait
+    **
+    ** Description:     Block the caller and wait for a condition.
+    **                  millisec: Timeout in milliseconds.
+    **
+    ** Returns:         True if wait is successful; false if timeout occurs.
+    **
+    *******************************************************************************/
+    bool wait(std::mutex& mutex, long millisec);
+
+    /*******************************************************************************
+    **
+    ** Function:        notifyOne
+    **
+    ** Description:     Unblock the waiting thread.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    void notifyOne();
+
+  private:
+    pthread_cond_t mCondition;
+};
diff --git a/nfc/aidl/vts/functional/SyncEvent.h b/nfc/aidl/vts/functional/SyncEvent.h
new file mode 100644
index 0000000..352a549
--- /dev/null
+++ b/nfc/aidl/vts/functional/SyncEvent.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ *  Synchronize two or more threads using a condition variable and a mutex.
+ */
+#pragma once
+#include <mutex>
+
+#include "CondVar.h"
+
+class SyncEvent {
+  public:
+    /*******************************************************************************
+    **
+    ** Function:        ~SyncEvent
+    **
+    ** Description:     Cleanup all resources.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    ~SyncEvent() {}
+
+    /*******************************************************************************
+    **
+    ** Function:        start
+    **
+    ** Description:     Start a synchronization operation.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    void start() { mMutex.lock(); }
+
+    /*******************************************************************************
+    **
+    ** Function:        wait
+    **
+    ** Description:     Block the thread and wait for the event to occur.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    void wait() { mCondVar.wait(mMutex); }
+
+    /*******************************************************************************
+    **
+    ** Function:        wait
+    **
+    ** Description:     Block the thread and wait for the event to occur.
+    **                  millisec: Timeout in milliseconds.
+    **
+    ** Returns:         True if wait is successful; false if timeout occurs.
+    **
+    *******************************************************************************/
+    bool wait(long millisec) {
+        bool retVal = mCondVar.wait(mMutex, millisec);
+        return retVal;
+    }
+
+    /*******************************************************************************
+    **
+    ** Function:        notifyOne
+    **
+    ** Description:     Notify a blocked thread that the event has occurred.
+    *Unblocks it.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    void notifyOne() { mCondVar.notifyOne(); }
+
+    /*******************************************************************************
+    **
+    ** Function:        end
+    **
+    ** Description:     End a synchronization operation.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    void end() { mMutex.unlock(); }
+
+  private:
+    CondVar mCondVar;
+    std::mutex mMutex;
+};
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+/*****************************************************************************
+**
+**  Name:           SyncEventGuard
+**
+**  Description:    Automatically start and end a synchronization event.
+**
+*****************************************************************************/
+class SyncEventGuard {
+  public:
+    /*******************************************************************************
+    **
+    ** Function:        SyncEventGuard
+    **
+    ** Description:     Start a synchronization operation.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    SyncEventGuard(SyncEvent& event) : mEvent(event) {
+        event.start();  // automatically start operation
+    };
+
+    /*******************************************************************************
+    **
+    ** Function:        ~SyncEventGuard
+    **
+    ** Description:     End a synchronization operation.
+    **
+    ** Returns:         None.
+    **
+    *******************************************************************************/
+    ~SyncEventGuard() {
+        mEvent.end();  // automatically end operation
+    };
+
+  private:
+    SyncEvent& mEvent;
+};
diff --git a/nfc/aidl/vts/functional/VtsNfcBehaviorChangesTest.cpp b/nfc/aidl/vts/functional/VtsNfcBehaviorChangesTest.cpp
new file mode 100644
index 0000000..0b73cc9
--- /dev/null
+++ b/nfc/aidl/vts/functional/VtsNfcBehaviorChangesTest.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "nfc_behavior_changes_test"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <future>
+
+#include "NfcAdaptation.h"
+#include "SyncEvent.h"
+#include "nci_defs.h"
+#include "nfa_api.h"
+#include "nfa_ee_api.h"
+
+using android::base::StringPrintf;
+
+static SyncEvent sNfaEnableEvent;  // event for NFA_Enable()
+static SyncEvent sNfaVsCommand;    // event for VS commands
+static SyncEvent sNfaEnableDisablePollingEvent;
+static SyncEvent sNfaPowerChangeEvent;
+static bool sIsNfaEnabled;
+static tNFA_STATUS sVSCmdStatus;
+
+static void nfaDeviceManagementCallback(uint8_t dmEvent, tNFA_DM_CBACK_DATA* eventData) {
+    LOG(DEBUG) << StringPrintf("%s: enter; event=0x%X", __func__, dmEvent);
+
+    switch (dmEvent) {
+        case NFA_DM_ENABLE_EVT: /* Result of NFA_Enable */
+        {
+            SyncEventGuard guard(sNfaEnableEvent);
+            LOG(DEBUG) << StringPrintf("%s: NFA_DM_ENABLE_EVT; status=0x%X", __func__,
+                                       eventData->status);
+            sIsNfaEnabled = eventData->status == NFA_STATUS_OK;
+            sNfaEnableEvent.notifyOne();
+        } break;
+
+        case NFA_DM_DISABLE_EVT: /* Result of NFA_Disable */
+        {
+            SyncEventGuard guard(sNfaEnableEvent);
+            LOG(DEBUG) << StringPrintf("%s: NFA_DM_DISABLE_EVT; status=0x%X", __func__,
+                                       eventData->status);
+            sIsNfaEnabled = eventData->status == NFA_STATUS_OK;
+            sNfaEnableEvent.notifyOne();
+        } break;
+
+        case NFA_DM_PWR_MODE_CHANGE_EVT: {
+            SyncEventGuard guard(sNfaPowerChangeEvent);
+            LOG(DEBUG) << StringPrintf(
+                    "%s: NFA_DM_PWR_MODE_CHANGE_EVT: status=0x%X, power_mode=0x%X", __func__,
+                    eventData->status, eventData->power_mode.power_mode);
+
+            sNfaPowerChangeEvent.notifyOne();
+
+        } break;
+    }
+}
+
+static void nfaConnectionCallback(uint8_t connEvent, tNFA_CONN_EVT_DATA* eventData) {
+    LOG(DEBUG) << StringPrintf("%s: event= %u", __func__, connEvent);
+
+    switch (connEvent) {
+        case NFA_LISTEN_DISABLED_EVT: {
+            SyncEventGuard guard(sNfaEnableDisablePollingEvent);
+            sNfaEnableDisablePollingEvent.notifyOne();
+        } break;
+
+        case NFA_LISTEN_ENABLED_EVT: {
+            SyncEventGuard guard(sNfaEnableDisablePollingEvent);
+            sNfaEnableDisablePollingEvent.notifyOne();
+        } break;
+
+        case NFA_RF_DISCOVERY_STARTED_EVT:  // RF Discovery started
+        {
+            LOG(DEBUG) << StringPrintf("%s: NFA_RF_DISCOVERY_STARTED_EVT: status = %u", __func__,
+                                       eventData->status);
+
+            SyncEventGuard guard(sNfaEnableDisablePollingEvent);
+            sNfaEnableDisablePollingEvent.notifyOne();
+        } break;
+
+        case NFA_RF_DISCOVERY_STOPPED_EVT:  // RF Discovery stopped event
+        {
+            LOG(DEBUG) << StringPrintf("%s: NFA_RF_DISCOVERY_STOPPED_EVT: status = %u", __func__,
+                                       eventData->status);
+
+            SyncEventGuard guard(sNfaEnableDisablePollingEvent);
+            sNfaEnableDisablePollingEvent.notifyOne();
+        } break;
+    }
+}
+
+void static nfaVSCallback(uint8_t event, uint16_t /* param_len */, uint8_t* p_param) {
+    switch (event & NCI_OID_MASK) {
+        case NCI_MSG_PROP_ANDROID: {
+            uint8_t android_sub_opcode = p_param[3];
+            switch (android_sub_opcode) {
+                case NCI_ANDROID_PASSIVE_OBSERVE: {
+                    sVSCmdStatus = p_param[4];
+                    LOG(INFO) << StringPrintf("Observe mode RSP: status: %x", sVSCmdStatus);
+                    SyncEventGuard guard(sNfaVsCommand);
+                    sNfaVsCommand.notifyOne();
+                } break;
+                case NCI_ANDROID_POLLING_FRAME_NTF: {
+                    // TODO
+                } break;
+                default:
+                    LOG(WARNING) << StringPrintf("Unknown Android sub opcode %x",
+                                                 android_sub_opcode);
+            }
+        } break;
+        default:
+            break;
+    }
+}
+
+/*
+ * Enable passive observe mode.
+ */
+tNFA_STATUS static nfaObserveModeEnable(bool enable) {
+    tNFA_STATUS status = NFA_STATUS_FAILED;
+
+    status = NFA_StopRfDiscovery();
+    if (status == NFA_STATUS_OK) {
+        if (!sNfaEnableDisablePollingEvent.wait(1000)) {
+            LOG(WARNING) << "Timeout waiting to disable NFC RF discovery";
+            return NFA_STATUS_TIMEOUT;
+        }
+    }
+
+    uint8_t cmd[] = {(NCI_MT_CMD << NCI_MT_SHIFT) | NCI_GID_PROP, NCI_MSG_PROP_ANDROID,
+                     NCI_ANDROID_PASSIVE_OBSERVE_PARAM_SIZE, NCI_ANDROID_PASSIVE_OBSERVE,
+                     static_cast<uint8_t>(enable ? NCI_ANDROID_PASSIVE_OBSERVE_PARAM_ENABLE
+                                                 : NCI_ANDROID_PASSIVE_OBSERVE_PARAM_DISABLE)};
+
+    status = NFA_SendRawVsCommand(sizeof(cmd), cmd, nfaVSCallback);
+
+    if (status == NFA_STATUS_OK) {
+        if (!sNfaVsCommand.wait(1000)) {
+            LOG(WARNING) << "Timeout waiting for NFA VS command response";
+            return NFA_STATUS_TIMEOUT;
+        }
+    }
+
+    return status;
+}
+
+class NfcBehaviorChanges : public testing::Test {
+  protected:
+    void SetUp() override {
+        tNFA_STATUS status = NFA_STATUS_OK;
+
+        sIsNfaEnabled = false;
+        sVSCmdStatus = NFA_STATUS_OK;
+
+        NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
+        theInstance.Initialize();  // start GKI, NCI task, NFC task
+
+        {
+            SyncEventGuard guard(sNfaEnableEvent);
+            tHAL_NFC_ENTRY* halFuncEntries = theInstance.GetHalEntryFuncs();
+
+            NFA_Init(halFuncEntries);
+
+            status = NFA_Enable(nfaDeviceManagementCallback, nfaConnectionCallback);
+            ASSERT_EQ(status, NFA_STATUS_OK);
+
+            // wait for NFA command to finish
+            ASSERT_TRUE(sNfaEnableEvent.wait(1000))
+                    << "Timeout waiting for NFA command on NFA_Enable";
+        }
+
+        ASSERT_TRUE(sIsNfaEnabled) << "Could not initialize NFC controller";
+
+        status = NFA_StartRfDiscovery();
+        ASSERT_EQ(status, NFA_STATUS_OK);
+        ASSERT_TRUE(sNfaEnableDisablePollingEvent.wait(1000)) << "Timeout starting RF discovery";
+    }
+};
+
+/*
+ * ObserveModeEnable:
+ * Attempts to enable observe mode. Does not test Observe Mode functionality,
+ * but simply verifies that the enable command responds successfully.
+ *
+ * @VsrTest = GMS-VSR-3.2.8-001
+ */
+TEST_F(NfcBehaviorChanges, ObserveModeEnableDisable) {
+    tNFA_STATUS status = nfaObserveModeEnable(true);
+    ASSERT_EQ(status, NFA_STATUS_OK);
+
+    status = nfaObserveModeEnable(false);
+    ASSERT_EQ(status, NFA_STATUS_OK);
+}
+
+int main(int argc, char** argv) {
+    testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
+    std::system("/system/bin/svc nfc disable"); /* Turn off NFC service */
+    sleep(5);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    std::system("/system/bin/svc nfc enable"); /* Turn on NFC service */
+    sleep(5);
+    return status;
+}
diff --git a/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl b/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
index 01f7327..451eaa9 100644
--- a/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
+++ b/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
@@ -62,7 +62,7 @@
     // IMS and SIP layer security (See 3GPP TS 33.203)
     // No IPsec config
     SIP_NO_IPSEC_CONFIG = 66,
-    IMS_NULL = 67,
+    IMS_NULL = 67, // Deprecated. Use SIP_NO_IPSEC_CONFIG and SIP_NULL instead.
 
     // Has IPsec config
     SIP_NULL = 68,
diff --git a/renderscript/1.0/Android.bp b/renderscript/1.0/Android.bp
index 1f2ac15..c699141 100644
--- a/renderscript/1.0/Android.bp
+++ b/renderscript/1.0/Android.bp
@@ -14,10 +14,6 @@
     root: "android.hardware",
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     srcs: [
         "types.hal",
         "IContext.hal",
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index 953630b..122a421 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -46,9 +46,74 @@
     ],
 }
 
+rust_binary {
+    name: "android.hardware.security.keymint-service.nonsecure",
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.security.keymint-service.rc"],
+    vintf_fragments: [
+        "android.hardware.security.keymint-service.xml",
+        "android.hardware.security.sharedsecret-service.xml",
+        "android.hardware.security.secureclock-service.xml",
+    ],
+    defaults: [
+        "keymint_use_latest_hal_aidl_rust",
+    ],
+    srcs: [
+        "main.rs",
+    ],
+    rustlibs: [
+        "libandroid_logger",
+        "libbinder_rs",
+        "liblog_rust",
+        "libkmr_hal",
+        "libkmr_hal_nonsecure",
+        "libkmr_ta_nonsecure",
+    ],
+    required: [
+        "android.hardware.hardware_keystore.xml",
+    ],
+}
+
 prebuilt_etc {
     name: "android.hardware.hardware_keystore.xml",
     sub_dir: "permissions",
     vendor: true,
     src: "android.hardware.hardware_keystore.xml",
 }
+
+rust_library {
+    name: "libkmr_hal_nonsecure",
+    crate_name: "kmr_hal_nonsecure",
+    vendor_available: true,
+    lints: "android",
+    rustlibs: [
+        "libbinder_rs",
+        "libhex",
+        "liblibc",
+        "liblog_rust",
+        "libkmr_hal",
+        "libkmr_wire",
+    ],
+    srcs: ["hal/lib.rs"],
+
+}
+
+rust_library {
+    name: "libkmr_ta_nonsecure",
+    crate_name: "kmr_ta_nonsecure",
+    vendor_available: true,
+    host_supported: true,
+    lints: "android",
+    rustlibs: [
+        "libhex",
+        "liblibc",
+        "liblog_rust",
+        "libkmr_common",
+        "libkmr_crypto_boring",
+        "libkmr_ta",
+        "libkmr_wire",
+    ],
+    srcs: ["ta/lib.rs"],
+
+}
diff --git a/security/keymint/aidl/default/hal/lib.rs b/security/keymint/aidl/default/hal/lib.rs
new file mode 100644
index 0000000..621f077
--- /dev/null
+++ b/security/keymint/aidl/default/hal/lib.rs
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+//! KeyMint helper functions that are only suitable for non-secure environments
+//! such as Cuttlefish.
+
+use kmr_hal::env::get_property;
+use log::error;
+
+/// Populate attestation ID information based on properties (where available).
+/// Retrieving the serial number requires SELinux permission.
+pub fn attestation_id_info() -> kmr_wire::AttestationIdInfo {
+    let prop = |name| {
+        get_property(name)
+            .unwrap_or_else(|_| format!("{} unavailable", name))
+            .as_bytes()
+            .to_vec()
+    };
+    kmr_wire::AttestationIdInfo {
+        brand: prop("ro.product.brand"),
+        device: prop("ro.product.device"),
+        product: prop("ro.product.name"),
+        serial: prop("ro.serialno"),
+        manufacturer: prop("ro.product.manufacturer"),
+        model: prop("ro.product.model"),
+        // Currently modem_simulator always returns one fixed value. See `handleGetIMEI` in
+        // device/google/cuttlefish/host/commands/modem_simulator/misc_service.cpp for more details.
+        // TODO(b/263188546): Use device-specific IMEI values when available.
+        imei: b"867400022047199".to_vec(),
+        imei2: b"867400022047199".to_vec(),
+        meid: vec![],
+    }
+}
+
+/// Get boot information based on system properties.
+pub fn get_boot_info() -> kmr_wire::SetBootInfoRequest {
+    // No access to a verified boot key.
+    let verified_boot_key = vec![0; 32];
+    let vbmeta_digest = get_property("ro.boot.vbmeta.digest").unwrap_or_else(|_| "00".repeat(32));
+    let verified_boot_hash = hex::decode(&vbmeta_digest).unwrap_or_else(|_e| {
+        error!("failed to parse hex data in '{}'", vbmeta_digest);
+        vec![0; 32]
+    });
+    let device_boot_locked = match get_property("ro.boot.vbmeta.device_state")
+        .unwrap_or_else(|_| "no-prop".to_string())
+        .as_str()
+    {
+        "locked" => true,
+        "unlocked" => false,
+        v => {
+            error!("Unknown device_state '{}', treating as unlocked", v);
+            false
+        }
+    };
+    let verified_boot_state = match get_property("ro.boot.verifiedbootstate")
+        .unwrap_or_else(|_| "no-prop".to_string())
+        .as_str()
+    {
+        "green" => 0,  // Verified
+        "yellow" => 1, // SelfSigned
+        "orange" => 2, // Unverified,
+        "red" => 3,    // Failed,
+        v => {
+            error!("Unknown boot state '{}', treating as Unverified", v);
+            2
+        }
+    };
+
+    // Attempt to get the boot patchlevel from a system property.  This requires an SELinux
+    // permission, so fall back to re-using the OS patchlevel if this can't be done.
+    let boot_patchlevel_prop = get_property("ro.vendor.boot_security_patch").unwrap_or_else(|e| {
+        error!("Failed to retrieve boot patchlevel: {:?}", e);
+        get_property(kmr_hal::env::OS_PATCHLEVEL_PROPERTY)
+            .unwrap_or_else(|_| "1970-09-19".to_string())
+    });
+    let boot_patchlevel =
+        kmr_hal::env::extract_patchlevel(&boot_patchlevel_prop).unwrap_or(19700919);
+
+    kmr_wire::SetBootInfoRequest {
+        verified_boot_key,
+        device_boot_locked,
+        verified_boot_state,
+        verified_boot_hash,
+        boot_patchlevel,
+    }
+}
diff --git a/security/keymint/aidl/default/main.rs b/security/keymint/aidl/default/main.rs
new file mode 100644
index 0000000..ea432d1
--- /dev/null
+++ b/security/keymint/aidl/default/main.rs
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+//! Default implementation of the KeyMint HAL and related HALs.
+//!
+//! This implementation of the HAL is only intended to allow testing and policy compliance.  A real
+//! implementation **must be implemented in a secure environment**.
+
+use kmr_hal::SerializedChannel;
+use kmr_hal_nonsecure::{attestation_id_info, get_boot_info};
+use log::{debug, error, info};
+use std::ops::DerefMut;
+use std::sync::{mpsc, Arc, Mutex};
+
+/// Name of KeyMint binder device instance.
+static SERVICE_INSTANCE: &str = "default";
+
+static KM_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
+static RPC_SERVICE_NAME: &str = "android.hardware.security.keymint.IRemotelyProvisionedComponent";
+static CLOCK_SERVICE_NAME: &str = "android.hardware.security.secureclock.ISecureClock";
+static SECRET_SERVICE_NAME: &str = "android.hardware.security.sharedsecret.ISharedSecret";
+
+/// Local error type for failures in the HAL service.
+#[derive(Debug, Clone)]
+struct HalServiceError(String);
+
+impl From<String> for HalServiceError {
+    fn from(s: String) -> Self {
+        Self(s)
+    }
+}
+
+fn main() {
+    if let Err(e) = inner_main() {
+        panic!("HAL service failed: {:?}", e);
+    }
+}
+
+fn inner_main() -> Result<(), HalServiceError> {
+    // Initialize Android logging.
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("keymint-hal-nonsecure")
+            .with_max_level(log::LevelFilter::Info)
+            .with_log_buffer(android_logger::LogId::System),
+    );
+    // Redirect panic messages to logcat.
+    std::panic::set_hook(Box::new(|panic_info| {
+        error!("{}", panic_info);
+    }));
+
+    info!("Insecure KeyMint HAL service is starting.");
+
+    info!("Starting thread pool now.");
+    binder::ProcessState::start_thread_pool();
+
+    // Create a TA in-process, which acts as a local channel for communication.
+    let channel = Arc::new(Mutex::new(LocalTa::new()));
+
+    let km_service = kmr_hal::keymint::Device::new_as_binder(channel.clone());
+    let service_name = format!("{}/{}", KM_SERVICE_NAME, SERVICE_INSTANCE);
+    binder::add_service(&service_name, km_service.as_binder()).map_err(|e| {
+        HalServiceError(format!(
+            "Failed to register service {} because of {:?}.",
+            service_name, e
+        ))
+    })?;
+
+    let rpc_service = kmr_hal::rpc::Device::new_as_binder(channel.clone());
+    let service_name = format!("{}/{}", RPC_SERVICE_NAME, SERVICE_INSTANCE);
+    binder::add_service(&service_name, rpc_service.as_binder()).map_err(|e| {
+        HalServiceError(format!(
+            "Failed to register service {} because of {:?}.",
+            service_name, e
+        ))
+    })?;
+
+    let clock_service = kmr_hal::secureclock::Device::new_as_binder(channel.clone());
+    let service_name = format!("{}/{}", CLOCK_SERVICE_NAME, SERVICE_INSTANCE);
+    binder::add_service(&service_name, clock_service.as_binder()).map_err(|e| {
+        HalServiceError(format!(
+            "Failed to register service {} because of {:?}.",
+            service_name, e
+        ))
+    })?;
+
+    let secret_service = kmr_hal::sharedsecret::Device::new_as_binder(channel.clone());
+    let service_name = format!("{}/{}", SECRET_SERVICE_NAME, SERVICE_INSTANCE);
+    binder::add_service(&service_name, secret_service.as_binder()).map_err(|e| {
+        HalServiceError(format!(
+            "Failed to register service {} because of {:?}.",
+            service_name, e
+        ))
+    })?;
+
+    info!("Successfully registered KeyMint HAL services.");
+
+    // Let the TA know information about the boot environment. In a real device this
+    // is communicated directly from the bootloader to the TA, but here we retrieve
+    // the information from system properties and send from the HAL service.
+    let boot_req = get_boot_info();
+    debug!("boot/HAL->TA: boot info is {:?}", boot_req);
+    kmr_hal::send_boot_info(channel.lock().unwrap().deref_mut(), boot_req)
+        .map_err(|e| HalServiceError(format!("Failed to send boot info: {:?}", e)))?;
+
+    // Let the TA know information about the userspace environment.
+    if let Err(e) = kmr_hal::send_hal_info(channel.lock().unwrap().deref_mut()) {
+        error!("Failed to send HAL info: {:?}", e);
+    }
+
+    // Let the TA know about attestation IDs. (In a real device these would be pre-provisioned into
+    // the TA.)
+    let attest_ids = attestation_id_info();
+    if let Err(e) = kmr_hal::send_attest_ids(channel.lock().unwrap().deref_mut(), attest_ids) {
+        error!("Failed to send attestation ID info: {:?}", e);
+    }
+
+    info!("Successfully registered KeyMint HAL services.");
+    binder::ProcessState::join_thread_pool();
+    info!("KeyMint HAL service is terminating."); // should not reach here
+    Ok(())
+}
+
+/// Implementation of the KeyMint TA that runs locally in-process (and which is therefore
+/// insecure).
+#[derive(Debug)]
+pub struct LocalTa {
+    in_tx: mpsc::Sender<Vec<u8>>,
+    out_rx: mpsc::Receiver<Vec<u8>>,
+}
+
+impl LocalTa {
+    /// Create a new instance.
+    pub fn new() -> Self {
+        // Create a pair of channels to communicate with the TA thread.
+        let (in_tx, in_rx) = mpsc::channel();
+        let (out_tx, out_rx) = mpsc::channel();
+
+        // The TA code expects to run single threaded, so spawn a thread to run it in.
+        std::thread::spawn(move || {
+            let mut ta = kmr_ta_nonsecure::build_ta();
+            loop {
+                let req_data: Vec<u8> = in_rx.recv().expect("failed to receive next req");
+                let rsp_data = ta.process(&req_data);
+                out_tx.send(rsp_data).expect("failed to send out rsp");
+            }
+        });
+        Self { in_tx, out_rx }
+    }
+}
+
+impl SerializedChannel for LocalTa {
+    const MAX_SIZE: usize = usize::MAX;
+
+    fn execute(&mut self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
+        self.in_tx
+            .send(req_data.to_vec())
+            .expect("failed to send in request");
+        Ok(self.out_rx.recv().expect("failed to receive response"))
+    }
+}
diff --git a/security/keymint/aidl/default/ta/attest.rs b/security/keymint/aidl/default/ta/attest.rs
new file mode 100644
index 0000000..1ce2066
--- /dev/null
+++ b/security/keymint/aidl/default/ta/attest.rs
@@ -0,0 +1,425 @@
+//
+// 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.
+
+//! Attestation keys and certificates.
+//!
+//! Hard-coded keys and certs copied from system/keymaster/context/soft_attestation_cert.cpp
+
+use kmr_common::{
+    crypto::ec, crypto::rsa, crypto::CurveType, crypto::KeyMaterial, wire::keymint,
+    wire::keymint::EcCurve, Error,
+};
+use kmr_ta::device::{RetrieveCertSigningInfo, SigningAlgorithm, SigningKeyType};
+
+/// RSA attestation private key in PKCS#1 format.
+///
+/// Decoded contents (using [der2ascii](https://github.com/google/der-ascii)):
+///
+/// ```
+/// SEQUENCE {
+///   INTEGER { 0 }
+///   INTEGER { `00c08323dc56881bb8302069f5b08561c6eebe7f05e2f5a842048abe8b47be76feaef25cf29b2afa3200141601429989a15fcfc6815eb363583c2fd2f20be4983283dd814b16d7e185417ae54abc296a3a6db5c004083b68c556c1f02339916419864d50b74d40aeca484c77356c895a0c275abfac499d5d7d2362f29c5e02e871` }
+///   INTEGER { 65537 }
+///   INTEGER { `00be860b0b99a802a6fb1a59438a7bb715065b09a36dc6e9cacc6bf3c02c34d7d79e94c6606428d88c7b7f6577c1cdea64074abe8e7286df1f0811dc9728260868de95d32efc96b6d084ff271a5f60defcc703e7a38e6e29ba9a3c5fc2c28076b6a896af1d34d78828ce9bddb1f34f9c9404430781298e201316725bbdbc993a41` }
+///   INTEGER { `00e1c6d927646c0916ec36826d594983740c21f1b074c4a1a59867c669795c85d3dc464c5b929e94bfb34e0dcc5014b10f13341ab7fdd5f60414d2a326cad41cc5` }
+///   INTEGER { `00da485997785cd5630fb0fd8c5254f98e538e18983aae9e6b7e6a5a7b5d343755b9218ebd40320d28387d789f76fa218bcc2d8b68a5f6418fbbeca5179ab3afbd` }
+///   INTEGER { `50fefc32649559616ed6534e154509329d93a3d810dbe5bdb982292cf78bd8badb8020ae8d57f4b71d05386ffe9e9db271ca3477a34999db76f8e5ece9c0d49d` }
+///   INTEGER { `15b74cf27cceff8bb36bf04d9d8346b09a2f70d2f4439b0f26ac7e03f7e9d1f77d4b915fd29b2823f03acb5d5200e0857ff2a803e93eee96d6235ce95442bc21` }
+///   INTEGER { `0090a745da8970b2cd649660324228c5f82856ffd665ba9a85c8d60f1b8bee717ecd2c72eae01dad86ba7654d4cf45adb5f1f2b31d9f8122cfa5f1a5570f9b2d25` }
+/// }
+/// ```
+const RSA_ATTEST_KEY: &str = concat!(
+    "3082025d02010002818100c08323dc56881bb8302069f5b08561c6eebe7f05e2",
+    "f5a842048abe8b47be76feaef25cf29b2afa3200141601429989a15fcfc6815e",
+    "b363583c2fd2f20be4983283dd814b16d7e185417ae54abc296a3a6db5c00408",
+    "3b68c556c1f02339916419864d50b74d40aeca484c77356c895a0c275abfac49",
+    "9d5d7d2362f29c5e02e871020301000102818100be860b0b99a802a6fb1a5943",
+    "8a7bb715065b09a36dc6e9cacc6bf3c02c34d7d79e94c6606428d88c7b7f6577",
+    "c1cdea64074abe8e7286df1f0811dc9728260868de95d32efc96b6d084ff271a",
+    "5f60defcc703e7a38e6e29ba9a3c5fc2c28076b6a896af1d34d78828ce9bddb1",
+    "f34f9c9404430781298e201316725bbdbc993a41024100e1c6d927646c0916ec",
+    "36826d594983740c21f1b074c4a1a59867c669795c85d3dc464c5b929e94bfb3",
+    "4e0dcc5014b10f13341ab7fdd5f60414d2a326cad41cc5024100da485997785c",
+    "d5630fb0fd8c5254f98e538e18983aae9e6b7e6a5a7b5d343755b9218ebd4032",
+    "0d28387d789f76fa218bcc2d8b68a5f6418fbbeca5179ab3afbd024050fefc32",
+    "649559616ed6534e154509329d93a3d810dbe5bdb982292cf78bd8badb8020ae",
+    "8d57f4b71d05386ffe9e9db271ca3477a34999db76f8e5ece9c0d49d024015b7",
+    "4cf27cceff8bb36bf04d9d8346b09a2f70d2f4439b0f26ac7e03f7e9d1f77d4b",
+    "915fd29b2823f03acb5d5200e0857ff2a803e93eee96d6235ce95442bc210241",
+    "0090a745da8970b2cd649660324228c5f82856ffd665ba9a85c8d60f1b8bee71",
+    "7ecd2c72eae01dad86ba7654d4cf45adb5f1f2b31d9f8122cfa5f1a5570f9b2d",
+    "25",
+);
+
+/// Attestation certificate corresponding to [`RSA_ATTEST_KEY`], signed by the key in
+/// [`RSA_ATTEST_ROOT_CERT`].
+///
+/// Decoded contents:
+///
+/// ```
+/// Certificate:
+///     Data:
+///         Version: 3 (0x2)
+///         Serial Number: 4096 (0x1000)
+///     Signature Algorithm: SHA256-RSA
+///         Issuer: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California
+///         Validity:
+///             Not Before: 2016-01-04 12:40:53 +0000 UTC
+///             Not After : 2035-12-30 12:40:53 +0000 UTC
+///         Subject: C=US, O=Google, Inc., OU=Android, ST=California, CN=Android Software Attestation Key
+///         Subject Public Key Info:
+///             Public Key Algorithm: rsaEncryption
+///                 Public Key: (1024 bit)
+///                 Modulus:
+///                     c0:83:23:dc:56:88:1b:b8:30:20:69:f5:b0:85:61:
+///                     c6:ee:be:7f:05:e2:f5:a8:42:04:8a:be:8b:47:be:
+///                     76:fe:ae:f2:5c:f2:9b:2a:fa:32:00:14:16:01:42:
+///                     99:89:a1:5f:cf:c6:81:5e:b3:63:58:3c:2f:d2:f2:
+///                     0b:e4:98:32:83:dd:81:4b:16:d7:e1:85:41:7a:e5:
+///                     4a:bc:29:6a:3a:6d:b5:c0:04:08:3b:68:c5:56:c1:
+///                     f0:23:39:91:64:19:86:4d:50:b7:4d:40:ae:ca:48:
+///                     4c:77:35:6c:89:5a:0c:27:5a:bf:ac:49:9d:5d:7d:
+///                     23:62:f2:9c:5e:02:e8:71:
+///                 Exponent: 65537 (0x10001)
+///         X509v3 extensions:
+///             X509v3 Authority Key Identifier:
+///                 keyid:29faf1accc4dd24c96402775b6b0e932e507fe2e
+///             X509v3 Subject Key Identifier:
+///                 keyid:d40c101bf8cd63b9f73952b50e135ca6d7999386
+///             X509v3 Key Usage: critical
+///                 Digital Signature, Certificate Signing
+///             X509v3 Basic Constraints: critical
+///                 CA:true, pathlen:0
+///     Signature Algorithm: SHA256-RSA
+///          9e:2d:48:5f:8c:67:33:dc:1a:85:ad:99:d7:50:23:ea:14:ec:
+///          43:b0:e1:9d:ea:c2:23:46:1e:72:b5:19:dc:60:22:e4:a5:68:
+///          31:6c:0b:55:c4:e6:9c:a2:2d:9f:3a:4f:93:6b:31:8b:16:78:
+///          16:0d:88:cb:d9:8b:cc:80:9d:84:f0:c2:27:e3:6b:38:f1:fd:
+///          d1:e7:17:72:31:59:35:7d:96:f3:c5:7f:ab:9d:8f:96:61:26:
+///          4f:b2:be:81:bb:0d:49:04:22:8a:ce:9f:f7:f5:42:2e:25:44:
+///          fa:21:07:12:5a:83:b5:55:ad:18:82:f8:40:14:9b:9c:20:63:
+///          04:7f:
+/// ```
+const RSA_ATTEST_CERT: &str = concat!(
+    "308202b63082021fa00302010202021000300d06092a864886f70d01010b0500",
+    "3063310b30090603550406130255533113301106035504080c0a43616c69666f",
+    "726e69613116301406035504070c0d4d6f756e7461696e205669657731153013",
+    "060355040a0c0c476f6f676c652c20496e632e3110300e060355040b0c07416e",
+    "64726f6964301e170d3136303130343132343035335a170d3335313233303132",
+    "343035335a3076310b30090603550406130255533113301106035504080c0a43",
+    "616c69666f726e696131153013060355040a0c0c476f6f676c652c20496e632e",
+    "3110300e060355040b0c07416e64726f69643129302706035504030c20416e64",
+    "726f696420536f667477617265204174746573746174696f6e204b657930819f",
+    "300d06092a864886f70d010101050003818d0030818902818100c08323dc5688",
+    "1bb8302069f5b08561c6eebe7f05e2f5a842048abe8b47be76feaef25cf29b2a",
+    "fa3200141601429989a15fcfc6815eb363583c2fd2f20be4983283dd814b16d7",
+    "e185417ae54abc296a3a6db5c004083b68c556c1f02339916419864d50b74d40",
+    "aeca484c77356c895a0c275abfac499d5d7d2362f29c5e02e8710203010001a3",
+    "663064301d0603551d0e04160414d40c101bf8cd63b9f73952b50e135ca6d799",
+    "9386301f0603551d2304183016801429faf1accc4dd24c96402775b6b0e932e5",
+    "07fe2e30120603551d130101ff040830060101ff020100300e0603551d0f0101",
+    "ff040403020284300d06092a864886f70d01010b0500038181009e2d485f8c67",
+    "33dc1a85ad99d75023ea14ec43b0e19deac223461e72b519dc6022e4a568316c",
+    "0b55c4e69ca22d9f3a4f936b318b1678160d88cbd98bcc809d84f0c227e36b38",
+    "f1fdd1e717723159357d96f3c57fab9d8f9661264fb2be81bb0d4904228ace9f",
+    "f7f5422e2544fa2107125a83b555ad1882f840149b9c2063047f",
+);
+
+/// Attestation self-signed root certificate holding the key that signed [`RSA_ATTEST_CERT`].
+///
+/// Decoded contents:
+///
+/// ```
+/// Certificate:
+///     Data:
+///         Version: 3 (0x2)
+///         Serial Number: 18416584322103887884 (0xff94d9dd9f07c80c)
+///     Signature Algorithm: SHA256-RSA
+///         Issuer: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California
+///         Validity:
+///             Not Before: 2016-01-04 12:31:08 +0000 UTC
+///             Not After : 2035-12-30 12:31:08 +0000 UTC
+///         Subject: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California
+///         Subject Public Key Info:
+///             Public Key Algorithm: rsaEncryption
+///                 Public Key: (1024 bit)
+///                 Modulus:
+///                     a2:6b:ad:eb:6e:2e:44:61:ef:d5:0e:82:e6:b7:94:
+///                     d1:75:23:1f:77:9b:63:91:63:ff:f7:aa:ff:0b:72:
+///                     47:4e:c0:2c:43:ec:33:7c:d7:ac:ed:40:3e:8c:28:
+///                     a0:66:d5:f7:87:0b:33:97:de:0e:b8:4e:13:40:ab:
+///                     af:a5:27:bf:95:69:a0:31:db:06:52:65:f8:44:59:
+///                     57:61:f0:bb:f2:17:4b:b7:41:80:64:c0:28:0e:8f:
+///                     52:77:8e:db:d2:47:b6:45:e9:19:c8:e9:8b:c3:db:
+///                     c2:91:3f:d7:d7:50:c4:1d:35:66:f9:57:e4:97:96:
+///                     0b:09:ac:ce:92:35:85:9b:
+///                 Exponent: 65537 (0x10001)
+///         X509v3 extensions:
+///             X509v3 Authority Key Identifier:
+///                 keyid:29faf1accc4dd24c96402775b6b0e932e507fe2e
+///             X509v3 Subject Key Identifier:
+///                 keyid:29faf1accc4dd24c96402775b6b0e932e507fe2e
+///             X509v3 Key Usage: critical
+///                 Digital Signature, Certificate Signing
+///             X509v3 Basic Constraints: critical
+///                 CA:true
+///     Signature Algorithm: SHA256-RSA
+///          4f:72:f3:36:59:8d:0e:c1:b9:74:5b:31:59:f6:f0:8d:25:49:
+///          30:9e:a3:1c:1c:29:d2:45:2d:20:b9:4d:5f:64:b4:e8:80:c7:
+///          78:7a:9c:39:de:a8:b3:f5:bf:2f:70:5f:47:10:5c:c5:e6:eb:
+///          4d:06:99:61:d2:ae:9a:07:ff:f7:7c:b8:ab:eb:9c:0f:24:07:
+///          5e:b1:7f:ba:79:71:fd:4d:5b:9e:df:14:a9:fe:df:ed:7c:c0:
+///          88:5d:f8:dd:9b:64:32:56:d5:35:9a:e2:13:f9:8f:ce:c1:7c:
+///          dc:ef:a4:aa:b2:55:c3:83:a9:2e:fb:5c:f6:62:f5:27:52:17:
+///          be:63:
+/// ```
+const RSA_ATTEST_ROOT_CERT: &str = concat!(
+    "308202a730820210a003020102020900ff94d9dd9f07c80c300d06092a864886",
+    "f70d01010b05003063310b30090603550406130255533113301106035504080c",
+    "0a43616c69666f726e69613116301406035504070c0d4d6f756e7461696e2056",
+    "69657731153013060355040a0c0c476f6f676c652c20496e632e3110300e0603",
+    "55040b0c07416e64726f6964301e170d3136303130343132333130385a170d33",
+    "35313233303132333130385a3063310b30090603550406130255533113301106",
+    "035504080c0a43616c69666f726e69613116301406035504070c0d4d6f756e74",
+    "61696e205669657731153013060355040a0c0c476f6f676c652c20496e632e31",
+    "10300e060355040b0c07416e64726f696430819f300d06092a864886f70d0101",
+    "01050003818d0030818902818100a26badeb6e2e4461efd50e82e6b794d17523",
+    "1f779b639163fff7aaff0b72474ec02c43ec337cd7aced403e8c28a066d5f787",
+    "0b3397de0eb84e1340abafa527bf9569a031db065265f844595761f0bbf2174b",
+    "b7418064c0280e8f52778edbd247b645e919c8e98bc3dbc2913fd7d750c41d35",
+    "66f957e497960b09acce9235859b0203010001a3633061301d0603551d0e0416",
+    "041429faf1accc4dd24c96402775b6b0e932e507fe2e301f0603551d23041830",
+    "16801429faf1accc4dd24c96402775b6b0e932e507fe2e300f0603551d130101",
+    "ff040530030101ff300e0603551d0f0101ff040403020284300d06092a864886",
+    "f70d01010b0500038181004f72f336598d0ec1b9745b3159f6f08d2549309ea3",
+    "1c1c29d2452d20b94d5f64b4e880c7787a9c39dea8b3f5bf2f705f47105cc5e6",
+    "eb4d069961d2ae9a07fff77cb8abeb9c0f24075eb17fba7971fd4d5b9edf14a9",
+    "fedfed7cc0885df8dd9b643256d5359ae213f98fcec17cdcefa4aab255c383a9",
+    "2efb5cf662f5275217be63",
+);
+
+/// EC attestation private key in `ECPrivateKey` format.
+///
+/// Decoded contents (using [der2ascii](https://github.com/google/der-ascii)):
+///
+/// ```
+/// SEQUENCE {
+///   INTEGER { 1 }
+///   OCTET_STRING { `21e086432a15198459cf363a50fc14c9daadf935f527c2dfd71e4d6dbc42e544` }
+///   [0] {
+///     # secp256r1
+///     OBJECT_IDENTIFIER { 1.2.840.10045.3.1.7 }
+///   }
+///   [1] {
+///     BIT_STRING { `00` `04eb9e79f8426359accb2a914c8986cc70ad90669382a9732613feaccbf821274c2174974a2afea5b94d7f66d4e065106635bc53b7a0a3a671583edb3e11ae1014` }
+///   }
+/// }
+/// ```
+const EC_ATTEST_KEY: &str = concat!(
+    "3077020101042021e086432a15198459cf363a50fc14c9daadf935f527c2dfd7",
+    "1e4d6dbc42e544a00a06082a8648ce3d030107a14403420004eb9e79f8426359",
+    "accb2a914c8986cc70ad90669382a9732613feaccbf821274c2174974a2afea5",
+    "b94d7f66d4e065106635bc53b7a0a3a671583edb3e11ae1014",
+);
+
+/// Attestation certificate corresponding to [`EC_ATTEST_KEY`], signed by the key in
+/// [`EC_ATTEST_ROOT_CERT`].
+///
+/// Decoded contents:
+///
+/// ```
+/// Certificate:
+///     Data:
+///         Version: 3 (0x2)
+///         Serial Number: 4097 (0x1001)
+///     Signature Algorithm: ECDSA-SHA256
+///         Issuer: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California, CN=Android Keystore Software Attestation Root
+///         Validity:
+///             Not Before: 2016-01-11 00:46:09 +0000 UTC
+///             Not After : 2026-01-08 00:46:09 +0000 UTC
+///         Subject: C=US, O=Google, Inc., OU=Android, ST=California, CN=Android Keystore Software Attestation Intermediate
+///         Subject Public Key Info:
+///             Public Key Algorithm: id-ecPublicKey
+///                 Public Key: (256 bit)
+///                 pub:
+///                     04:eb:9e:79:f8:42:63:59:ac:cb:2a:91:4c:89:86:
+///                     cc:70:ad:90:66:93:82:a9:73:26:13:fe:ac:cb:f8:
+///                     21:27:4c:21:74:97:4a:2a:fe:a5:b9:4d:7f:66:d4:
+///                     e0:65:10:66:35:bc:53:b7:a0:a3:a6:71:58:3e:db:
+///                     3e:11:ae:10:14:
+///                 ASN1 OID: prime256v1
+///         X509v3 extensions:
+///             X509v3 Authority Key Identifier:
+///                 keyid:c8ade9774c45c3a3cf0d1610e479433a215a30cf
+///             X509v3 Subject Key Identifier:
+///                 keyid:3ffcacd61ab13a9e8120b8d5251cc565bb1e91a9
+///             X509v3 Key Usage: critical
+///                 Digital Signature, Certificate Signing
+///             X509v3 Basic Constraints: critical
+///                 CA:true, pathlen:0
+///     Signature Algorithm: ECDSA-SHA256
+///          30:45:02:20:4b:8a:9b:7b:ee:82:bc:c0:33:87:ae:2f:c0:89:
+///          98:b4:dd:c3:8d:ab:27:2a:45:9f:69:0c:c7:c3:92:d4:0f:8e:
+///          02:21:00:ee:da:01:5d:b6:f4:32:e9:d4:84:3b:62:4c:94:04:
+///          ef:3a:7c:cc:bd:5e:fb:22:bb:e7:fe:b9:77:3f:59:3f:fb:
+/// ```
+const EC_ATTEST_CERT: &str = concat!(
+    "308202783082021ea00302010202021001300a06082a8648ce3d040302308198",
+    "310b30090603550406130255533113301106035504080c0a43616c69666f726e",
+    "69613116301406035504070c0d4d6f756e7461696e2056696577311530130603",
+    "55040a0c0c476f6f676c652c20496e632e3110300e060355040b0c07416e6472",
+    "6f69643133303106035504030c2a416e64726f6964204b657973746f72652053",
+    "6f667477617265204174746573746174696f6e20526f6f74301e170d31363031",
+    "31313030343630395a170d3236303130383030343630395a308188310b300906",
+    "03550406130255533113301106035504080c0a43616c69666f726e6961311530",
+    "13060355040a0c0c476f6f676c652c20496e632e3110300e060355040b0c0741",
+    "6e64726f6964313b303906035504030c32416e64726f6964204b657973746f72",
+    "6520536f667477617265204174746573746174696f6e20496e7465726d656469",
+    "6174653059301306072a8648ce3d020106082a8648ce3d03010703420004eb9e",
+    "79f8426359accb2a914c8986cc70ad90669382a9732613feaccbf821274c2174",
+    "974a2afea5b94d7f66d4e065106635bc53b7a0a3a671583edb3e11ae1014a366",
+    "3064301d0603551d0e041604143ffcacd61ab13a9e8120b8d5251cc565bb1e91",
+    "a9301f0603551d23041830168014c8ade9774c45c3a3cf0d1610e479433a215a",
+    "30cf30120603551d130101ff040830060101ff020100300e0603551d0f0101ff",
+    "040403020284300a06082a8648ce3d040302034800304502204b8a9b7bee82bc",
+    "c03387ae2fc08998b4ddc38dab272a459f690cc7c392d40f8e022100eeda015d",
+    "b6f432e9d4843b624c9404ef3a7cccbd5efb22bbe7feb9773f593ffb",
+);
+
+/// Attestation self-signed root certificate holding the key that signed [`EC_ATTEST_CERT`].
+///
+/// Decoded contents:
+///
+/// ```
+/// Certificate:
+///     Data:
+///         Version: 3 (0x2)
+///         Serial Number: 11674912229752527703 (0xa2059ed10e435b57)
+///     Signature Algorithm: ECDSA-SHA256
+///         Issuer: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California, CN=Android Keystore Software Attestation Root
+///         Validity:
+///             Not Before: 2016-01-11 00:43:50 +0000 UTC
+///             Not After : 2036-01-06 00:43:50 +0000 UTC
+///         Subject: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California, CN=Android Keystore Software Attestation Root
+///         Subject Public Key Info:
+///             Public Key Algorithm: id-ecPublicKey
+///                 Public Key: (256 bit)
+///                 pub:
+///                     04:ee:5d:5e:c7:e1:c0:db:6d:03:a6:7e:e6:b6:1b:
+///                     ec:4d:6a:5d:6a:68:2e:0f:ff:7f:49:0e:7d:77:1f:
+///                     44:22:6d:bd:b1:af:fa:16:cb:c7:ad:c5:77:d2:56:
+///                     9c:aa:b7:b0:2d:54:01:5d:3e:43:2b:2a:8e:d7:4e:
+///                     ec:48:75:41:a4:
+///                 ASN1 OID: prime256v1
+///         X509v3 extensions:
+///             X509v3 Authority Key Identifier:
+///                 keyid:c8ade9774c45c3a3cf0d1610e479433a215a30cf
+///             X509v3 Subject Key Identifier:
+///                 keyid:c8ade9774c45c3a3cf0d1610e479433a215a30cf
+///             X509v3 Key Usage: critical
+///                 Digital Signature, Certificate Signing
+///             X509v3 Basic Constraints: critical
+///                 CA:true
+///     Signature Algorithm: ECDSA-SHA256
+///          30:44:02:20:35:21:a3:ef:8b:34:46:1e:9c:d5:60:f3:1d:58:
+///          89:20:6a:dc:a3:65:41:f6:0d:9e:ce:8a:19:8c:66:48:60:7b:
+///          02:20:4d:0b:f3:51:d9:30:7c:7d:5b:da:35:34:1d:a8:47:1b:
+///          63:a5:85:65:3c:ad:4f:24:a7:e7:4d:af:41:7d:f1:bf:
+/// ```
+const EC_ATTEST_ROOT_CERT: &str = concat!(
+    "3082028b30820232a003020102020900a2059ed10e435b57300a06082a8648ce",
+    "3d040302308198310b30090603550406130255533113301106035504080c0a43",
+    "616c69666f726e69613116301406035504070c0d4d6f756e7461696e20566965",
+    "7731153013060355040a0c0c476f6f676c652c20496e632e3110300e06035504",
+    "0b0c07416e64726f69643133303106035504030c2a416e64726f6964204b6579",
+    "73746f726520536f667477617265204174746573746174696f6e20526f6f7430",
+    "1e170d3136303131313030343335305a170d3336303130363030343335305a30",
+    "8198310b30090603550406130255533113301106035504080c0a43616c69666f",
+    "726e69613116301406035504070c0d4d6f756e7461696e205669657731153013",
+    "060355040a0c0c476f6f676c652c20496e632e3110300e060355040b0c07416e",
+    "64726f69643133303106035504030c2a416e64726f6964204b657973746f7265",
+    "20536f667477617265204174746573746174696f6e20526f6f74305930130607",
+    "2a8648ce3d020106082a8648ce3d03010703420004ee5d5ec7e1c0db6d03a67e",
+    "e6b61bec4d6a5d6a682e0fff7f490e7d771f44226dbdb1affa16cbc7adc577d2",
+    "569caab7b02d54015d3e432b2a8ed74eec487541a4a3633061301d0603551d0e",
+    "04160414c8ade9774c45c3a3cf0d1610e479433a215a30cf301f0603551d2304",
+    "1830168014c8ade9774c45c3a3cf0d1610e479433a215a30cf300f0603551d13",
+    "0101ff040530030101ff300e0603551d0f0101ff040403020284300a06082a86",
+    "48ce3d040302034700304402203521a3ef8b34461e9cd560f31d5889206adca3",
+    "6541f60d9ece8a198c6648607b02204d0bf351d9307c7d5bda35341da8471b63",
+    "a585653cad4f24a7e74daf417df1bf",
+);
+
+/// Per-algorithm attestation certificate signing information.
+pub struct CertSignAlgoInfo {
+    key: KeyMaterial,
+    chain: Vec<keymint::Certificate>,
+}
+
+/// Certificate signing information for all asymmetric key types.
+pub struct CertSignInfo {
+    rsa_info: CertSignAlgoInfo,
+    ec_info: CertSignAlgoInfo,
+}
+
+impl CertSignInfo {
+    /// Create a new cert signing impl.
+    pub fn new() -> Self {
+        CertSignInfo {
+            rsa_info: CertSignAlgoInfo {
+                key: KeyMaterial::Rsa(rsa::Key(hex::decode(RSA_ATTEST_KEY).unwrap()).into()),
+                chain: vec![
+                    keymint::Certificate {
+                        encoded_certificate: hex::decode(RSA_ATTEST_CERT).unwrap(),
+                    },
+                    keymint::Certificate {
+                        encoded_certificate: hex::decode(RSA_ATTEST_ROOT_CERT).unwrap(),
+                    },
+                ],
+            },
+            ec_info: CertSignAlgoInfo {
+                key: KeyMaterial::Ec(
+                    EcCurve::P256,
+                    CurveType::Nist,
+                    ec::Key::P256(ec::NistKey(hex::decode(EC_ATTEST_KEY).unwrap())).into(),
+                ),
+                chain: vec![
+                    keymint::Certificate {
+                        encoded_certificate: hex::decode(EC_ATTEST_CERT).unwrap(),
+                    },
+                    keymint::Certificate {
+                        encoded_certificate: hex::decode(EC_ATTEST_ROOT_CERT).unwrap(),
+                    },
+                ],
+            },
+        }
+    }
+}
+
+impl RetrieveCertSigningInfo for CertSignInfo {
+    fn signing_key(&self, key_type: SigningKeyType) -> Result<KeyMaterial, Error> {
+        Ok(match key_type.algo_hint {
+            SigningAlgorithm::Rsa => self.rsa_info.key.clone(),
+            SigningAlgorithm::Ec => self.ec_info.key.clone(),
+        })
+    }
+
+    fn cert_chain(&self, key_type: SigningKeyType) -> Result<Vec<keymint::Certificate>, Error> {
+        Ok(match key_type.algo_hint {
+            SigningAlgorithm::Rsa => self.rsa_info.chain.clone(),
+            SigningAlgorithm::Ec => self.ec_info.chain.clone(),
+        })
+    }
+}
diff --git a/security/keymint/aidl/default/ta/clock.rs b/security/keymint/aidl/default/ta/clock.rs
new file mode 100644
index 0000000..ad8509a
--- /dev/null
+++ b/security/keymint/aidl/default/ta/clock.rs
@@ -0,0 +1,40 @@
+//
+// 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.
+
+//! Monotonic clock implementation.
+
+use kmr_common::crypto;
+use std::time::Instant;
+
+/// Monotonic clock.
+pub struct StdClock {
+    start: Instant,
+}
+
+impl StdClock {
+    /// Create new clock instance, holding time since construction.
+    pub fn new() -> Self {
+        Self {
+            start: Instant::now(),
+        }
+    }
+}
+
+impl crypto::MonotonicClock for StdClock {
+    fn now(&self) -> crypto::MillisecondsSinceEpoch {
+        let duration = self.start.elapsed();
+        crypto::MillisecondsSinceEpoch(duration.as_millis().try_into().unwrap())
+    }
+}
diff --git a/security/keymint/aidl/default/ta/lib.rs b/security/keymint/aidl/default/ta/lib.rs
new file mode 100644
index 0000000..fe8ad95
--- /dev/null
+++ b/security/keymint/aidl/default/ta/lib.rs
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+//! Local in-process implementation of the KeyMint TA. This is insecure and should
+//! only be used for testing purposes.
+
+// This crate is `std` using, but some of the code uses macros from a `no_std` world.
+extern crate alloc;
+
+use kmr_common::crypto;
+use kmr_crypto_boring::{
+    aes::BoringAes, aes_cmac::BoringAesCmac, des::BoringDes, ec::BoringEc, eq::BoringEq,
+    hmac::BoringHmac, rng::BoringRng, rsa::BoringRsa, sha256::BoringSha256,
+};
+use kmr_ta::device::{
+    BootloaderDone, CsrSigningAlgorithm, Implementation, TrustedPresenceUnsupported,
+};
+use kmr_ta::{HardwareInfo, KeyMintTa, RpcInfo, RpcInfoV3};
+use kmr_wire::keymint::SecurityLevel;
+use kmr_wire::rpc::MINIMUM_SUPPORTED_KEYS_IN_CSR;
+use log::info;
+
+pub mod attest;
+pub mod clock;
+pub mod rpc;
+pub mod soft;
+
+/// Build a set of crypto trait implementations based around BoringSSL and the standard library
+/// clock.
+pub fn boringssl_crypto_impls() -> crypto::Implementation {
+    let rng = BoringRng;
+    let clock = clock::StdClock::new();
+    let rsa = BoringRsa::default();
+    let ec = BoringEc::default();
+    crypto::Implementation {
+        rng: Box::new(rng),
+        clock: Some(Box::new(clock)),
+        compare: Box::new(BoringEq),
+        aes: Box::new(BoringAes),
+        des: Box::new(BoringDes),
+        hmac: Box::new(BoringHmac),
+        rsa: Box::new(rsa),
+        ec: Box::new(ec),
+        ckdf: Box::new(BoringAesCmac),
+        hkdf: Box::new(BoringHmac),
+        sha256: Box::new(BoringSha256),
+    }
+}
+
+/// Build a [`kmr_ta::KeyMintTa`] instance for nonsecure use.
+pub fn build_ta() -> kmr_ta::KeyMintTa {
+    info!("Building NON-SECURE KeyMint Rust TA");
+    let hw_info = HardwareInfo {
+        version_number: 1,
+        security_level: SecurityLevel::TrustedEnvironment,
+        impl_name: "Rust reference implementation",
+        author_name: "Google",
+        unique_id: "NON-SECURE KeyMint TA",
+    };
+    let rpc_sign_algo = CsrSigningAlgorithm::EdDSA;
+    let rpc_info_v3 = RpcInfoV3 {
+        author_name: "Google",
+        unique_id: "NON-SECURE KeyMint TA",
+        fused: false,
+        supported_num_of_keys_in_csr: MINIMUM_SUPPORTED_KEYS_IN_CSR,
+    };
+
+    let sign_info = attest::CertSignInfo::new();
+    let keys: Box<dyn kmr_ta::device::RetrieveKeyMaterial> = Box::new(soft::Keys);
+    let rpc: Box<dyn kmr_ta::device::RetrieveRpcArtifacts> = Box::new(soft::RpcArtifacts::new(
+        soft::Derive::default(),
+        rpc_sign_algo,
+    ));
+    let dev = Implementation {
+        keys,
+        sign_info: Box::new(sign_info),
+        // HAL populates attestation IDs from properties.
+        attest_ids: None,
+        sdd_mgr: None,
+        // `BOOTLOADER_ONLY` keys not supported.
+        bootloader: Box::new(BootloaderDone),
+        // `STORAGE_KEY` keys not supported.
+        sk_wrapper: None,
+        // `TRUSTED_USER_PRESENCE_REQUIRED` keys not supported
+        tup: Box::new(TrustedPresenceUnsupported),
+        // No support for converting previous implementation's keyblobs.
+        legacy_key: None,
+        rpc,
+    };
+    KeyMintTa::new(
+        hw_info,
+        RpcInfo::V3(rpc_info_v3),
+        boringssl_crypto_impls(),
+        dev,
+    )
+}
diff --git a/security/keymint/aidl/default/ta/rpc.rs b/security/keymint/aidl/default/ta/rpc.rs
new file mode 100644
index 0000000..39da50e
--- /dev/null
+++ b/security/keymint/aidl/default/ta/rpc.rs
@@ -0,0 +1,234 @@
+//
+// 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.
+
+//! Emulated implementation of device traits for `IRemotelyProvisionedComponent`.
+
+use core::cell::RefCell;
+use kmr_common::crypto::{ec, ec::CoseKeyPurpose, Ec, KeyMaterial};
+use kmr_common::{crypto, explicit, rpc_err, vec_try, Error};
+use kmr_crypto_boring::{ec::BoringEc, hmac::BoringHmac, rng::BoringRng};
+use kmr_ta::device::{
+    CsrSigningAlgorithm, DiceInfo, PubDiceArtifacts, RetrieveRpcArtifacts, RpcV2Req,
+};
+use kmr_wire::coset::{iana, CoseSign1Builder, HeaderBuilder};
+use kmr_wire::keymint::{Digest, EcCurve};
+use kmr_wire::{cbor::value::Value, coset::AsCborValue, rpc, CborError};
+
+/// Trait to encapsulate deterministic derivation of secret data.
+pub trait DeriveBytes {
+    /// Derive `output_len` bytes of data from `context`, deterministically.
+    fn derive_bytes(&self, context: &[u8], output_len: usize) -> Result<Vec<u8>, Error>;
+}
+
+/// Common emulated implementation of RPC artifact retrieval.
+pub struct Artifacts<T: DeriveBytes> {
+    derive: T,
+    sign_algo: CsrSigningAlgorithm,
+    // Invariant once populated: `self.dice_info.signing_algorithm` == `self.sign_algo`
+    dice_info: RefCell<Option<DiceInfo>>,
+    // Invariant once populated: `self.bcc_signing_key` is a variant that matches `self.sign_algo`
+    bcc_signing_key: RefCell<Option<ec::Key>>,
+}
+
+impl<T: DeriveBytes> RetrieveRpcArtifacts for Artifacts<T> {
+    fn derive_bytes_from_hbk(
+        &self,
+        _hkdf: &dyn crypto::Hkdf,
+        context: &[u8],
+        output_len: usize,
+    ) -> Result<Vec<u8>, Error> {
+        self.derive.derive_bytes(context, output_len)
+    }
+
+    fn get_dice_info(&self, _test_mode: rpc::TestMode) -> Result<DiceInfo, Error> {
+        if self.dice_info.borrow().is_none() {
+            let (dice_info, priv_key) = self.generate_dice_artifacts(rpc::TestMode(false))?;
+            *self.dice_info.borrow_mut() = Some(dice_info);
+            *self.bcc_signing_key.borrow_mut() = Some(priv_key);
+        }
+
+        Ok(self
+            .dice_info
+            .borrow()
+            .as_ref()
+            .ok_or_else(|| rpc_err!(Failed, "DICE artifacts are not initialized."))?
+            .clone())
+    }
+
+    fn sign_data(
+        &self,
+        ec: &dyn crypto::Ec,
+        data: &[u8],
+        _rpc_v2: Option<RpcV2Req>,
+    ) -> Result<Vec<u8>, Error> {
+        // DICE artifacts should have been initialized via `get_dice_info()` by the time this
+        // method is called.
+        let private_key = self
+            .bcc_signing_key
+            .borrow()
+            .as_ref()
+            .ok_or_else(|| rpc_err!(Failed, "DICE artifacts are not initialized."))?
+            .clone();
+
+        let mut op = ec.begin_sign(private_key.into(), self.signing_digest())?;
+        op.update(data)?;
+        let sig = op.finish()?;
+        crypto::ec::to_cose_signature(self.signing_curve(), sig)
+    }
+}
+
+impl<T: DeriveBytes> Artifacts<T> {
+    /// Constructor.
+    pub fn new(derive: T, sign_algo: CsrSigningAlgorithm) -> Self {
+        Self {
+            derive,
+            sign_algo,
+            dice_info: RefCell::new(None),
+            bcc_signing_key: RefCell::new(None),
+        }
+    }
+
+    /// Indicate the curve used in signing.
+    fn signing_curve(&self) -> EcCurve {
+        match self.sign_algo {
+            CsrSigningAlgorithm::ES256 => EcCurve::P256,
+            CsrSigningAlgorithm::ES384 => EcCurve::P384,
+            CsrSigningAlgorithm::EdDSA => EcCurve::Curve25519,
+        }
+    }
+
+    /// Indicate the digest used in signing.
+    fn signing_digest(&self) -> Digest {
+        match self.sign_algo {
+            CsrSigningAlgorithm::ES256 => Digest::Sha256,
+            CsrSigningAlgorithm::ES384 => Digest::Sha384,
+            CsrSigningAlgorithm::EdDSA => Digest::None,
+        }
+    }
+
+    /// Indicate the COSE algorithm value associated with signing.
+    fn signing_cose_algo(&self) -> iana::Algorithm {
+        match self.sign_algo {
+            CsrSigningAlgorithm::ES256 => iana::Algorithm::ES256,
+            CsrSigningAlgorithm::ES384 => iana::Algorithm::ES384,
+            CsrSigningAlgorithm::EdDSA => iana::Algorithm::EdDSA,
+        }
+    }
+
+    fn generate_dice_artifacts(
+        &self,
+        _test_mode: rpc::TestMode,
+    ) -> Result<(DiceInfo, ec::Key), Error> {
+        let ec = BoringEc::default();
+
+        let key_material = match self.sign_algo {
+            CsrSigningAlgorithm::EdDSA => {
+                let secret = self.derive_bytes_from_hbk(&BoringHmac, b"Device Key Seed", 32)?;
+                ec::import_raw_ed25519_key(&secret)
+            }
+            // TODO: generate the *same* key after reboot, by use of the TPM.
+            CsrSigningAlgorithm::ES256 => {
+                ec.generate_nist_key(&mut BoringRng, ec::NistCurve::P256, &[])
+            }
+            CsrSigningAlgorithm::ES384 => {
+                ec.generate_nist_key(&mut BoringRng, ec::NistCurve::P384, &[])
+            }
+        }?;
+        let (pub_cose_key, private_key) = match key_material {
+            KeyMaterial::Ec(curve, curve_type, key) => (
+                key.public_cose_key(
+                    &ec,
+                    curve,
+                    curve_type,
+                    CoseKeyPurpose::Sign,
+                    None, /* no key ID */
+                    rpc::TestMode(false),
+                )?,
+                key,
+            ),
+            _ => {
+                return Err(rpc_err!(
+                    Failed,
+                    "expected the Ec variant of KeyMaterial for the cdi leaf key."
+                ))
+            }
+        };
+
+        let cose_key_cbor = pub_cose_key.to_cbor_value().map_err(CborError::from)?;
+        let cose_key_cbor_data = kmr_ta::rkp::serialize_cbor(&cose_key_cbor)?;
+
+        // Construct `DiceChainEntryPayload`
+        let dice_chain_entry_payload = Value::Map(vec_try![
+            // Issuer
+            (
+                Value::Integer(1.into()),
+                Value::Text(String::from("Issuer"))
+            ),
+            // Subject
+            (
+                Value::Integer(2.into()),
+                Value::Text(String::from("Subject"))
+            ),
+            // Subject public key
+            (
+                Value::Integer((-4670552).into()),
+                Value::Bytes(cose_key_cbor_data)
+            ),
+            // Key Usage field contains a CBOR byte string of the bits which correspond
+            // to `keyCertSign` as per RFC 5280 Section 4.2.1.3 (in little-endian byte order)
+            (
+                Value::Integer((-4670553).into()),
+                Value::Bytes(vec_try![0x20]?)
+            ),
+        ]?);
+        let dice_chain_entry_payload_data = kmr_ta::rkp::serialize_cbor(&dice_chain_entry_payload)?;
+
+        // Construct `DiceChainEntry`
+        let protected = HeaderBuilder::new()
+            .algorithm(self.signing_cose_algo())
+            .build();
+        let dice_chain_entry = CoseSign1Builder::new()
+            .protected(protected)
+            .payload(dice_chain_entry_payload_data)
+            .try_create_signature(&[], |input| {
+                let mut op = ec.begin_sign(private_key.clone(), self.signing_digest())?;
+                op.update(input)?;
+                let sig = op.finish()?;
+                crypto::ec::to_cose_signature(self.signing_curve(), sig)
+            })?
+            .build();
+        let dice_chain_entry_cbor = dice_chain_entry.to_cbor_value().map_err(CborError::from)?;
+
+        // Construct `DiceCertChain`
+        let dice_cert_chain = Value::Array(vec_try![cose_key_cbor, dice_chain_entry_cbor]?);
+        let dice_cert_chain_data = kmr_ta::rkp::serialize_cbor(&dice_cert_chain)?;
+
+        // Construct `UdsCerts` as an empty CBOR map
+        let uds_certs_data = kmr_ta::rkp::serialize_cbor(&Value::Map(Vec::new()))?;
+
+        let pub_dice_artifacts = PubDiceArtifacts {
+            dice_cert_chain: dice_cert_chain_data,
+            uds_certs: uds_certs_data,
+        };
+
+        let dice_info = DiceInfo {
+            pub_dice_artifacts,
+            signing_algorithm: self.sign_algo,
+            rpc_v2_test_cdi_priv: None,
+        };
+
+        Ok((dice_info, explicit!(private_key)?))
+    }
+}
diff --git a/security/keymint/aidl/default/ta/soft.rs b/security/keymint/aidl/default/ta/soft.rs
new file mode 100644
index 0000000..5bbe060
--- /dev/null
+++ b/security/keymint/aidl/default/ta/soft.rs
@@ -0,0 +1,67 @@
+//
+// 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.
+
+//! Software-only trait implementations using fake keys.
+
+use kmr_common::{
+    crypto,
+    crypto::{Hkdf, Rng},
+    Error,
+};
+use kmr_crypto_boring::{hmac::BoringHmac, rng::BoringRng};
+use kmr_ta::device::RetrieveKeyMaterial;
+
+/// Root key retrieval using hard-coded fake keys.
+pub struct Keys;
+
+impl RetrieveKeyMaterial for Keys {
+    fn root_kek(&self, _context: &[u8]) -> Result<crypto::OpaqueOr<crypto::hmac::Key>, Error> {
+        // Matches `MASTER_KEY` in system/keymaster/key_blob_utils/software_keyblobs.cpp
+        Ok(crypto::hmac::Key::new([0; 16].to_vec()).into())
+    }
+    fn kak(&self) -> Result<crypto::OpaqueOr<crypto::aes::Key>, Error> {
+        // Matches `kFakeKeyAgreementKey` in
+        // system/keymaster/km_openssl/soft_keymaster_enforcement.cpp.
+        Ok(crypto::aes::Key::Aes256([0; 32]).into())
+    }
+    fn unique_id_hbk(&self, _ckdf: &dyn crypto::Ckdf) -> Result<crypto::hmac::Key, Error> {
+        // Matches value used in system/keymaster/contexts/pure_soft_keymaster_context.cpp.
+        crypto::hmac::Key::new_from(b"MustBeRandomBits")
+    }
+}
+
+/// Implementation of key derivation using a random fake key.
+pub struct Derive {
+    hbk: Vec<u8>,
+}
+
+impl Default for Derive {
+    fn default() -> Self {
+        // Use random data as an emulation of a hardware-backed key.
+        let mut hbk = vec![0; 32];
+        let mut rng = BoringRng;
+        rng.fill_bytes(&mut hbk);
+        Self { hbk }
+    }
+}
+
+impl crate::rpc::DeriveBytes for Derive {
+    fn derive_bytes(&self, context: &[u8], output_len: usize) -> Result<Vec<u8>, Error> {
+        BoringHmac.hkdf(&[], &self.hbk, context, output_len)
+    }
+}
+
+/// RPC artifact retrieval using software fake key.
+pub type RpcArtifacts = crate::rpc::Artifacts<Derive>;
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 087f763..c121d31 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -2024,7 +2024,7 @@
         }
     }
 
-    if (KeyMintAidlTestBase::dump_Attestations) std::cout << cert_data.str();
+    if (KeyMintAidlTestBase::dump_Attestations) std::cout << "cert chain:\n" << cert_data.str();
     return AssertionSuccess();
 }
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 9575183..3bcdd8f 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -5222,6 +5222,149 @@
                                        .Padding(PaddingMode::RSA_OAEP)));
 }
 
+auto wrapped_rsa_key = hex2str(
+        "308206230201000482010060f81b63ae53aa4be2e91b0b7cbdabd108125836139e5b991f3e3c9a98eca6cb7188"
+        "fba1c1232605747ed118975870c886e583a0ff766fc32b789a17029955caaff39a9c6c439be168e24b51046683"
+        "ce16110e0df115ccabbadcbe7ea9118b9589e4cccf240b6f0a506dfee57e19738c3cabb7dbf63b43e1b9ab058b"
+        "41b9480f2797210ef2bfbecb82526ac60ac006ebe0a053e825ad996d0ce8a98dc1ebf6ad889e491e03e9ddcc05"
+        "63f31921b55a54c61aa7f846d814dfe548f2c7939940bc6cf20489733203732df924b2b2a5aa9b54d31e7e42b9"
+        "e6cf107182edd33cb8e41db88167a79a264bbf883e69300ac82aac8de9dca0a13900150111efead81b74040c78"
+        "01d20b1547cfef40de45da30350201013030a1083106020102020103a203020101a30402020800a40531030201"
+        "01a5053103020104a6053103020103bf8377020500048204c126cd1642e83dea941151d872de12b8aaa835446e"
+        "94d2c1ea99c030225c5cad125dabe2341d9aba63e4df7fefc51e8e6f623ffae2aab9927113562b674b3cc2d7fc"
+        "fc34f199151a56ab114e792e6a21bd3b31fbf0d93050b9f90fb8e6cad3a067a4033848c4380184990f19a141d9"
+        "527177fdc13d802c33d222206c36404518285fe7e631aaeb6072c22c351c8c9db06e0b24e11aecef305f6abefb"
+        "4f31111534f7c55da8cf0d33882edbb43765304d1d45545c5207a858ea8d4369393bf1c54624df03da86c0ed47"
+        "b9ce1297149622069d51d2512f656ad0d421e6ff746ce8f79920df6a204c31732414a2f7eb24f8c2950348187a"
+        "4ba20b88a72355a4ec2b383be9f9b5b9ad564aa4c81de47dd95d77a8156ed0901d005a26f523b2a82c2d25d64d"
+        "f7660a6d3a720a6ba1eafe71da9fed0265d37a475193525620e705a543a928827accad93aba90556da859808be"
+        "dc2a8105af252e883892f41679d0600ddefb84415145bc28a2d9b0c60cea1ed3876486950ae0532cc1e953b0b5"
+        "81314c74250550741b24e4221ebb2804428caa2f08356a7de853ccfc5b18c2179147a883fa5763dd54f0d45388"
+        "c72f1bea19675d14014a725e125cdfac98d1701d9562be9d75362ea238b93244f46306cee4d77cbb8cbe7bf22d"
+        "fe677bbb103c00a204e49a0731660a2b23ee73ec7297a17822d4c4468e271029f8f1e8995f1a37cdc38324ead3"
+        "2474e6ee3ff671803d8a98a870324364d408c4d966d3cf0b9bbcbdbdff34a3e9666705362bc78beb96df4b8964"
+        "d141022250f62d1433cba5d1f510859eff688e46ce65dea00f5ebcfe7a79081ef1f0f5584dba14b79bc5a5f309"
+        "a1e48fe2bd9e94fcd9793d9b3632ccc51f18f7453e897e33b729abd2d34be324acbc22dfbf1d089aa93a178f79"
+        "23344140a468ac120b2f0055c284576b968e1d5148c6879b207b6cdb4eb513bccca619ae12ef156a9df03d6d8c"
+        "2c1c2ea7109dbcb61e5a74b36d0a7529f38b9ea742a956376da823251a6126693e2e1dab55b643c4e9783db835"
+        "f64d91069a2de1cda55539da52cadeeba2d3278da9005d89b4de4c5571600823f53d9cab1b55f65a560479d9ee"
+        "edeb361ab80ccedd0a067ddf5de639d115ffb3acf07fbba1cba6daa524b99db0b785273f7b6c15c4237ce1dce8"
+        "1b81622f35f116b638c75f0e0b26ba6bd9c5caee60c8b4f9198052b25e8c101638598946cb02c14db0a21b46c6"
+        "61ea123b2a2b5a51eb059715ce26940c977715a32e288b713013d66d0dae398d546abcd8c80966190b77732a7c"
+        "e2b8fc83e0cd83f69adef2b24b69fba19c546362087c08c8dab941a8573a084be3407d45a318c9a299f69d79f6"
+        "fae0859d6f08ee7708cf6041cccd815c3515f792aefc23a624e8e58bd9c6fe2f8f1ca6dcf04c6fdfa23eb3ff74"
+        "c5e5c7388f9faa32c86b6cd7438774e6cf06cb23a32cddb04c30f7d11e221db306c7937796e70a4dcfb7415c04"
+        "7823b965bedeaea196dc30fe648c52f3c1bcee62b19d4cccdb740ca35c3f3daad998c99dc117fffb7d150d500f"
+        "812b60ebec8b2067b13938250d078768e77f898fcdfc5f3554b6eda9df3b42bef38bb4d67cb63b7ede01e93b4d"
+        "c7768b52aa8ad8fb7fb288a529b84671f1ff9e44bb7c8f05d99806b65eb8e90b530fef3817f9fc4c921d0d46af"
+        "11aee8252407adc6c54589e9f6e6c1e25fc7510cfe499ea20465610410bf575efdbeb5af763920c3b4cdc8401"
+        "2");
+
+auto wrapped_ec_key = hex2str(
+        "308201dd020100048201000bb910602f88b1419ada400c8ab7602cf2fdbb4ef5e36881255fd5f85d49c4110c52"
+        "c75eab5e27a1732c1afa17bfe2cd393dea0a78a77ee08759e984411d1c7f0dbdcb6b77e05556694534be4434d8"
+        "596a7152aec71481522c85f0cc4635df2875d58dc29a78317b2aedd3586055e6e2227616f6a8ac4b9db5a2ad0e"
+        "10f5c4b43374bd6c9f57f79a103e64084414cfab3d3e0b7c2f26eb00a62105b7d1c7f41b7292fd6fce9395f39c"
+        "e0b6da0b5bf0d29d8952b958bd29b47c5ebd20d53ade370f463e35a166c04af71e3d5ce550019d3d20a5544896"
+        "65d169875d0e6a52348b7ec39b674f818e9b60dfa284d7ae4188471d05b9b2d9a5f750f5a00af999c568040c31"
+        "4144bde8ada6279d32e61530270201013022a1083106020102020103a203020103a30402020100a50531030201"
+        "04bf837702050004818a96e0f8be5a263616b506371d3c2ff3a3c2bcffc3ce067b242af66e30d5cd975b9546eb"
+        "32216d4f083f08fde246ab05fd7e930a0f05701067b44840c01a6722e1b2408be5b6acd0b39a0329cb2f357515"
+        "876433b193382c0b18aed9ed244dcbef5d61d98ca480f99a6cf2a00efda22eb8750db1725e30f64770ac6862ac"
+        "44cfd08a2c55812b512a0b92f704105c80b6a23cf339b2b10c677613510b1b");
+
+auto wrapping_key_for_asym_keys = hex2str(
+        "308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100a7f521fe024ebc"
+        "659db8e7a32b41dba27c5d446cb3d064d594b811d4856c3a583d155b0ff9300df3745738c32c4c4cd15adb6090"
+        "72ca870364bb7f3485784fde12e598b486c91950b9c45016bcb73c3842747c871be02dfc5f0e4b96d1ff5c8a09"
+        "7ae77b27e46dc60f1f574d1bb5e97487c1c3f9b493509e07318e1a0f0e9fdae401f4a62a5dd54daa09bf88ef42"
+        "9923f6f6f55d239908f227676d0f0b618238728dc4babd2a1f7d15fa9827346a1a160ab9427461533006fdf34d"
+        "4efec9aeefcea80b3a7d4ee4a4550055f0030700c5d20abcc32ce74d90ffabf83e02a759ce9074809936564f3d"
+        "3039af9c5e8a6afd9aa5459ab35c3eb851f10b3ae88ba91f0203010001028201001885515124451a7c3b6aa366"
+        "cf09ee66ea81335c2b6461544d42125854a258624988b4a2c05ea3aac77174780a1f9997770c502cc6958ae093"
+        "f44bbdff3e716a9a97aa93b099eb783da6cb8a8642ba27fc8bc522748f66275239640fc0d8e749bfd891b3093f"
+        "f046da2e593088bb263a3d17ace4e7d81a0cf83fe3df2a139882bff509523a3f886922200168ddd8fb7b4c9f26"
+        "62ff941c37937cebbbfeba24dd78d5ccd42025cb0276fa5661965f529274520bbb9faf36c501cafb48e5e47ae0"
+        "6980334fa36b6c62e2da733a8c7f01067de17e38d32d4a0721a6d184405bceaebb39ed3838633e6fbe43ac8b23"
+        "337bfe33cdf0b67ac3938ddccc37d775ad150102818100d538885135037730fad28e987d7562c1ef8ca58f95f7"
+        "ed81cb165ca63e15e810552eb9d487c9b9cde563fb29d1de22a60d54a856385719a4028cf386bcdc88e858d963"
+        "6d644cea25e0ee54ad1237983d9a06a66ea2f764eb540a4992ba2291ea96d20dfbd98bf5b313322cda4eb6710d"
+        "020139e085beb8e52a3e69bd05c71c7b02818100c9a7c89b11fcf8d99eb41995b5641472ef972e5aaa1f1446d7"
+        "ea57a9979e8e64f72ef1cde358649b71be7f21dc19dab52814f9a521d8620bd994a9bb621a8182a250066a0728"
+        "f0b16ab93a106ed79bc19cd519e83196157a8c6f82b5144a285b9384415394905fe18863b0988b27e77c969a81"
+        "c34a074e8fef5908fdf3c51ead02818019d5e8c6963ade45640f01523ed96b66fe64b766e7900c0a4f165d9193"
+        "324a55384d1a1d437ad0f5bed6d78720b3ded4ea069903217e844fd833460acc75986d36ded86a57ddedfd3afd"
+        "05eb96aa7fdaeeffe148c49c5f711854cac769a068b7d92088ab3c97f5e485eded7b62503ef0898ea679ab1b0a"
+        "0252950f70e4f35463028181008ff4c027bb8aad17a5cd0a2aaea83854e8a73347340525d38115e0e8c7bd4007"
+        "e1d1d87ad35e69cbf2423cbdae43a2b70a5b16f0849dd53882663758f6aad763ab7d97669f9fe15bb6456ea706"
+        "89d2be3fb87d5b1df2f77859c2cd3b79b58ae3fd0640206b813981667d4c3749b7fdf01a0f48ad622e9f2def7e"
+        "cf0583bd67ad0281805bd8f20cc82cb5e08dc2e7eea977d4180a5ef4c558e01255b8475feb9084475e20328c93"
+        "5a2247a775c941d64372d01abb27c95ee7d4336b6cbce190808b2f7a8d314d785336397dd6edc0c778f563d37e"
+        "0057b13695600b92fececc3edb067f69b374f9b9c343220a8b927deb6104768edc72b87751e0a3fb1585e679c9"
+        "8564");
+
+TEST_P(ImportWrappedKeyTest, RsaKey) {
+    int vsr_api_level = get_vsr_api_level();
+    if (vsr_api_level < __ANDROID_API_V__) {
+        /*
+         * The Keymaster v4 spec introduced `importWrappedKey()` and did not restrict it to
+         * just symmetric keys.  However, the import of asymmetric wrapped keys was not tested
+         * at the time, so we can only be strict about checking this for implementations claiming
+         * support for VSR API level 35 and above.
+         */
+        GTEST_SKIP() << "Applies only to VSR API level 35, this device is: " << vsr_api_level;
+    }
+
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                     .RsaEncryptionKey(2048, 65537)
+                                     .Digest(Digest::SHA_2_256)
+                                     .Padding(PaddingMode::RSA_OAEP)
+                                     .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY)
+                                     .SetDefaultValidity();
+
+    ASSERT_EQ(ErrorCode::OK, ImportWrappedKey(wrapped_rsa_key, wrapping_key_for_asym_keys,
+                                              wrapping_key_desc, zero_masking_key,
+                                              AuthorizationSetBuilder()
+                                                      .Digest(Digest::SHA_2_256)
+                                                      .Padding(PaddingMode::RSA_OAEP)));
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS);
+    string signature = SignMessage(message, params);
+    LocalVerifyMessage(message, signature, params);
+}
+
+TEST_P(ImportWrappedKeyTest, EcKey) {
+    int vsr_api_level = get_vsr_api_level();
+    if (vsr_api_level < __ANDROID_API_V__) {
+        /*
+         * The Keymaster v4 spec introduced `importWrappedKey()` and did not restrict it to
+         * just symmetric keys.  However, the import of asymmetric wrapped keys was not tested
+         * at the time, so we can only be strict about checking this for implementations claiming
+         * support for VSR API level 35 and above.
+         */
+        GTEST_SKIP() << "Applies only to VSR API level 35, this device is: " << vsr_api_level;
+    }
+
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                     .RsaEncryptionKey(2048, 65537)
+                                     .Digest(Digest::SHA_2_256)
+                                     .Padding(PaddingMode::RSA_OAEP)
+                                     .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY)
+                                     .SetDefaultValidity();
+
+    ASSERT_EQ(ErrorCode::OK, ImportWrappedKey(wrapped_ec_key, wrapping_key_for_asym_keys,
+                                              wrapping_key_desc, zero_masking_key,
+                                              AuthorizationSetBuilder()
+                                                      .Digest(Digest::SHA_2_256)
+                                                      .Padding(PaddingMode::RSA_OAEP)));
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    LocalVerifyMessage(message, signature, params);
+}
+
 INSTANTIATE_KEYMINT_AIDL_TEST(ImportWrappedKeyTest);
 
 typedef KeyMintAidlTestBase EncryptionOperationsTest;
diff --git a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
index f668536..98cf023 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
@@ -28,8 +28,9 @@
 parcelable DeviceInfo {
     /**
      * DeviceInfo is a CBOR Map structure described by the following CDDL. DeviceInfo must be
-     * canonicalized according to the specification in RFC 7049. The ordering presented here is
-     * non-canonical to group similar entries semantically.
+     * ordered according to the Length-First Map Key Ordering specified in RFC 8949,
+     * Section 4.2.3. Please note that the ordering presented here groups similar entries
+     * semantically, and not in the correct order per RFC 8949, Section 4.2.3.
      *
      * The DeviceInfo has changed across versions 1, 2, and 3 of the HAL. All versions of the
      * DeviceInfo CDDL are described in the DeviceInfoV*.cddl files. Please refer to the CDDL
diff --git a/soundtrigger/2.0/Android.bp b/soundtrigger/2.0/Android.bp
index 996105c..828b9ec 100644
--- a/soundtrigger/2.0/Android.bp
+++ b/soundtrigger/2.0/Android.bp
@@ -12,9 +12,6 @@
 hidl_interface {
     name: "android.hardware.soundtrigger@2.0",
     root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "types.hal",
         "ISoundTriggerHw.hal",
diff --git a/soundtrigger/2.0/default/Android.bp b/soundtrigger/2.0/default/Android.bp
index 8236e30..2cbf041 100644
--- a/soundtrigger/2.0/default/Android.bp
+++ b/soundtrigger/2.0/default/Android.bp
@@ -26,9 +26,6 @@
     name: "android.hardware.soundtrigger@2.0-core",
     defaults: ["hidl_defaults"],
     vendor_available: true,
-    vndk: {
-        enabled: true,
-    },
     srcs: [
         "SoundTriggerHalImpl.cpp",
     ],
diff --git a/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp b/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
index 8a3c6f0..4dbd339 100644
--- a/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
+++ b/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
@@ -35,8 +35,7 @@
 void HdmiCecMock::serviceDied(void* cookie) {
     ALOGE("HdmiCecMock died");
     auto hdmiCecMock = static_cast<HdmiCecMock*>(cookie);
-    hdmiCecMock->mCecThreadRun = false;
-    pthread_join(hdmiCecMock->mThreadId, NULL);
+    hdmiCecMock->closeCallback();
 }
 
 ScopedAStatus HdmiCecMock::addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) {
@@ -86,10 +85,10 @@
 }
 
 ScopedAStatus HdmiCecMock::setCallback(const std::shared_ptr<IHdmiCecCallback>& callback) {
-    // If callback is null, mCallback is also set to null so we do not call the old callback.
-    mCallback = callback;
+    closeCallback();
 
     if (callback != nullptr) {
+        mCallback = callback;
         mDeathRecipient =
                 ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
         AIBinder_linkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this /* cookie */);
@@ -104,8 +103,8 @@
 
 ScopedAStatus HdmiCecMock::setLanguage(const std::string& language) {
     if (language.size() != 3) {
-        LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size()
-                   << ".";
+        ALOGE("[halimp_aidl] Wrong language code: expected 3 letters, but it was %zu",
+              language.size());
         return ScopedAStatus::ok();
     }
     // TODO Validate if language is a valid language code
@@ -169,7 +168,7 @@
     // Open the output pipe for writing outgoing cec message
     mOutputFile = open(CEC_MSG_OUT_FIFO, O_WRONLY | O_CLOEXEC);
     if (mOutputFile < 0) {
-        ALOGD("[halimp_aidl] file open failed for writing");
+        ALOGE("[halimp_aidl] file open failed for writing");
         return -1;
     }
 
@@ -258,17 +257,24 @@
 }
 
 HdmiCecMock::HdmiCecMock() {
-    ALOGE("[halimp_aidl] Opening a virtual CEC HAL for testing and virtual machine.");
+    ALOGD("[halimp_aidl] Opening a virtual CEC HAL for testing and virtual machine.");
     mCallback = nullptr;
     mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
 }
 
+void HdmiCecMock::closeCallback() {
+    if (mCallback != nullptr) {
+        ALOGD("[halimp_aidl] HdmiCecMock close the current callback.");
+        mCallback = nullptr;
+        mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+        mCecThreadRun = false;
+        pthread_join(mThreadId, NULL);
+    }
+}
+
 HdmiCecMock::~HdmiCecMock() {
-    ALOGE("[halimp_aidl] HdmiCecMock shutting down.");
-    mCallback = nullptr;
-    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
-    mCecThreadRun = false;
-    pthread_join(mThreadId, NULL);
+    ALOGD("[halimp_aidl] HdmiCecMock shutting down.");
+    closeCallback();
 }
 
 }  // namespace implementation
diff --git a/tv/hdmi/cec/aidl/default/HdmiCecMock.h b/tv/hdmi/cec/aidl/default/HdmiCecMock.h
index e78b1cf..ef392bb 100644
--- a/tv/hdmi/cec/aidl/default/HdmiCecMock.h
+++ b/tv/hdmi/cec/aidl/default/HdmiCecMock.h
@@ -55,6 +55,7 @@
     ::ndk::ScopedAStatus enableCec(bool value) override;
     ::ndk::ScopedAStatus enableSystemCecControl(bool value) override;
     void printCecMsgBuf(const char* msg_buf, int len);
+    void closeCallback();
 
   private:
     static void* __threadLoop(void* data);
@@ -62,9 +63,8 @@
     int readMessageFromFifo(unsigned char* buf, int msgCount);
     int sendMessageToFifo(const CecMessage& message);
     void handleCecMessage(unsigned char* msgBuf, int length);
-
-  private:
     static void serviceDied(void* cookie);
+
     std::shared_ptr<IHdmiCecCallback> mCallback;
 
     // Variables for the virtual cec hal impl
diff --git a/uwb/aidl/default/src/uwb_chip.rs b/uwb/aidl/default/src/uwb_chip.rs
index d1c3c67..878aa64 100644
--- a/uwb/aidl/default/src/uwb_chip.rs
+++ b/uwb/aidl/default/src/uwb_chip.rs
@@ -180,6 +180,8 @@
             let mut reader = AsyncFd::new(reader).unwrap();
 
             loop {
+                const MESSAGE_TYPE_MASK: u8 = 0b11100000;
+                const DATA_MESSAGE_TYPE: u8 = 0b000;
                 const UWB_HEADER_SIZE: usize = 4;
                 let mut buffer = vec![0; UWB_HEADER_SIZE];
 
@@ -224,12 +226,22 @@
                 // Read the remaining header bytes, if truncated.
                 read_exact(reader.get_mut(), &mut buffer[read_len..]).unwrap();
 
-                let length = buffer[3] as usize + UWB_HEADER_SIZE;
+                let common_header = buffer[0];
+                let mt = (common_header & MESSAGE_TYPE_MASK) >> 5;
+                let payload_length = if mt == DATA_MESSAGE_TYPE {
+                    let payload_length_fields: [u8; 2] = buffer[2..=3].try_into().unwrap();
+                    u16::from_le_bytes(payload_length_fields) as usize
+                } else {
+                    buffer[3] as usize
+                };
+
+                let length = payload_length + UWB_HEADER_SIZE;
                 buffer.resize(length, 0);
 
                 // Read the payload bytes.
                 read_exact(reader.get_mut(), &mut buffer[UWB_HEADER_SIZE..]).unwrap();
 
+                log::debug!(" <-- {:?}", buffer);
                 client_callbacks.onUciMessage(&buffer).unwrap();
             }
         });
@@ -284,10 +296,13 @@
         log::debug!("sendUciMessage");
 
         if let State::Opened { ref mut serial, .. } = &mut *self.state.lock().await {
-            serial
-                .write(data)
-                .map(|written| written as i32)
-                .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into())
+            log::debug!(" --> {:?}", data);
+            let result = serial
+                .write_all(data)
+                .map(|_| data.len() as i32)
+                .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into());
+            log::debug!(" status: {:?}", result);
+            result
         } else {
             Err(binder::ExceptionCode::ILLEGAL_STATE.into())
         }
diff --git a/uwb/aidl/vts/VtsHalUwbTargetTest.cpp b/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
index 81d26ba..3b0b606 100644
--- a/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
+++ b/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
@@ -216,5 +216,12 @@
     ::testing::InitGoogleTest(&argc, argv);
     ProcessState::self()->setThreadPoolMaxThreadCount(1);
     ProcessState::self()->startThreadPool();
-    return RUN_ALL_TESTS();
+    // UWB HAL only allows 1 client, make sure framework
+    // does not have UWB HAL open before running
+    std::system("/system/bin/cmd uwb disable-uwb");
+    sleep(3);
+    auto status = RUN_ALL_TESTS();
+    sleep(3);
+    std::system("/system/bin/cmd uwb enable-uwb");
+    return status;
 }
diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp
index 55d6f59..cf86120 100644
--- a/wifi/aidl/default/wifi_legacy_hal.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -1867,9 +1867,8 @@
     return {capabs, status};
 }
 
-wifi_error WifiLegacyHal::twtSessionSetup(
-        const std::string& ifaceName, uint32_t cmdId, const wifi_twt_request& request,
-        const on_twt_failure& on_twt_failure_user_callback,
+wifi_error WifiLegacyHal::twtRegisterEvents(
+        const std::string& ifaceName, const on_twt_failure& on_twt_failure_user_callback,
         const on_twt_session_create& on_twt_session_create_user_callback,
         const on_twt_session_update& on_twt_session_update_user_callback,
         const on_twt_session_teardown& on_twt_session_teardown_user_callback,
@@ -1921,13 +1920,18 @@
         on_twt_session_resume_user_callback(id, session_id);
     };
 
-    return global_func_table_.wifi_twt_session_setup(
-            cmdId, getIfaceHandle(ifaceName), request,
+    return global_func_table_.wifi_twt_register_events(
+            getIfaceHandle(ifaceName),
             {onAsyncTwtError, onAsyncTwtSessionCreate, onAsyncTwtSessionUpdate,
              onAsyncTwtSessionTeardown, onAsyncTwtSessionStats, onAsyncTwtSessionSuspend,
              onAsyncTwtSessionResume});
 }
 
+wifi_error WifiLegacyHal::twtSessionSetup(const std::string& ifaceName, uint32_t cmdId,
+                                          const wifi_twt_request& request) {
+    return global_func_table_.wifi_twt_session_setup(cmdId, getIfaceHandle(ifaceName), request);
+}
+
 wifi_error WifiLegacyHal::twtSessionUpdate(const std::string& ifaceName, uint32_t cmdId,
                                            uint32_t sessionId, const wifi_twt_request& request) {
     return global_func_table_.wifi_twt_session_update(cmdId, getIfaceHandle(ifaceName), sessionId,
diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h
index 121d1b5..3fd567b 100644
--- a/wifi/aidl/default/wifi_legacy_hal.h
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -780,15 +780,16 @@
 
     // TWT functions
     std::pair<wifi_twt_capabilities, wifi_error> twtGetCapabilities(const std::string& ifaceName);
+    wifi_error twtRegisterEvents(
+            const std::string& ifaceName, const on_twt_failure& on_twt_failure_user_callback,
+            const on_twt_session_create& on_twt_session_create_user_callback,
+            const on_twt_session_update& on_twt_session_update_user_callback,
+            const on_twt_session_teardown& on_twt_session_teardown_user_callback,
+            const on_twt_session_stats& on_twt_session_stats_user_callback,
+            const on_twt_session_suspend& on_twt_session_suspend_user_callback,
+            const on_twt_session_resume& on_twt_session_resume_user_callback);
     wifi_error twtSessionSetup(const std::string& ifaceName, uint32_t cmdId,
-                               const wifi_twt_request& request,
-                               const on_twt_failure& on_twt_failure_user_callback,
-                               const on_twt_session_create& on_twt_session_create_user_callback,
-                               const on_twt_session_update& on_twt_session_update_user_callback,
-                               const on_twt_session_teardown& on_twt_session_teardown_user_callback,
-                               const on_twt_session_stats& on_twt_session_stats_user_callback,
-                               const on_twt_session_suspend& on_twt_session_suspend_user_callback,
-                               const on_twt_session_resume& on_twt_session_resume_user_callback);
+                               const wifi_twt_request& request);
     wifi_error twtSessionUpdate(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId,
                                 const wifi_twt_request& request);
     wifi_error twtSessionSuspend(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId);
@@ -797,7 +798,7 @@
     wifi_error twtSessionGetStats(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId);
 
     // Note: Following TWT functions are deprecated
-    // Deprecated
+    // Deprecated by twtRegisterEvegnts
     wifi_error twtRegisterHandler(const std::string& iface_name,
                                   const TwtCallbackHandlers& handler);
     // Deprecated by twtGetCapabilities
diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
index 73ea088..878abf0 100644
--- a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -182,6 +182,7 @@
     populateStubFor(&hal_fn->wifi_get_rtt_capabilities_v3);
     populateStubFor(&hal_fn->wifi_rtt_range_request_v3);
     populateStubFor(&hal_fn->wifi_twt_get_capabilities);
+    populateStubFor(&hal_fn->wifi_twt_register_events);
     populateStubFor(&hal_fn->wifi_twt_session_setup);
     populateStubFor(&hal_fn->wifi_twt_session_update);
     populateStubFor(&hal_fn->wifi_twt_session_suspend);
diff --git a/wifi/aidl/default/wifi_sta_iface.cpp b/wifi/aidl/default/wifi_sta_iface.cpp
index aee183d..85e373c 100644
--- a/wifi/aidl/default/wifi_sta_iface.cpp
+++ b/wifi/aidl/default/wifi_sta_iface.cpp
@@ -31,7 +31,11 @@
 WifiStaIface::WifiStaIface(const std::string& ifname,
                            const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
                            const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
-    : ifname_(ifname), legacy_hal_(legacy_hal), iface_util_(iface_util), is_valid_(true) {
+    : ifname_(ifname),
+      legacy_hal_(legacy_hal),
+      iface_util_(iface_util),
+      is_valid_(true),
+      is_twt_registered_(false) {
     // Turn on DFS channel usage for STA iface.
     legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setDfsFlag(ifname_, true);
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
@@ -266,11 +270,150 @@
     return {ifname_, ndk::ScopedAStatus::ok()};
 }
 
+ndk::ScopedAStatus WifiStaIface::registerTwtEventCallbackInternal() {
+    std::weak_ptr<WifiStaIface> weak_ptr_this = weak_ptr_this_;
+
+    // onTwtFailure callback
+    const auto& on_twt_failure = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                 legacy_hal::wifi_twt_error_code error_code) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        IWifiStaIfaceEventCallback::TwtErrorCode aidl_error_code =
+                aidl_struct_util::convertLegacyHalTwtErrorCodeToAidl(error_code);
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtFailure(id, aidl_error_code).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtFailure callback";
+            }
+        }
+    };
+    // onTwtSessionCreate callback
+    const auto& on_twt_session_create = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                        legacy_hal::wifi_twt_session twt_session) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        TwtSession aidl_twt_session;
+        if (!aidl_struct_util::convertLegacyHalTwtSessionToAidl(twt_session, &aidl_twt_session)) {
+            LOG(ERROR) << "convertLegacyHalTwtSessionToAidl failed";
+            return;
+        }
+
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtSessionCreate(id, aidl_twt_session).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtSessionCreate callback";
+            }
+        }
+    };
+    // onTwtSessionUpdate callback
+    const auto& on_twt_session_update = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                        legacy_hal::wifi_twt_session twt_session) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        TwtSession aidl_twt_session;
+        if (!aidl_struct_util::convertLegacyHalTwtSessionToAidl(twt_session, &aidl_twt_session)) {
+            LOG(ERROR) << "convertLegacyHalTwtSessionToAidl failed";
+            return;
+        }
+
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtSessionUpdate(id, aidl_twt_session).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtSessionUpdate callback";
+            }
+        }
+    };
+    // onTwtSessionTeardown callback
+    const auto& on_twt_session_teardown =
+            [weak_ptr_this](legacy_hal::wifi_request_id id, int session_id,
+                            legacy_hal::wifi_twt_teardown_reason_code reason_code) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                IWifiStaIfaceEventCallback::TwtTeardownReasonCode aidl_reason_code =
+                        aidl_struct_util::convertLegacyHalTwtReasonCodeToAidl(reason_code);
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->onTwtSessionTeardown(id, session_id, aidl_reason_code).isOk()) {
+                        LOG(ERROR) << "Failed to invoke onTwtSessionTeardown callback";
+                    }
+                }
+            };
+    // onTwtSessionStats callback
+    const auto& on_twt_session_stats = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                       int session_id,
+                                                       legacy_hal::wifi_twt_session_stats stats) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        TwtSessionStats aidl_session_stats;
+        if (!aidl_struct_util::convertLegacyHalTwtSessionStatsToAidl(stats, &aidl_session_stats)) {
+            LOG(ERROR) << "convertLegacyHalTwtSessionStatsToAidl failed";
+            return;
+        }
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtSessionStats(id, session_id, aidl_session_stats).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtSessionStats callback";
+            }
+        }
+    };
+    // onTwtSessionSuspend callback
+    const auto& on_twt_session_suspend = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                         int session_id) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtSessionSuspend(id, session_id).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtSessionSuspend callback";
+            }
+        }
+    };
+    // onTwtSessionResume callback
+    const auto& on_twt_session_resume = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                        int session_id) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtSessionResume(id, session_id).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtSessionResume callback";
+            }
+        }
+    };
+
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->twtRegisterEvents(
+            ifname_, on_twt_failure, on_twt_session_create, on_twt_session_update,
+            on_twt_session_teardown, on_twt_session_stats, on_twt_session_suspend,
+            on_twt_session_resume);
+
+    if (legacy_status == legacy_hal::WIFI_ERROR_NOT_SUPPORTED) {
+        LOG(INFO) << "twtRegisterEvents is not supported" << legacy_status;
+    } else if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "twtRegisterEvents failed - %d" << legacy_status;
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
 ndk::ScopedAStatus WifiStaIface::registerEventCallbackInternal(
         const std::shared_ptr<IWifiStaIfaceEventCallback>& callback) {
     if (!event_cb_handler_.addCallback(callback)) {
         return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
     }
+    is_twt_registered_ = registerTwtEventCallbackInternal().isOk();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -617,138 +760,16 @@
 
 ndk::ScopedAStatus WifiStaIface::twtSessionSetupInternal(int32_t cmdId,
                                                          const TwtRequest& aidlTwtRequest) {
+    if (!is_twt_registered_) {
+        LOG(INFO) << "twtSessionSetup is not supported as twtRegisterEvents failed";
+        return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+    }
     legacy_hal::wifi_twt_request legacyHalTwtRequest;
     if (!aidl_struct_util::convertAidlTwtRequestToLegacy(aidlTwtRequest, &legacyHalTwtRequest)) {
         return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
     }
-    std::weak_ptr<WifiStaIface> weak_ptr_this = weak_ptr_this_;
-
-    // onTwtFailure callback
-    const auto& on_twt_failure = [weak_ptr_this](legacy_hal::wifi_request_id id,
-                                                 legacy_hal::wifi_twt_error_code error_code) {
-        const auto shared_ptr_this = weak_ptr_this.lock();
-        IWifiStaIfaceEventCallback::TwtErrorCode aidl_error_code =
-                aidl_struct_util::convertLegacyHalTwtErrorCodeToAidl(error_code);
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-            if (!callback->onTwtFailure(id, aidl_error_code).isOk()) {
-                LOG(ERROR) << "Failed to invoke onTwtFailure callback";
-            }
-        }
-    };
-    // onTwtSessionCreate callback
-    const auto& on_twt_session_create = [weak_ptr_this](legacy_hal::wifi_request_id id,
-                                                        legacy_hal::wifi_twt_session twt_session) {
-        const auto shared_ptr_this = weak_ptr_this.lock();
-        TwtSession aidl_twt_session;
-        if (!aidl_struct_util::convertLegacyHalTwtSessionToAidl(twt_session, &aidl_twt_session)) {
-            LOG(ERROR) << "convertLegacyHalTwtSessionToAidl failed";
-            return;
-        }
-
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-            if (!callback->onTwtSessionCreate(id, aidl_twt_session).isOk()) {
-                LOG(ERROR) << "Failed to invoke onTwtSessionCreate callback";
-            }
-        }
-    };
-    // onTwtSessionUpdate callback
-    const auto& on_twt_session_update = [weak_ptr_this](legacy_hal::wifi_request_id id,
-                                                        legacy_hal::wifi_twt_session twt_session) {
-        const auto shared_ptr_this = weak_ptr_this.lock();
-        TwtSession aidl_twt_session;
-        if (!aidl_struct_util::convertLegacyHalTwtSessionToAidl(twt_session, &aidl_twt_session)) {
-            LOG(ERROR) << "convertLegacyHalTwtSessionToAidl failed";
-            return;
-        }
-
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-            if (!callback->onTwtSessionUpdate(id, aidl_twt_session).isOk()) {
-                LOG(ERROR) << "Failed to invoke onTwtSessionUpdate callback";
-            }
-        }
-    };
-    // onTwtSessionTeardown callback
-    const auto& on_twt_session_teardown =
-            [weak_ptr_this](legacy_hal::wifi_request_id id, int session_id,
-                            legacy_hal::wifi_twt_teardown_reason_code reason_code) {
-                const auto shared_ptr_this = weak_ptr_this.lock();
-                IWifiStaIfaceEventCallback::TwtTeardownReasonCode aidl_reason_code =
-                        aidl_struct_util::convertLegacyHalTwtReasonCodeToAidl(reason_code);
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->onTwtSessionTeardown(id, session_id, aidl_reason_code).isOk()) {
-                        LOG(ERROR) << "Failed to invoke onTwtSessionTeardown callback";
-                    }
-                }
-            };
-    // onTwtSessionStats callback
-    const auto& on_twt_session_stats = [weak_ptr_this](legacy_hal::wifi_request_id id,
-                                                       int session_id,
-                                                       legacy_hal::wifi_twt_session_stats stats) {
-        const auto shared_ptr_this = weak_ptr_this.lock();
-        TwtSessionStats aidl_session_stats;
-        if (!aidl_struct_util::convertLegacyHalTwtSessionStatsToAidl(stats, &aidl_session_stats)) {
-            LOG(ERROR) << "convertLegacyHalTwtSessionStatsToAidl failed";
-            return;
-        }
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-            if (!callback->onTwtSessionStats(id, session_id, aidl_session_stats).isOk()) {
-                LOG(ERROR) << "Failed to invoke onTwtSessionStats callback";
-            }
-        }
-    };
-    // onTwtSessionSuspend callback
-    const auto& on_twt_session_suspend = [weak_ptr_this](legacy_hal::wifi_request_id id,
-                                                         int session_id) {
-        const auto shared_ptr_this = weak_ptr_this.lock();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-            if (!callback->onTwtSessionSuspend(id, session_id).isOk()) {
-                LOG(ERROR) << "Failed to invoke onTwtSessionSuspend callback";
-            }
-        }
-    };
-    // onTwtSessionResume callback
-    const auto& on_twt_session_resume = [weak_ptr_this](legacy_hal::wifi_request_id id,
-                                                        int session_id) {
-        const auto shared_ptr_this = weak_ptr_this.lock();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-            if (!callback->onTwtSessionResume(id, session_id).isOk()) {
-                LOG(ERROR) << "Failed to invoke onTwtSessionResume callback";
-            }
-        }
-    };
-
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->twtSessionSetup(
-            ifname_, cmdId, legacyHalTwtRequest, on_twt_failure, on_twt_session_create,
-            on_twt_session_update, on_twt_session_teardown, on_twt_session_stats,
-            on_twt_session_suspend, on_twt_session_resume);
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionSetup(ifname_, cmdId, legacyHalTwtRequest);
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
diff --git a/wifi/aidl/default/wifi_sta_iface.h b/wifi/aidl/default/wifi_sta_iface.h
index eb8f745..5713928 100644
--- a/wifi/aidl/default/wifi_sta_iface.h
+++ b/wifi/aidl/default/wifi_sta_iface.h
@@ -103,6 +103,7 @@
   private:
     // Corresponding worker functions for the AIDL methods.
     std::pair<std::string, ndk::ScopedAStatus> getNameInternal();
+    ndk::ScopedAStatus registerTwtEventCallbackInternal();
     ndk::ScopedAStatus registerEventCallbackInternal(
             const std::shared_ptr<IWifiStaIfaceEventCallback>& callback);
     std::pair<int32_t, ndk::ScopedAStatus> getFeatureSetInternal();
@@ -157,6 +158,7 @@
     std::weak_ptr<WifiStaIface> weak_ptr_this_;
     bool is_valid_;
     aidl_callback_util::AidlCallbackHandler<IWifiStaIfaceEventCallback> event_cb_handler_;
+    bool is_twt_registered_;
 
     DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
 };