Merge "Added CROSS_TRAFFIC_MONITORING_WARNING_STATE to HAL" into main
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
index e14e9c0..07a85f8 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
@@ -74,6 +74,7 @@
   boolean supportsVariableLatency();
   int getAAudioMixerBurstCount();
   int getAAudioHardwareBurstMinUsec();
+  void prepareToDisconnectExternalDevice(int portId);
   const int DEFAULT_AAUDIO_MIXER_BURST_COUNT = 2;
   const int DEFAULT_AAUDIO_HARDWARE_BURST_MIN_DURATION_US = 1000;
   @VintfStability
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index e736c32..2d4d283 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -206,8 +206,10 @@
      * after successful connection of an external device.
      *
      * Handling of a disconnect is done in a reverse order:
-     *  1. Reset port configuration using the 'resetAudioPortConfig' method.
-     *  2. Release the connected device port by calling the 'disconnectExternalDevice'
+     *  1. Notify the HAL module to prepare for device disconnection using
+     *     'prepareToDisconnectExternalDevice' method.
+     *  2. Reset port configuration using the 'resetAudioPortConfig' method.
+     *  3. Release the connected device port by calling the 'disconnectExternalDevice'
      *     method. This also removes the audio routes associated with this
      *     device port.
      *
@@ -234,11 +236,15 @@
      * instance previously instantiated using the 'connectExternalDevice'
      * method.
      *
-     * The framework will call this method before closing streams and resetting
-     * patches. This call can be used by the HAL module to prepare itself to
-     * device disconnection. If the HAL module indicates an error after the first
-     * call, the framework will call this method once again after closing associated
-     * streams and patches.
+     * On AIDL HAL v1, the framework will call this method before closing streams
+     * and resetting patches. This call can be used by the HAL module to prepare
+     * itself to device disconnection. If the HAL module indicates an error after
+     * the first call, the framework will call this method once again after closing
+     * associated streams and patches.
+     *
+     * On AIDL HAL v2 and later, the framework will call 'prepareToDisconnectExternalDevice'
+     * method to notify the HAL module to prepare itself for device disconnection. The
+     * framework will only call this method after closing associated streams and patches.
      *
      * @throws EX_ILLEGAL_ARGUMENT In the following cases:
      *                             - If the port can not be found by the ID.
@@ -912,4 +918,20 @@
      * @throw EX_UNSUPPORTED_OPERATION If the module does not support aaudio MMAP.
      */
     int getAAudioHardwareBurstMinUsec();
+
+    /**
+     * Notify the HAL module to prepare for disconnecting an external device.
+     *
+     * This method is used to inform the HAL module that 'disconnectExternalDevice' will be
+     * called soon. The HAL module can rely on this method to abort active data operations
+     * early. The 'portId' must be of a connected device Port instance previously instantiated
+     * using 'connectExternalDevice' method. 'disconnectExternalDevice' method will be called
+     * soon after this method with the same 'portId'.
+     *
+     * @param portId The ID of the audio port that is about to disconnect
+     * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+     *                             - If the port can not be found by the ID.
+     *                             - If this is not a connected device port.
+     */
+    void prepareToDisconnectExternalDevice(int portId);
 }
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index d63e353..2a8e58f 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -321,9 +321,9 @@
 //
 // Mix ports:
 //  * "r_submix output", maximum 10 opened streams, maximum 10 active streams
-//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //  * "r_submix input", maximum 10 opened streams, maximum 10 active streams
-//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //
 // Routes:
 //  "r_submix output" -> "Remote Submix Out"
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 66c2169..d0e8745 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -762,6 +762,28 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::prepareToDisconnectExternalDevice(int32_t in_portId) {
+    auto& ports = getConfig().ports;
+    auto portIt = findById<AudioPort>(ports, in_portId);
+    if (portIt == ports.end()) {
+        LOG(ERROR) << __func__ << ": 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";
+        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";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    onPrepareToDisconnectExternalDevice(*portIt);
+
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Module::getAudioPatches(std::vector<AudioPatch>* _aidl_return) {
     *_aidl_return = getConfig().patches;
     LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " patches";
@@ -1541,6 +1563,11 @@
     LOG(DEBUG) << __func__ << ": do nothing and return";
 }
 
+void Module::onPrepareToDisconnectExternalDevice(
+        const ::aidl::android::media::audio::common::AudioPort& audioPort __unused) {
+    LOG(DEBUG) << __func__ << ": do nothing and return";
+}
+
 ndk::ScopedAStatus Module::onMasterMuteChanged(bool mute __unused) {
     LOG(VERBOSE) << __func__ << ": do nothing and return ok";
     return ndk::ScopedAStatus::ok();
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 00de797..6f0af21 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -96,8 +96,8 @@
             <libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
         </effectProxy>
         <effect name="extension_effect" library="extensioneffect" uuid="fa81dd00-588b-11ed-9b6a-0242ac120002" type="fa81de0e-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="acoustic_echo_canceler" library="aecsw" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
-        <effect name="noise_suppression" library="nssw" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
+        <effect name="acoustic_echo_canceler" library="pre_processing" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
+        <effect name="noise_suppression" library="pre_processing" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
     </effects>
 
     <preprocess>
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index caf43f1..572b597 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -70,6 +70,7 @@
             const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
             ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
     ndk::ScopedAStatus disconnectExternalDevice(int32_t in_portId) override;
+    ndk::ScopedAStatus prepareToDisconnectExternalDevice(int32_t in_portId) override;
     ndk::ScopedAStatus getAudioPatches(std::vector<AudioPatch>* _aidl_return) override;
     ndk::ScopedAStatus getAudioPort(
             int32_t in_portId,
@@ -195,6 +196,8 @@
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks);
     virtual void onExternalDeviceConnectionChanged(
             const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected);
+    virtual void onPrepareToDisconnectExternalDevice(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort);
     virtual ndk::ScopedAStatus onMasterMuteChanged(bool mute);
     virtual ndk::ScopedAStatus onMasterVolumeChanged(float volume);
     virtual std::vector<::aidl::android::media::audio::common::MicrophoneInfo> getMicrophoneInfos();
diff --git a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
index 3e8dd7c..2f42889 100644
--- a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
@@ -112,7 +112,7 @@
     static constexpr int32_t kMaxLatencyMs =
             (r_submix::kDefaultPipeSizeInFrames * 1000) / r_submix::kDefaultSampleRateHz;
     static constexpr int32_t kMinLatencyMs = kMaxLatencyMs / r_submix::kDefaultPipePeriodCount;
-    return (kMaxLatencyMs + kMinLatencyMs) / 2;
+    return kMinLatencyMs;
 }
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index 6258c93..d238aa4 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -73,10 +73,8 @@
         LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
         return ::android::NO_INIT;
     }
-    // If the sink has been shutdown or pipe recreation is forced, delete the pipe and
-    // recreate it.
-    if (sink->isShutdown()) {
-        LOG(DEBUG) << __func__ << ": Non-nullptr shut down sink when opening stream";
+    if ((!mIsInput || mCurrentRoute->isStreamInOpen()) && sink->isShutdown()) {
+        LOG(DEBUG) << __func__ << ": Shut down sink when opening stream";
         if (::android::OK != mCurrentRoute->resetPipe()) {
             LOG(ERROR) << __func__ << ": reset pipe failed";
             return ::android::NO_INIT;
diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp
index f04e607..235c9a3 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.cpp
+++ b/audio/aidl/default/r_submix/SubmixRoute.cpp
@@ -98,6 +98,9 @@
         }
         mStreamInStandby = true;
         mReadCounterFrames = 0;
+        if (mSink != nullptr) {
+            mSink->shutdown(false);
+        }
     } else {
         mStreamOutOpen = true;
     }
@@ -106,8 +109,7 @@
 void SubmixRoute::closeStream(bool isInput) {
     std::lock_guard guard(mLock);
     if (isInput) {
-        mInputRefCount--;
-        if (mInputRefCount == 0) {
+        if (--mInputRefCount == 0) {
             mStreamInOpen = false;
             if (mSink != nullptr) {
                 mSink->shutdown(true);
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
index e9f3251..515b8a2 100644
--- a/audio/aidl/vts/TestUtils.h
+++ b/audio/aidl/vts/TestUtils.h
@@ -69,6 +69,23 @@
                                          << "\n  but is has completed with: " << status;
 }
 
+inline ::testing::AssertionResult assertIsOkOrUnknownTransaction(
+        const char* expr, const ::ndk::ScopedAStatus& status) {
+    if (status.getStatus() == STATUS_UNKNOWN_TRANSACTION) {
+        return ::testing::AssertionSuccess();
+    }
+    return assertIsOk(expr, status);
+}
+
+inline ::testing::AssertionResult assertResultOrUnknownTransaction(
+        const char* exp_expr, const char* act_expr, int32_t expected,
+        const ::ndk::ScopedAStatus& status) {
+    if (status.getStatus() == STATUS_UNKNOWN_TRANSACTION) {
+        return ::testing::AssertionSuccess();
+    }
+    return assertResult(exp_expr, act_expr, expected, status);
+}
+
 }  // namespace detail
 
 }  // namespace android::hardware::audio::common::testing
@@ -93,3 +110,15 @@
             GTEST_SKIP() << "Skip data path for offload";                                        \
         }                                                                                        \
     })
+
+// Test that the transaction status 'isOk' if it is a known transaction
+#define EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(ret)                                                 \
+    EXPECT_PRED_FORMAT1(                                                                         \
+            ::android::hardware::audio::common::testing::detail::assertIsOkOrUnknownTransaction, \
+            ret)
+
+// Test that the transaction status is as expected if it is a known transaction
+#define EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(expected, ret)                                        \
+    EXPECT_PRED_FORMAT2(                                                                           \
+            ::android::hardware::audio::common::testing::detail::assertResultOrUnknownTransaction, \
+            expected, ret)
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 697aae9..f91795b 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -573,6 +573,8 @@
     WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
     ~WithDevicePortConnectedState() {
         if (mModule != nullptr) {
+            EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(mModule->prepareToDisconnectExternalDevice(getId()))
+                    << "when preparing to disconnect device port ID " << getId();
             EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
                     << "when disconnecting device port ID " << getId();
         }
@@ -1753,6 +1755,9 @@
         ScopedAStatus status = module->connectExternalDevice(portWithData, &connectedPort);
         EXPECT_STATUS(EX_ILLEGAL_STATE, status) << "static port " << portWithData.toString();
         if (status.isOk()) {
+            EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(
+                    module->prepareToDisconnectExternalDevice(connectedPort.id))
+                    << "when preparing to disconnect device port ID " << connectedPort.id;
             EXPECT_IS_OK(module->disconnectExternalDevice(connectedPort.id))
                     << "when disconnecting device port ID " << connectedPort.id;
         }
@@ -1782,6 +1787,9 @@
         invalidPort.id = portId;
         EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
                 << "port ID " << portId << ", when setting CONNECTED state";
+        EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
+                                             module->prepareToDisconnectExternalDevice(portId))
+                << "port ID " << portId << ", when preparing to disconnect";
         EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
                 << "port ID " << portId << ", when setting DISCONNECTED state";
     }
@@ -1792,6 +1800,9 @@
         if (port.ext.getTag() != AudioPortExt::Tag::device) {
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
                     << "non-device port ID " << port.id << " when setting CONNECTED state";
+            EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
+                                                 module->prepareToDisconnectExternalDevice(port.id))
+                    << "non-device port ID " << port.id << " when preparing to disconnect";
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
                     << "non-device port ID " << port.id << " when setting DISCONNECTED state";
         } else {
@@ -1800,6 +1811,10 @@
                 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
                         << "for a permanently attached device port ID " << port.id
                         << " when setting CONNECTED state";
+                EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(
+                        EX_ILLEGAL_ARGUMENT, module->prepareToDisconnectExternalDevice(port.id))
+                        << "for a permanently attached device port ID " << port.id
+                        << " when preparing to disconnect";
                 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
                         << "for a permanently attached device port ID " << port.id
                         << " when setting DISCONNECTED state";
@@ -1817,6 +1832,9 @@
         GTEST_SKIP() << "No external devices in the module.";
     }
     for (const auto& port : ports) {
+        EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
+                                             module->prepareToDisconnectExternalDevice(port.id))
+                << "when preparing to disconnect already disconnected device port ID " << port.id;
         EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
                 << "when disconnecting already disconnected device port ID " << port.id;
         AudioPort portWithData = GenerateUniqueDeviceAddress(port);
@@ -1851,6 +1869,10 @@
             // Our test assumes that 'getAudioPort' returns at least one profile, and it
             // is not a dynamic profile.
             ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
+            EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(
+                    module->prepareToDisconnectExternalDevice(portConnected.getId()))
+                    << "when preparing to disconnect device port ID " << port.id
+                    << " with active configuration " << config.getId();
             EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
                     << "when trying to disconnect device port ID " << port.id
                     << " with active configuration " << config.getId();
diff --git a/automotive/vehicle/OWNERS b/automotive/vehicle/OWNERS
index d6969e5..9a6b65d 100644
--- a/automotive/vehicle/OWNERS
+++ b/automotive/vehicle/OWNERS
@@ -1,2 +1,9 @@
 ericjeong@google.com
 shanyu@google.com
+
+# GRPC VHAL
+per-file aidl/impl/grpc/** = chenhaosjtuacm@google.com, egranata@google.com
+
+# Property definition
+per-file aidl_property/** = tylertrephan@google.com
+per-file aidl/generated_lib/** = tylertrephan@google.com
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 3d026b4..665c10e 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -2447,9 +2447,9 @@
                 160,
                 280,
                 5,
-                600,
-                840,
-                10
+                608,
+                824,
+                9
             ]
         },
         {
@@ -2459,7 +2459,7 @@
                     66.19999694824219,
                     "VehicleUnit::FAHRENHEIT",
                     19.0,
-                    66.0
+                    66.2
                 ]
             }
         },
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index dc1e1e4..dced624 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -489,7 +489,7 @@
                                                   int increment) {
     requestedTemp = std::max(requestedTemp, minTemp);
     requestedTemp = std::min(requestedTemp, maxTemp);
-    int numIncrements = (requestedTemp - minTemp) / increment;
+    int numIncrements = std::round((requestedTemp - minTemp) / static_cast<float>(increment));
     return numIncrements;
 }
 
diff --git a/automotive/vehicle/aidl/impl/grpc/OWNERS b/automotive/vehicle/aidl/impl/grpc/OWNERS
deleted file mode 100644
index 7a96f23..0000000
--- a/automotive/vehicle/aidl/impl/grpc/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-shanyu@google.com
-chenhaosjtuacm@google.com
-egranata@google.com
diff --git a/automotive/vehicle/aidl_property/OWNERS b/automotive/vehicle/aidl_property/OWNERS
deleted file mode 100644
index 73e45ca..0000000
--- a/automotive/vehicle/aidl_property/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tylertrephan@google.com
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
index 3fde1c7..8b345b2 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
@@ -40,4 +40,5 @@
   SLEEP_IMMEDIATELY = 4,
   HIBERNATE_IMMEDIATELY = 5,
   CAN_HIBERNATE = 6,
+  EMERGENCY_SHUTDOWN = 7,
 }
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleArea.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleArea.aidl
index db867f4..b63003a 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleArea.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleArea.aidl
@@ -40,5 +40,6 @@
   SEAT = 0x05000000,
   DOOR = 0x06000000,
   WHEEL = 0x07000000,
+  VENDOR = 0x08000000,
   MASK = 0x0f000000,
 }
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
index a863d14..923d42a 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
@@ -45,4 +45,8 @@
      * AP can enter hibernation (suspend to disk) instead of shutting down completely.
      */
     CAN_HIBERNATE = 6,
+    /**
+     * AP must shutdown (gracefully) without a delay.
+     */
+    EMERGENCY_SHUTDOWN = 7,
 }
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleArea.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleArea.aidl
index 6f7f783..259b231 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleArea.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleArea.aidl
@@ -49,6 +49,11 @@
     DOOR = 0x06000000,
     /** WHEEL maps to enum VehicleAreaWheel */
     WHEEL = 0x07000000,
+    /**
+     * A property with the VENDOR vehicle area contains area IDs that are vendor defined. Each area
+     * ID within this area type must be unique with no overlapping bits set.
+     */
+    VENDOR = 0x08000000,
 
     MASK = 0x0f000000,
 }
diff --git a/automotive/vehicle/vts/OWNERS b/automotive/vehicle/vts/OWNERS
index c93a843..0f88eec 100644
--- a/automotive/vehicle/vts/OWNERS
+++ b/automotive/vehicle/vts/OWNERS
@@ -1,3 +1,3 @@
 # Bug component: 533426
 shanyu@google.com
-kwangsudo@google.com
+tylertrephan@google.com
diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
index 79d3e60..2668a97 100644
--- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
+++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
@@ -750,7 +750,7 @@
     ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
     LOG(DEBUG) << "Current program info: " << infoCb.toString();
     // it should tune exactly to what was requested
-    EXPECT_EQ(infoCb.selector, hdSel);
+    EXPECT_EQ(infoCb.selector.primaryId, hdSel.primaryId);
     EXPECT_EQ(infoCb.physicallyTunedTo, physicallyTunedToExpected);
 }
 
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl
index e573556..c99169e 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl
@@ -45,4 +45,5 @@
   byte chreApiMinorVersion;
   char chrePatchVersion;
   String[] supportedPermissions;
+  boolean supportsReliableMessages;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl
index e38c251..a6951a8 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl
@@ -39,4 +39,6 @@
   int messageType;
   byte[] messageBody;
   String[] permissions;
+  boolean isReliable;
+  int messageSequenceNumber;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ErrorCode.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ErrorCode.aidl
new file mode 100644
index 0000000..8924658
--- /dev/null
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ErrorCode.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.contexthub;
+@Backing(type="byte") @VintfStability
+enum ErrorCode {
+  OK = 0,
+  TRANSIENT_ERROR,
+  PERMANENT_ERROR,
+  PERMISSION_DENIED,
+  DESTINATION_NOT_FOUND,
+}
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index de8d752..7341e0e 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -48,5 +48,6 @@
   long[] getPreloadedNanoappIds(in int contextHubId);
   void onNanSessionStateChanged(in android.hardware.contexthub.NanSessionStateUpdate update);
   void setTestMode(in boolean enable);
+  void sendMessageDeliveryStatusToHub(in int contextHubId, in android.hardware.contexthub.MessageDeliveryStatus messageDeliveryStatus);
   const int EX_CONTEXT_HUB_UNSPECIFIED = (-1) /* -1 */;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
index 4e99082..70f69c6 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
@@ -39,6 +39,7 @@
   void handleContextHubAsyncEvent(in android.hardware.contexthub.AsyncEventType evt);
   void handleTransactionResult(in int transactionId, in boolean success);
   void handleNanSessionRequest(in android.hardware.contexthub.NanSessionRequest request);
+  void handleMessageDeliveryStatus(in char hostEndpointId, in android.hardware.contexthub.MessageDeliveryStatus messageDeliveryStatus);
   byte[16] getUuid();
   String getName();
   const int CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS = 10000;
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/MessageDeliveryStatus.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/MessageDeliveryStatus.aidl
new file mode 100644
index 0000000..40dac13
--- /dev/null
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/MessageDeliveryStatus.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.contexthub;
+@VintfStability
+parcelable MessageDeliveryStatus {
+  int messageSequenceNumber;
+  android.hardware.contexthub.ErrorCode errorCode;
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl b/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl
index c0fa702..42dba10 100644
--- a/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl
@@ -33,7 +33,9 @@
     /** Peak MIPs this platform can deliver */
     float peakMips;
 
-    /** The maximum length in bytes of the message that can be sent to the Context Hub. */
+    /**
+     * The maximum length in bytes of a message sent to the Context Hub.
+     */
     int maxSupportedMessageLengthBytes;
 
     /**
@@ -61,4 +63,11 @@
      * are granted in order to communicate with them.
      */
     String[] supportedPermissions;
+
+    /**
+     * True if the Context Hub supports reliable messages. False otherwise, in which case
+     * ContextHubMessage.isReliable must always be set to false. See
+     * ContextHubMessage.isReliable for more information.
+     */
+    boolean supportsReliableMessages;
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl b/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl
index 95d478e..3cd20ca 100644
--- a/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl
@@ -50,4 +50,35 @@
      * of the permissions that the sending nanoapp is using.
      */
     String[] permissions;
+
+    /**
+     * Whether the message is reliable.
+     *
+     * For reliable messages, the receiver is expected to acknowledge the reception of
+     * the message by sending a message delivery status back to the sender. Acknowledgment of
+     * the message must be returned within 1 second.
+     *
+     * For reliable messages sent by the host, the Context Hub invokes
+     * IContextHubCallback#handleMessageDeliveryStatus to report the status.
+     *
+     * For reliable messages sent by the Context Hub, the host calls
+     * IContextHub#sendMessageDeliveryStatusToHub to report the status.
+     */
+    boolean isReliable;
+
+    /**
+     * The sequence number for a reliable message. For less than 2^32 messages, each message sent
+     * from a Context Hub will have a unique sequence number generated by the Context Hub, and the
+     * sequence numbers are guaranteed to not be reused for unacknowledged messages. For messages
+     * sent to the Context Hub, sequence numbers are only guaranteed to be unique within the scope
+     * of a given hostEndPoint. The sequence number may be reused if more than 2^32 messages are
+     * sent, due to the size limit of int.
+     *
+     * The sequence number is used only for reliable messages. There is no guarantee of strict
+     * ordering of messages. The recipient may receive messages with gaps between the sequence
+     * numbers. This is not an indication of a missed message.
+     *
+     * See isReliable for more information.
+     */
+    int messageSequenceNumber;
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/ErrorCode.aidl b/contexthub/aidl/android/hardware/contexthub/ErrorCode.aidl
new file mode 100644
index 0000000..22e7ea1
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/ErrorCode.aidl
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package android.hardware.contexthub;
+
+@VintfStability
+@Backing(type="byte")
+enum ErrorCode {
+    /**
+     * No Error.
+     */
+    OK = 0,
+
+    /**
+     * A generic transient error. The sender may retry the
+     * operation, but there is no guarantee of success.
+     */
+    TRANSIENT_ERROR,
+
+    /**
+     * A generic permanent error. The sender should not retry the operation.
+     */
+    PERMANENT_ERROR,
+
+    /**
+     * The request failed because the sender does not have necessary permissions.
+     * The sender should not retry the operation.
+     */
+    PERMISSION_DENIED,
+
+    /**
+     * The request failed because the destination was not found.
+     * The sender should not retry the operation.
+     */
+    DESTINATION_NOT_FOUND,
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index 9683d2d..b146ff8 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -20,6 +20,7 @@
 import android.hardware.contexthub.ContextHubMessage;
 import android.hardware.contexthub.HostEndpointInfo;
 import android.hardware.contexthub.IContextHubCallback;
+import android.hardware.contexthub.MessageDeliveryStatus;
 import android.hardware.contexthub.NanSessionStateUpdate;
 import android.hardware.contexthub.NanoappBinary;
 import android.hardware.contexthub.NanoappInfo;
@@ -147,7 +148,7 @@
 
     /**
      * Register a callback for the HAL implementation to send asynchronous messages to the service
-     * from a Context hub. There can only be one callback registered for a single Context Hub ID.
+     * from a Context hub. Each HAL client can only have one callback for each Context Hub ID.
      *
      * A call to this function when a callback has already been registered must override the
      * previous registration.
@@ -236,6 +237,21 @@
     void setTestMode(in boolean enable);
 
     /**
+     * Sends a message delivery status to the Context Hub in response to receiving a
+     * ContextHubMessage with isReliable=true. Each reliable message should have a
+     * messageDeliveryStatus response. This method sends the message delivery status
+     * back to the Context Hub.
+     *
+     * @param contextHubId The identifier of the Context Hub.
+     * @param messageDeliveryStatus The status to be sent.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION if ContextHubInfo.supportsReliableMessages is false for
+     * this hub.
+     */
+    void sendMessageDeliveryStatusToHub(
+            in int contextHubId, in MessageDeliveryStatus messageDeliveryStatus);
+
+    /**
      * Error codes that are used as service specific errors with the AIDL return
      * value EX_SERVICE_SPECIFIC.
      */
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
index ebfc4d8..1aa0776 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.contexthub.AsyncEventType;
 import android.hardware.contexthub.ContextHubMessage;
+import android.hardware.contexthub.MessageDeliveryStatus;
 import android.hardware.contexthub.NanSessionRequest;
 import android.hardware.contexthub.NanoappInfo;
 
@@ -91,6 +92,19 @@
     void handleNanSessionRequest(in NanSessionRequest request);
 
     /**
+     * This callback is passed by the Contexthub service to the HAL
+     * implementation to allow the HAL to send the response for a reliable message.
+     * The response is the message delivery status of a recently sent message. See
+     * sendMessageDeliveryStatusToHub() for more details.
+     *
+     * @param hostEndPointId The ID of the host endpoint associated with this message delivery
+     *                       status.
+     * @param messageDeliveryStatus The status to be sent.
+     */
+    void handleMessageDeliveryStatus(
+            in char hostEndpointId, in MessageDeliveryStatus messageDeliveryStatus);
+
+    /**
      * This callback is passed to the HAL implementation to allow the HAL to request a UUID that
      * uniquely identifies a client.
      *
diff --git a/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl b/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl
new file mode 100644
index 0000000..ae425b3
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.hardware.contexthub;
+
+import android.hardware.contexthub.ErrorCode;
+
+@VintfStability
+parcelable MessageDeliveryStatus {
+    /**
+     * The messageSequenceNumber of the ContextHubMessage to which this status applies.
+     */
+    int messageSequenceNumber;
+
+    /**
+     * The error code associated with this status.
+     */
+    ErrorCode errorCode;
+}
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index 5272957..bd483d7 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -16,10 +16,7 @@
 
 #include "contexthub-impl/ContextHub.h"
 
-namespace aidl {
-namespace android {
-namespace hardware {
-namespace contexthub {
+namespace aidl::android::hardware::contexthub {
 
 using ::ndk::ScopedAStatus;
 
@@ -34,10 +31,11 @@
     hub.chrePlatformId = UINT64_C(0x476f6f6754000000);
     hub.chreApiMajorVersion = 1;
     hub.chreApiMinorVersion = 6;
+    hub.supportsReliableMessages = false;
 
     out_contextHubInfos->push_back(hub);
 
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 // We don't expose any nanoapps for the default impl, therefore all nanoapp-related APIs fail.
@@ -63,14 +61,14 @@
 }
 
 ScopedAStatus ContextHub::onSettingChanged(Setting /* in_setting */, bool /*in_enabled */) {
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus ContextHub::queryNanoapps(int32_t in_contextHubId) {
     if (in_contextHubId == kMockHubId && mCallback != nullptr) {
         std::vector<NanoappInfo> nanoapps;
         mCallback->handleNanoappInfo(nanoapps);
-        return ndk::ScopedAStatus::ok();
+        return ScopedAStatus::ok();
     } else {
         return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
@@ -85,18 +83,18 @@
     for (uint64_t i = 0; i < 10; ++i) {
         out_preloadedNanoappIds->push_back(i);
     }
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus ContextHub::onNanSessionStateChanged(const NanSessionStateUpdate& /*in_update*/) {
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId,
                                            const std::shared_ptr<IContextHubCallback>& in_cb) {
     if (in_contextHubId == kMockHubId) {
         mCallback = in_cb;
-        return ndk::ScopedAStatus::ok();
+        return ScopedAStatus::ok();
     } else {
         return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
@@ -108,20 +106,20 @@
         // Return true here to indicate that the HAL has accepted the message.
         // Successful delivery of the message to a nanoapp should be handled at
         // a higher level protocol.
-        return ndk::ScopedAStatus::ok();
+        return ScopedAStatus::ok();
     } else {
         return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 }
 
 ScopedAStatus ContextHub::setTestMode(bool /* enable */) {
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus ContextHub::onHostEndpointConnected(const HostEndpointInfo& in_info) {
     mConnectedHostEndpoints.insert(in_info.hostEndpointId);
 
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus ContextHub::onHostEndpointDisconnected(char16_t in_hostEndpointId) {
@@ -129,10 +127,13 @@
         mConnectedHostEndpoints.erase(in_hostEndpointId);
     }
 
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-}  // namespace contexthub
-}  // namespace hardware
-}  // namespace android
-}  // namespace aidl
+ScopedAStatus ContextHub::sendMessageDeliveryStatusToHub(
+        int32_t /* in_contextHubId */,
+        const MessageDeliveryStatus& /* in_messageDeliveryStatus */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+}  // namespace aidl::android::hardware::contexthub
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index 7a2cfd1..72e8b3b 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -49,6 +49,9 @@
 
     ::ndk::ScopedAStatus onHostEndpointDisconnected(char16_t in_hostEndpointId) override;
     ::ndk::ScopedAStatus onNanSessionStateChanged(const NanSessionStateUpdate& in_update) override;
+    ::ndk::ScopedAStatus sendMessageDeliveryStatusToHub(
+            int32_t in_contextHubId,
+            const MessageDeliveryStatus& in_messageDeliveryStatus) override;
 
   private:
     static constexpr uint32_t kMockHubId = 0;
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index 76b25b6..fd55b80 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -36,9 +36,11 @@
 using ::android::hardware::contexthub::AsyncEventType;
 using ::android::hardware::contexthub::ContextHubInfo;
 using ::android::hardware::contexthub::ContextHubMessage;
+using ::android::hardware::contexthub::ErrorCode;
 using ::android::hardware::contexthub::HostEndpointInfo;
 using ::android::hardware::contexthub::IContextHub;
 using ::android::hardware::contexthub::IContextHubCallbackDefault;
+using ::android::hardware::contexthub::MessageDeliveryStatus;
 using ::android::hardware::contexthub::NanoappBinary;
 using ::android::hardware::contexthub::NanoappInfo;
 using ::android::hardware::contexthub::NanoappRpcService;
@@ -132,6 +134,12 @@
         return Status::ok();
     }
 
+    Status handleMessageDeliveryStatus(
+            char16_t /* hostEndPointId */,
+            const MessageDeliveryStatus& /* messageDeliveryStatus */) override {
+        return Status::ok();
+    }
+
     Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
         *out_uuid = kUuid;
         return Status::ok();
@@ -172,6 +180,12 @@
         return Status::ok();
     }
 
+    Status handleMessageDeliveryStatus(
+            char16_t /* hostEndPointId */,
+            const MessageDeliveryStatus& /* messageDeliveryStatus */) override {
+        return Status::ok();
+    }
+
     Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
         *out_uuid = kUuid;
         return Status::ok();
@@ -248,6 +262,12 @@
         return Status::ok();
     }
 
+    Status handleMessageDeliveryStatus(
+            char16_t /* hostEndPointId */,
+            const MessageDeliveryStatus& /* messageDeliveryStatus */) override {
+        return Status::ok();
+    }
+
     Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
         *out_uuid = kUuid;
         return Status::ok();
@@ -431,6 +451,20 @@
     }
 }
 
+TEST_P(ContextHubAidl, TestSendMessageDeliveryStatusToHub) {
+    MessageDeliveryStatus messageDeliveryStatus;
+    messageDeliveryStatus.messageSequenceNumber = 123;
+    messageDeliveryStatus.errorCode = ErrorCode::OK;
+
+    Status status = contextHub->sendMessageDeliveryStatusToHub(getHubId(), messageDeliveryStatus);
+    if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
+        status.transactionError() == android::UNKNOWN_TRANSACTION) {
+        GTEST_SKIP() << "Not supported -> old API; or not implemented";
+    } else {
+        EXPECT_TRUE(status.isOk());
+    }
+}
+
 std::string PrintGeneratedTest(const testing::TestParamInfo<ContextHubAidl::ParamType>& info) {
     return std::string("CONTEXT_HUB_ID_") + std::to_string(std::get<1>(info.param));
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
index f02f8aa..ee004d6 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
@@ -45,4 +45,5 @@
   BOOT_DISPLAY_CONFIG = 5,
   HDR_OUTPUT_CONVERSION_CONFIG = 6,
   REFRESH_RATE_CHANGED_CALLBACK_DEBUG = 7,
+  LAYER_LIFECYCLE_BATCH_COMMAND = 8,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
index 2b9801a..e9305e1 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
@@ -36,4 +36,5 @@
 parcelable RefreshRateChangedDebugData {
   long display;
   int vsyncPeriodNanos;
+  int refreshPeriodNanos;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
index 4638610..1dfc074 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
@@ -86,4 +86,14 @@
      * @see IComposerCallback.onRefreshRateChangedDebug
      */
     REFRESH_RATE_CHANGED_CALLBACK_DEBUG = 7,
+
+    /**
+     * Specifies that the device HAL supports the batching of layer creation and destruction
+     * for better performance.
+     *
+     * @see IComposerClient.executeCommands
+     * @see LayerCommand.layerLifecycleBatchCommandType
+     * @see LayerCommand.newBufferSlotCount
+     */
+    LAYER_LIFECYCLE_BATCH_COMMAND = 8,
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
index c1f78d6..11c0112 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
@@ -27,4 +27,15 @@
      * The display vsync period in nanoseconds.
      */
     int vsyncPeriodNanos;
+
+    /**
+     * The refresh period of the display in nanoseconds.
+     * On VRR (Variable Refresh Rate) displays, refreshPeriodNanos can be different from the
+     * vsyncPeriodNanos because not every vsync cycle of the display is a refresh cycle.
+     * This should be set to the current refresh period.
+     * On non-VRR displays this value should be equal to vsyncPeriodNanos
+     *
+     * @see vsyncPeriodNanos
+     */
+    int refreshPeriodNanos;
 }
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 11b995e..ac08cd1 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -517,7 +517,8 @@
 void VtsComposerClient::addDisplayConfigs(VtsDisplay* vtsDisplay,
                                           const std::vector<DisplayConfiguration>& configs) {
     for (const auto& config : configs) {
-        vtsDisplay->addDisplayConfig(config.configId, {config.vsyncPeriod, config.configGroup});
+        vtsDisplay->addDisplayConfig(config.configId,
+                                     {config.vsyncPeriod, config.configGroup, config.vrrConfig});
     }
 }
 
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index b45c71f..292bc40 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -253,10 +253,14 @@
     int32_t getDisplayHeight() const { return mDisplayHeight; }
 
     struct DisplayConfig {
-        DisplayConfig(int32_t vsyncPeriod_, int32_t configGroup_)
-            : vsyncPeriod(vsyncPeriod_), configGroup(configGroup_) {}
+        DisplayConfig(int32_t vsyncPeriod_, int32_t configGroup_,
+                      std::optional<VrrConfig> vrrConfig_ = {})
+            : vsyncPeriod(vsyncPeriod_),
+              configGroup(configGroup_),
+              vrrConfig(std::move(vrrConfig_)) {}
         int32_t vsyncPeriod;
         int32_t configGroup;
+        std::optional<VrrConfig> vrrConfig;
     };
 
     void addDisplayConfig(int32_t config, DisplayConfig displayConfig) {
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index a53eb38..2bbaf29 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -2664,26 +2664,40 @@
         return;
     }
 
-    const auto displayId = getPrimaryDisplayId();
-    EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
-    // Enable the callback
-    ASSERT_TRUE(mComposerClient
-                        ->setRefreshRateChangedCallbackDebugEnabled(displayId,
-                                                                    /*enabled*/ true)
-                        .isOk());
-    std::this_thread::sleep_for(100ms);
+    for (VtsDisplay& display : mDisplays) {
+        const auto displayId = display.getDisplayId();
+        EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
+        // Enable the callback
+        ASSERT_TRUE(mComposerClient
+                            ->setRefreshRateChangedCallbackDebugEnabled(displayId,
+                                                                        /*enabled*/ true)
+                            .isOk());
+        std::this_thread::sleep_for(100ms);
 
-    const auto displayFilter = [displayId](auto refreshRateChangedDebugData) {
-        return displayId == refreshRateChangedDebugData.display;
-    };
+        const auto [status, configId] = mComposerClient->getActiveConfig(display.getDisplayId());
+        EXPECT_TRUE(status.isOk());
 
-    // Check that we immediately got a callback
-    EXPECT_TRUE(checkIfCallbackRefreshRateChangedDebugEnabledReceived(displayFilter));
+        const auto displayFilter = [&](auto refreshRateChangedDebugData) {
+            bool nonVrrRateMatching = true;
+            if (std::optional<VrrConfig> vrrConfigOpt =
+                        display.getDisplayConfig(configId).vrrConfig;
+                getInterfaceVersion() >= 3 && !vrrConfigOpt) {
+                nonVrrRateMatching = refreshRateChangedDebugData.refreshPeriodNanos ==
+                                     refreshRateChangedDebugData.vsyncPeriodNanos;
+            }
+            const bool isDisplaySame =
+                    display.getDisplayId() == refreshRateChangedDebugData.display;
+            return nonVrrRateMatching && isDisplaySame;
+        };
 
-    ASSERT_TRUE(mComposerClient
-                        ->setRefreshRateChangedCallbackDebugEnabled(displayId,
-                                                                    /*enabled*/ false)
-                        .isOk());
+        // Check that we immediately got a callback
+        EXPECT_TRUE(checkIfCallbackRefreshRateChangedDebugEnabledReceived(displayFilter));
+
+        ASSERT_TRUE(mComposerClient
+                            ->setRefreshRateChangedCallbackDebugEnabled(displayId,
+                                                                        /*enabled*/ false)
+                            .isOk());
+    }
 }
 
 TEST_P(GraphicsComposerAidlCommandV2Test,
@@ -3001,7 +3015,6 @@
         PerInstance, GraphicsComposerAidlCommandV2Test,
         testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
         ::android::PrintInstanceNameToString);
-
 }  // namespace aidl::android::hardware::graphics::composer3::vts
 
 int main(int argc, char** argv) {
diff --git a/health/aidl/default/Health.cpp b/health/aidl/default/Health.cpp
index 2e1365f..6df623a 100644
--- a/health/aidl/default/Health.cpp
+++ b/health/aidl/default/Health.cpp
@@ -62,6 +62,18 @@
 
 Health::~Health() {}
 
+static inline ndk::ScopedAStatus TranslateStatus(::android::status_t err) {
+    switch (err) {
+        case ::android::OK:
+            return ndk::ScopedAStatus::ok();
+        case ::android::NAME_NOT_FOUND:
+            return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        default:
+            return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                    IHealth::STATUS_UNKNOWN, ::android::statusToString(err).c_str());
+    }
+}
+
 //
 // Getters.
 //
@@ -78,16 +90,7 @@
         LOG(DEBUG) << "getProperty(" << id << ")"
                    << " fails: (" << err << ") " << ::android::statusToString(err);
     }
-
-    switch (err) {
-        case ::android::OK:
-            return ndk::ScopedAStatus::ok();
-        case ::android::NAME_NOT_FOUND:
-            return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-        default:
-            return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
-                    IHealth::STATUS_UNKNOWN, ::android::statusToString(err).c_str());
-    }
+    return TranslateStatus(err);
 }
 
 ndk::ScopedAStatus Health::getChargeCounterUah(int32_t* out) {
@@ -153,8 +156,21 @@
         !res.isOk()) {
         LOG(WARNING) << "Cannot get Battery_state_of_health: " << res.getDescription();
     }
-    out->batterySerialNumber = std::nullopt;
-    out->batteryPartStatus = BatteryPartStatus::UNSUPPORTED;
+    if (auto res = battery_monitor_.getSerialNumber(&out->batterySerialNumber);
+        res != ::android::OK) {
+        LOG(WARNING) << "Cannot get Battery_serial_number: "
+                     << TranslateStatus(res).getDescription();
+    }
+
+    int64_t part_status = static_cast<int64_t>(BatteryPartStatus::UNSUPPORTED);
+    if (auto res = GetProperty<int64_t>(&battery_monitor_, ::android::BATTERY_PROP_PART_STATUS,
+                                        static_cast<int64_t>(BatteryPartStatus::UNSUPPORTED),
+                                        &part_status);
+        !res.isOk()) {
+        LOG(WARNING) << "Cannot get Battery_part_status: " << res.getDescription();
+    }
+    out->batteryPartStatus = static_cast<BatteryPartStatus>(part_status);
+
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/radio/OWNERS b/radio/OWNERS
index 67ac2e2..8107287 100644
--- a/radio/OWNERS
+++ b/radio/OWNERS
@@ -2,3 +2,4 @@
 
 jackyu@google.com
 sarahchin@google.com
+jayachandranc@google.com
\ No newline at end of file
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierInfo.aidl
new file mode 100644
index 0000000..5838959
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierInfo.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.sim;
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
+parcelable CarrierInfo {
+  String mcc;
+  String mnc;
+  @nullable String spn;
+  @nullable String gid1;
+  @nullable String gid2;
+  @nullable String imsiPrefix;
+  @nullable List<android.hardware.radio.sim.Plmn> ephlmn;
+  @nullable String iccid;
+  @nullable String impi;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
index 84cdf5d..a5b8dc9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
@@ -35,10 +35,18 @@
 /* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CarrierRestrictions {
+  /**
+   * @deprecated use @List<CarrierInfo> allowedCarrierInfoList
+   */
   android.hardware.radio.sim.Carrier[] allowedCarriers;
+  /**
+   * @deprecated use @List<CarrierInfo> excludedCarrierInfoList
+   */
   android.hardware.radio.sim.Carrier[] excludedCarriers;
   boolean allowedCarriersPrioritized;
   android.hardware.radio.sim.CarrierRestrictions.CarrierRestrictionStatus status;
+  android.hardware.radio.sim.CarrierInfo[] allowedCarrierInfoList = {};
+  android.hardware.radio.sim.CarrierInfo[] excludedCarrierInfoList = {};
   @Backing(type="int") @VintfStability
   enum CarrierRestrictionStatus {
     UNKNOWN = 0,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/Plmn.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/Plmn.aidl
new file mode 100644
index 0000000..b29a4a7
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/Plmn.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.sim;
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
+parcelable Plmn {
+  String mcc;
+  String mnc;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
index 5a5e8ac..8cfe417 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
@@ -37,4 +37,11 @@
 enum SimLockMultiSimPolicy {
   NO_MULTISIM_POLICY,
   ONE_VALID_SIM_MUST_BE_PRESENT,
+  APPLY_TO_ALL_SLOTS,
+  APPLY_TO_ONLY_SLOT_1,
+  VALID_SIM_MUST_PRESENT_ON_SLOT_1,
+  ACTIVE_SERVICE_ON_SLOT_1_TO_UNBLOCK_OTHER_SLOTS,
+  ACTIVE_SERVICE_ON_ANY_SLOT_TO_UNBLOCK_OTHER_SLOTS,
+  ALL_SIMS_MUST_BE_VALID,
+  SLOT_POLICY_OTHER,
 }
diff --git a/radio/aidl/android/hardware/radio/sim/CarrierInfo.aidl b/radio/aidl/android/hardware/radio/sim/CarrierInfo.aidl
new file mode 100644
index 0000000..a890497
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sim/CarrierInfo.aidl
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.sim;
+
+import android.hardware.radio.sim.Plmn;
+
+/** @hide */
+@VintfStability
+@JavaDerive(toString=true)
+parcelable CarrierInfo {
+    /**
+     * MCC (Mobile Country Code) of Carrier. Wild char is either '*' or '?'.
+     */
+    String mcc;
+
+    /**
+     * MNC (Mobile Network Code) of the Carrier. Wild char is either '*' or '?'.
+     */
+    String mnc;
+    /**
+     * Service Provider Name(SPN) of the SIM card of the Carrier.
+     */
+    @nullable
+    String spn;
+    /**
+     * GID1 value of the SIM card of the Carrier.
+     */
+    @nullable
+    String gid1;
+    /**
+     * GID2 value of the SIM card of the Carrier.
+     */
+    @nullable
+    String gid2;
+
+    /**
+     * IMSI (International Mobile Subscriber Identity) prefix. Wild char is '*'.
+     */
+    @nullable
+    String imsiPrefix;
+    /**
+     * Equivalent HPLMN of the SIM card of the Carrier.
+     */
+    @nullable
+    List<Plmn> ephlmn;
+    /**
+     * ICCID (Integrated Circuit Card Identification) of the SIM card.
+     */
+    @nullable
+    String iccid;
+    /**
+     * IMPI (IMS Private Identity) of the SIM card of the Carrier.
+     */
+    @nullable
+    String impi;
+}
\ No newline at end of file
diff --git a/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl b/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
index d5e0c43..0002d5a 100644
--- a/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
+++ b/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
@@ -17,6 +17,7 @@
 package android.hardware.radio.sim;
 
 import android.hardware.radio.sim.Carrier;
+import android.hardware.radio.sim.CarrierInfo;
 
 /** @hide */
 @VintfStability
@@ -40,12 +41,14 @@
     }
     /**
      * Allowed carriers
+     * @deprecated use @List<CarrierInfo> allowedCarrierInfoList
      */
     Carrier[] allowedCarriers;
     /**
      * Explicitly excluded carriers which match allowed_carriers. Eg. allowedCarriers match mcc/mnc,
      * excludedCarriers has same mcc/mnc and gid1 is ABCD. It means except the carrier whose gid1
      * is ABCD, all carriers with the same mcc/mnc are allowed.
+     * @deprecated use @List<CarrierInfo> excludedCarrierInfoList
      */
     Carrier[] excludedCarriers;
     /**
@@ -59,4 +62,14 @@
     boolean allowedCarriersPrioritized;
     /** Current restriction status as defined in CarrierRestrictionStatus enum */
     CarrierRestrictionStatus status;
-}
+
+    /**  Allowed carriers. */
+    CarrierInfo[] allowedCarrierInfoList = {};
+
+    /**
+     * Explicitly excluded carriers which match allowed_carriers. Eg. allowedCarriers match mcc/mnc,
+     * excludedCarriers has same mcc/mnc and gid1 is ABCD. It means except the carrier whose gid1
+     * is ABCD, all carriers with the same mcc/mnc are allowed.
+     */
+    CarrierInfo[]  excludedCarrierInfoList = {};
+}
\ No newline at end of file
diff --git a/radio/aidl/android/hardware/radio/sim/Plmn.aidl b/radio/aidl/android/hardware/radio/sim/Plmn.aidl
new file mode 100644
index 0000000..fd82692
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sim/Plmn.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.sim;
+
+/** @hide */
+@VintfStability
+@JavaDerive(toString=true)
+parcelable Plmn {
+    /**
+     * MCC (Mobile Country Code) of the PLMN
+     */
+    String mcc;
+    /**
+     * MNC (Mobile Network Code) of the PLMN
+     */
+    String mnc;
+}
\ No newline at end of file
diff --git a/radio/aidl/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl b/radio/aidl/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
index 18f97f7..89d85a9 100644
--- a/radio/aidl/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
+++ b/radio/aidl/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
@@ -21,14 +21,56 @@
 @Backing(type="int")
 @JavaDerive(toString=true)
 enum SimLockMultiSimPolicy {
+
     /**
      * Indicates that configuration applies to each slot independently.
      */
     NO_MULTISIM_POLICY,
+
     /**
      * Indicates that any SIM card can be used as far as one valid card is present in the device.
      * For the modem, a SIM card is valid when its content (i.e. MCC, MNC, GID, SPN) matches the
      * carrier restriction configuration.
      */
     ONE_VALID_SIM_MUST_BE_PRESENT,
+
+    /**
+     * Indicates that the SIM lock policy applies uniformly to all sim slots.
+     */
+    APPLY_TO_ALL_SLOTS,
+
+    /**
+     * The SIM lock configuration applies exclusively to sim slot 1, leaving
+     * all other sim slots unlocked irrespective of the SIM card in slot 1
+     */
+    APPLY_TO_ONLY_SLOT_1,
+
+    /**
+     * Valid sim cards must be present on sim slot1 in order
+     * to use other sim slots.
+     */
+    VALID_SIM_MUST_PRESENT_ON_SLOT_1,
+
+    /**
+     * Valid sim card must be present on slot1 and it must be in full service
+     * in order to use other sim slots.
+     */
+    ACTIVE_SERVICE_ON_SLOT_1_TO_UNBLOCK_OTHER_SLOTS,
+
+    /**
+     * Valid sim card be present on any slot and it must be in full service
+     * in order to use other sim slots.
+     */
+    ACTIVE_SERVICE_ON_ANY_SLOT_TO_UNBLOCK_OTHER_SLOTS,
+
+    /**
+     * Valid sim cards must be present on all slots. If any SIM cards become
+     * invalid then device would set other SIM cards as invalid as well.
+     */
+    ALL_SIMS_MUST_BE_VALID,
+
+    /**
+     * In case there is no match policy listed above.
+     */
+    SLOT_POLICY_OTHER
 }
diff --git a/security/authgraph/aidl/vts/functional/sink.rs b/security/authgraph/aidl/vts/functional/sink.rs
index bb357b8..a331eef 100644
--- a/security/authgraph/aidl/vts/functional/sink.rs
+++ b/security/authgraph/aidl/vts/functional/sink.rs
@@ -29,11 +29,11 @@
 }
 
 /// Perform mainline AuthGraph key exchange with the provided sink and local implementation.
-/// Return the agreed AES keys in plaintext.
+/// Return the agreed AES keys in plaintext, together with the session ID.
 pub fn test_mainline(
     local_source: &mut ke::AuthGraphParticipant,
     sink: binder::Strong<dyn IAuthGraphKeyExchange>,
-) -> [key::AesKey; 2] {
+) -> ([key::AesKey; 2], Vec<u8>) {
     // Step 1: create an ephemeral ECDH key at the (local) source.
     let source_init_info = local_source
         .create()
@@ -113,7 +113,7 @@
         Ok(array) => array,
         Err(_) => panic!("wrong number of decrypted shared key arcs"),
     };
-    decrypted_shared_keys_array
+    (decrypted_shared_keys_array, sink_info.sessionId)
 }
 
 /// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
diff --git a/security/authgraph/aidl/vts/functional/source.rs b/security/authgraph/aidl/vts/functional/source.rs
index a1e76b3..019e1e8 100644
--- a/security/authgraph/aidl/vts/functional/source.rs
+++ b/security/authgraph/aidl/vts/functional/source.rs
@@ -29,11 +29,11 @@
 }
 
 /// Perform mainline AuthGraph key exchange with the provided source.
-/// Return the agreed AES keys in plaintext.
+/// Return the agreed AES keys in plaintext, together with the session ID.
 pub fn test_mainline(
     local_sink: &mut ke::AuthGraphParticipant,
     source: binder::Strong<dyn IAuthGraphKeyExchange>,
-) -> [key::AesKey; 2] {
+) -> ([key::AesKey; 2], Vec<u8>) {
     // Step 1: create an ephemeral ECDH key at the (remote) source.
     let source_init_info = source
         .create()
@@ -120,7 +120,7 @@
         Ok(array) => array,
         Err(_) => panic!("wrong number of decrypted shared key arcs"),
     };
-    decrypted_shared_keys_array
+    (decrypted_shared_keys_array, source_info.sessionId)
 }
 
 /// Perform mainline AuthGraph key exchange with the provided source, but provide an invalid session
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
new file mode 100644
index 0000000..cc07f9b
--- /dev/null
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ErrorCode.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.secretkeeper;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum ErrorCode {
+  OK = 0,
+  UNKNOWN_KEY_ID = 1,
+  INTERNAL_ERROR = 2,
+  REQUEST_MALFORMED = 3,
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl
new file mode 100644
index 0000000..e9cce09
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ErrorCode.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.hardware.security.secretkeeper;
+
+/**
+ * Secretkeeper unencrypted error code, returned via AIDL as service specific errors in
+ * EX_SERVICE_SPECIFIC.
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum ErrorCode {
+    OK = 0,
+    UNKNOWN_KEY_ID = 1,
+    INTERNAL_ERROR = 2,
+    REQUEST_MALFORMED = 3,
+
+    // TODO(b/291224769): Create a more exhaustive set of error code values.
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
index 1f4768a..cb3e9b9 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -35,7 +35,7 @@
  * Typical operations are (securely) updating the dice policy sealing the Secrets above. These
  * operations are core to AntiRollback protected secrets - ie, ensuring secrets of a pVM are only
  * accessible to same or higher versions of the images.
- * 2. Maintenance api: This is required for removing the Secretkeeper entries for obsolete pvMs.
+ * 2. Maintenance API: This is required for removing the Secretkeeper entries for obsolete pVMs.
  */
 interface ISecretkeeper {
     /**
@@ -60,7 +60,11 @@
      * Virtual Machines). For this, service (& client) must implement a key exchange protocol, which
      * is critical for establishing the secure channel.
      *
+     * If an encrypted response cannot be generated, then a service-specific Binder error using an
+     * error code from ErrorCode.aidl will be returned.
+     *
      * Secretkeeper database should guarantee the following properties:
+     *
      * 1. Confidentiality: No entity (of security privilege lower than Secretkeeper) should
      *    be able to get a client's data in clear.
      *
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
index 62a1bd7..66ca8ed 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
@@ -1,110 +1,73 @@
 ; CDDL for the Secret Management API.
-; Also see processSecretManagementRequest method in ISecretkeeper.aidl
 
-; ProtectedRequestPacket is used by client for accessing Secret Management API
-; in Secretkeeper service. The service returns ProtectedResponsePacket of the corresponding type.
+; The input parameter to the `processSecretManagementRequest` operation in
+; `ISecretkeeper.aidl` is always an encrypted request message, CBOR-encoded as a
+; COSE_Encrypt0 object.  The encryption uses the first of the keys agreed using
+; the associated AuthGraph instance, referred to as `KeySourceToSink`.
+ProtectedRequestPacket = CryptoPayload<RequestPacket, KeySourceToSink>
 
-; ProtectedRequestPacket & ProtectedResponsePacket are encrypted wrappers
-; on RequestPacket & ResponsePacket using symmetric keys agreed between Secretkeeper & clients
-; (these are referred to as KeySourceToSink & KeySinkToSource)
-;
-; The API operation required is encoded using 'Opcode', the arguments using 'Params'
-; and returned values as 'Result'.
-
-ProtectedRequestPacket =
-        ProtectedGetVersionRequest / ProtectedStoreSecretRequest / ProtectedGetSecretRequest
-ProtectedResponsePacket =
-        ProtectedGetVersionResponse / ProtectedStoreSecretResponse / ProtectedGetSecretResponse
-
-ProtectedGetVersionRequest = ProtectedRequestPacket<GetVersionRequestPacket>
-ProtectedGetVersionResponse = ProtectedResponsePacket<GetVersionResponsePacket>
-ProtectedStoreSecretRequest = ProtectedRequestPacket<StoreSecretRequestPacket>
-ProtectedStoreSecretResponse = ProtectedResponsePacket<StoreSecretResponsePacket>
-ProtectedGetSecretRequest = ProtectedRequestPacket<GetSecretRequestPacket>
-ProtectedGetSecretResponse = ProtectedResponsePacket<GetSecretResponsePacket>
-
-GetVersionRequestPacket = RequestPacket<GetVersionOpcode, GetVersionParams>
-GetVersionResponsePacket = ResponsePacket<GetVersionResult>
-StoreSecretRequestPacket = RequestPacket<StoreSecretOpcode, StoreSecretParams>
-StoreSecretResponsePacket = ResponsePacket<StoreSecretResult>
-GetSecretRequestPacket = RequestPacket<GetOpcode, GetSecretParams>
-GetSecretResponsePacket = ResponsePacket<GetSecretResult>
-
-RequestPacket<Opcode, Params> = [
-    Opcode,
-    Params
-]
-ResponsePacket<Result> = ResponsePacketError / ResponsePacketSuccess<Result>
-
-ResponsePacketSuccess = [
-    0,                          ; Indicates successful Response
-    result : Result
-]
-ResponsePacketError = [
-    error_code: ErrorCode,      ; Indicate the error
-    error_message: tstr         ; Additional human-readable context
-]
-
-Opcode = &(
-    GetVersionOpcode: 1,     ; Get version of the SecretManagement API
-    StoreSecretOpcode: 2,          ; Store a secret
-    GetSecretOpcode: 3,            ; Get the secret
-)
-
-GetVersionParams = ()
-GetVersionResult = (version : uint)
-
-StoreSecretParams = (
-    id : bstr .size 64              ; Unique identifier of the secret
-    secret : bstr .size 32,
-    sealing_policy : bstr .cbor DicePolicy,    ; See DicePolicy.cddl for definition of DicePolicy
-)
-StoreSecretResult = ()
-
-GetSecretParams = (
-    id : bstr .size 64              ; Unique identifier of the secret
-    ; Use this to update the sealing policy associated with a secret during GetSecret operation.
-    updated_sealing_policy : bstr .cbor DicePolicy / nil,
-)
-GetSecretResult = (secret : bstr .size 32)
-
-
-ProtectedRequestPacket<Payload, Key> = CryptoPayload<Payload, KeySourceToSink>
-ProtectedResponsePacket<Payload, Key> = ProtectedResponseError
-                                    / ProtectedResponseSuccess<Payload>
-
-ProtectedResponseSuccess<Payload> = [
-    0,                                ; Indicates successful crypto operations. Note: Payload
-                                                    ; may contain Error from functional layer.
-    message: CryptoPayload<Payload, KeySinkToSource>         ; message is the encrypted payload
-]
-
-ProtectedResponseError = [
-    error_code: CryptoErrorCode,           ; Indicates the error. This is in cleartext & will be
-                                           ; visible to Android. These are errors from crypto
-                                           ; layer & indicates the request could not even be read
-    message: tstr                          ; Additional human-readable context
-]
-
-CryptoPayload<Payload, Key> = [         ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
+CryptoPayload<Payload, Key> = [ ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
     protected: bstr .cbor {
         1 : 3,                  ; Algorithm: AES-GCM mode w/ 256-bit key, 128-bit tag
         4 : bstr                ; key identifier, uniquely identifies the session
                                 ; TODO(b/291228560): Refer to the Key Exchange spec.
     },
     unprotected: {
-        5 : bstr .size 12          ; IV
+        5 : bstr .size 12       ; IV
     },
-    ciphertext : bstr     ; AES-GCM-256(Key, bstr .cbor Payload)
-                          ; AAD for the encryption is CBOR-serialized
-                          ; Enc_structure (RFC 9052 s5.3) with empty external_aad.
+    ciphertext : bstr           ; AES-GCM-256(Key, bstr .cbor Payload)
+                                ; AAD for the encryption is CBOR-serialized
+                                ; Enc_structure (RFC 9052 s5.3) with empty external_aad.
 ]
 
-; TODO(b/291224769): Create a more exhaustive set of CryptoErrorCode
-CryptoErrorCode = &(
-    CryptoErrorCode_SessionExpired: 1,
+; Once decrypted, the request packet is an encoded CBOR array holding:
+; - An initial integer indicating which request is present.
+; - Subsequent objects holding the parameters for that specific request.
+RequestPacket =
+    [GetVersionOpcode, GetVersionParams] /
+    [StoreSecretOpcode, StoreSecretParams] /
+    [GetSecretOpcode, GetSecretParams]
+
+GetVersionOpcode = 1            ; Get version of the SecretManagement API
+StoreSecretOpcode = 2           ; Store a secret
+GetSecretOpcode = 3             ; Get the secret
+
+GetVersionParams = ()
+
+StoreSecretParams = (
+    id : SecretId,
+    secret : Secret,
+    sealing_policy : bstr .cbor DicePolicy,
 )
 
+; INCLUDE DicePolicy.cddl for: DicePolicy
+
+GetSecretParams = (
+    id : SecretId,
+    ; Retrieving the value of a secret may optionally also update the sealing
+    ; policy associated with a secret.
+    updated_sealing_policy : bstr .cbor DicePolicy / nil,
+)
+
+SecretId = bstr .size 64        ; Unique identifier of the secret.
+Secret = bstr .size 32          ; The secret value.
+
+; The return value from a successful `processSecretManagementRequest` operation is a
+; response message encrypted with the second of the keys agreed using the associated
+; AuthGraph instance, referred to as `KeySinkToSource`.
+ProtectedResponsePacket = CryptoPayload<ResponsePacket, KeySinkToSource>
+
+; Once decrypted, the inner response message is encoded as a CBOR array holding:
+; - An initial integer return code value.
+; - Subsequently:
+;    - If the return code is zero: result value(s).
+;    - If the return code is non-zero: an error message.
+ResponsePacket =
+    [0, Result] /
+    [error_code: ErrorCode, error_message: tstr]
+
+; An error code in the inner response message indicates a failure in
+; secret management processing.
 ; TODO(b/291224769): Create a more exhaustive set of ErrorCodes
 ErrorCode = &(
     ; Use this as if no other error code can be used.
@@ -119,4 +82,16 @@
     ErrorCode_DicePolicyError: 5,
 )
 
-; INCLUDE DicePolicy.cddl for: DicePolicy
\ No newline at end of file
+; The particular result variant present is determined by which request
+; message was originally sent.
+Result = &(
+    GetVersionResult,
+    StoreSecretResult,
+    GetSecretResult,
+)
+
+GetVersionResult = (version : uint)
+
+StoreSecretResult = ()
+
+GetSecretResult = (secret : Secret)
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
index def5d5d..c130a3a 100644
--- a/security/secretkeeper/aidl/vts/Android.bp
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -27,7 +27,9 @@
     ],
     rustlibs: [
         "libsecretkeeper_comm_nostd",
+        "libsecretkeeper_core_nostd",
         "android.hardware.security.secretkeeper-V1-rust",
+        "libauthgraph_boringssl",
         "libauthgraph_core",
         "libcoset",
         "libauthgraph_vts_test",
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
index cc606b1..a473bd0 100644
--- a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -16,8 +16,9 @@
 
 #[cfg(test)]
 use binder::StatusCode;
-use coset::CborSerializable;
+use coset::{CborSerializable, CoseEncrypt0};
 use log::warn;
+use secretkeeper_core::cipher;
 use secretkeeper_comm::data_types::error::SecretkeeperError;
 use secretkeeper_comm::data_types::request::Request;
 use secretkeeper_comm::data_types::request_response_impl::{
@@ -28,6 +29,7 @@
 use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
 use authgraph_vts_test as ag_vts;
+use authgraph_boringssl as boring;
 use authgraph_core::key;
 
 const SECRETKEEPER_IDENTIFIER: &str =
@@ -73,7 +75,50 @@
         }
     }
 }
-fn authgraph_key_exchange(sk: binder::Strong<dyn ISecretkeeper>) -> [key::AesKey; 2] {
+
+/// Secretkeeper client information.
+struct SkClient {
+    sk: binder::Strong<dyn ISecretkeeper>,
+    aes_keys: [key::AesKey; 2],
+    session_id: Vec<u8>,
+}
+
+impl SkClient {
+    fn new() -> Option<Self> {
+        let sk = get_connection()?;
+        let (aes_keys, session_id) = authgraph_key_exchange(sk.clone());
+        Some(Self {
+            sk,
+            aes_keys,
+            session_id,
+        })
+    }
+    /// Wrapper around `ISecretkeeper::processSecretManagementRequest` that handles
+    /// encryption and decryption.
+    fn secret_management_request(&self, req_data: &[u8]) -> Vec<u8> {
+        let aes_gcm = boring::BoringAes;
+        let rng = boring::BoringRng;
+        let request_bytes = cipher::encrypt_message(
+            &aes_gcm,
+            &rng,
+            &self.aes_keys[0],
+            &self.session_id,
+            &req_data,
+        )
+        .unwrap();
+
+        let response_bytes = self
+            .sk
+            .processSecretManagementRequest(&request_bytes)
+            .unwrap();
+
+        let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes).unwrap();
+        cipher::decrypt_message(&aes_gcm, &self.aes_keys[1], &response_encrypt0).unwrap()
+    }
+}
+
+/// Perform AuthGraph key exchange, returning the session keys and session ID.
+fn authgraph_key_exchange(sk: binder::Strong<dyn ISecretkeeper>) -> ([key::AesKey; 2], Vec<u8>) {
     let sink = sk.getAuthGraphKe().expect("failed to get AuthGraph");
     let mut source = ag_vts::test_ag_participant().expect("failed to create a local source");
     ag_vts::sink::test_mainline(&mut source, sink)
@@ -90,7 +135,7 @@
             return;
         }
     };
-    let _aes_keys = authgraph_key_exchange(sk);
+    let (_aes_keys, _session_id) = authgraph_key_exchange(sk);
 }
 
 /// Test that the AuthGraph instance returned by SecretKeeper correctly rejects
@@ -130,23 +175,19 @@
 
 #[test]
 fn secret_management_get_version() {
-    let secretkeeper = match get_connection() {
+    let sk_client = match SkClient::new() {
         Some(sk) => sk,
         None => {
             warn!("Secretkeeper HAL is unavailable, skipping test");
             return;
         }
     };
+
     let request = GetVersionRequest {};
     let request_packet = request.serialize_to_packet();
     let request_bytes = request_packet.to_vec().unwrap();
 
-    // TODO(b/291224769) The request will need to be encrypted & response need to be decrypted
-    // with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
-
-    let response_bytes = secretkeeper
-        .processSecretManagementRequest(&request_bytes)
-        .unwrap();
+    let response_bytes = sk_client.secret_management_request(&request_bytes);
 
     let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
     assert_eq!(
@@ -160,13 +201,14 @@
 
 #[test]
 fn secret_management_malformed_request() {
-    let secretkeeper = match get_connection() {
+    let sk_client = match SkClient::new() {
         Some(sk) => sk,
         None => {
             warn!("Secretkeeper HAL is unavailable, skipping test");
             return;
         }
     };
+
     let request = GetVersionRequest {};
     let request_packet = request.serialize_to_packet();
     let mut request_bytes = request_packet.to_vec().unwrap();
@@ -174,12 +216,7 @@
     // Deform the request
     request_bytes[0] = !request_bytes[0];
 
-    // TODO(b/291224769) The request will need to be encrypted & response need to be decrypted
-    // with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
-
-    let response_bytes = secretkeeper
-        .processSecretManagementRequest(&request_bytes)
-        .unwrap();
+    let response_bytes = sk_client.secret_management_request(&request_bytes);
 
     let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
     assert_eq!(
@@ -192,7 +229,7 @@
 
 #[test]
 fn secret_management_store_get_secret_found() {
-    let secretkeeper = match get_connection() {
+    let sk_client = match SkClient::new() {
         Some(sk) => sk,
         None => {
             warn!("Secretkeeper HAL is unavailable, skipping test");
@@ -207,9 +244,8 @@
     };
 
     let store_request = store_request.serialize_to_packet().to_vec().unwrap();
-    let store_response = secretkeeper
-        .processSecretManagementRequest(&store_request)
-        .unwrap();
+
+    let store_response = sk_client.secret_management_request(&store_request);
     let store_response = ResponsePacket::from_slice(&store_response).unwrap();
 
     assert_eq!(
@@ -226,9 +262,7 @@
     };
     let get_request = get_request.serialize_to_packet().to_vec().unwrap();
 
-    let get_response = secretkeeper
-        .processSecretManagementRequest(&get_request)
-        .unwrap();
+    let get_response = sk_client.secret_management_request(&get_request);
     let get_response = ResponsePacket::from_slice(&get_response).unwrap();
     assert_eq!(get_response.response_type().unwrap(), ResponseType::Success);
     let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
@@ -237,7 +271,7 @@
 
 #[test]
 fn secret_management_store_get_secret_not_found() {
-    let secretkeeper = match get_connection() {
+    let sk_client = match SkClient::new() {
         Some(sk) => sk,
         None => {
             warn!("Secretkeeper HAL is unavailable, skipping test");
@@ -253,9 +287,7 @@
     };
 
     let store_request = store_request.serialize_to_packet().to_vec().unwrap();
-    let store_response = secretkeeper
-        .processSecretManagementRequest(&store_request)
-        .unwrap();
+    let store_response = sk_client.secret_management_request(&store_request);
     let store_response = ResponsePacket::from_slice(&store_response).unwrap();
 
     assert_eq!(
@@ -269,9 +301,7 @@
         updated_sealing_policy: None,
     };
     let get_request = get_request.serialize_to_packet().to_vec().unwrap();
-    let get_response = secretkeeper
-        .processSecretManagementRequest(&get_request)
-        .unwrap();
+    let get_response = sk_client.secret_management_request(&get_request);
 
     // Check that response is `SecretkeeperError::EntryNotFound`
     let get_response = ResponsePacket::from_slice(&get_response).unwrap();
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
index bf4c2c0..ccb7876 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
@@ -62,6 +62,13 @@
   void stopSendingKeepAlivePackets(in int cmdId);
   void setDtimMultiplier(in int multiplier);
   android.hardware.wifi.CachedScanData getCachedScanData();
+  android.hardware.wifi.TwtCapabilities twtGetCapabilities();
+  void twtSessionSetup(in int cmdId, in android.hardware.wifi.TwtRequest twtRequest);
+  void twtSessionUpdate(in int cmdId, in int sessionId, in android.hardware.wifi.TwtRequest twtRequest);
+  void twtSessionSuspend(in int cmdId, in int sessionId);
+  void twtSessionResume(in int cmdId, in int sessionId);
+  void twtSessionTeardown(in int cmdId, in int sessionId);
+  void twtSessionGetStats(in int cmdId, in int sessionId);
   @Backing(type="int") @VintfStability
   enum FeatureSetMask {
     APF = (1 << 0) /* 1 */,
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
index 48b85b0..629ca3d 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
@@ -38,4 +38,31 @@
   oneway void onBackgroundScanFailure(in int cmdId);
   oneway void onBackgroundScanResults(in int cmdId, in android.hardware.wifi.StaScanData[] scanDatas);
   oneway void onRssiThresholdBreached(in int cmdId, in byte[6] currBssid, in int currRssi);
+  oneway void onTwtFailure(in int cmdId, in android.hardware.wifi.IWifiStaIfaceEventCallback.TwtErrorCode error);
+  oneway void onTwtSessionCreate(in int cmdId, in android.hardware.wifi.TwtSession twtSession);
+  oneway void onTwtSessionUpdate(in int cmdId, in android.hardware.wifi.TwtSession twtSession);
+  oneway void onTwtSessionTeardown(in int cmdId, in int twtSessionId, in android.hardware.wifi.IWifiStaIfaceEventCallback.TwtTeardownReasonCode reasonCode);
+  oneway void onTwtSessionStats(in int cmdId, in int twtSessionId, in android.hardware.wifi.TwtSessionStats twtSessionStats);
+  oneway void onTwtSessionSuspend(in int cmdId, in int twtSessionId);
+  oneway void onTwtSessionResume(in int cmdId, in int twtSessionId);
+  @Backing(type="byte") @VintfStability
+  enum TwtErrorCode {
+    FAILURE_UNKNOWN,
+    ALREADY_RESUMED,
+    ALREADY_SUSPENDED,
+    INVALID_PARAMS,
+    MAX_SESSION_REACHED,
+    NOT_AVAILABLE,
+    NOT_SUPPORTED,
+    PEER_NOT_SUPPORTED,
+    PEER_REJECTED,
+    TIMEOUT,
+  }
+  @Backing(type="byte") @VintfStability
+  enum TwtTeardownReasonCode {
+    UNKNOWN,
+    LOCALLY_REQUESTED,
+    INTERNALLY_INITIATED,
+    PEER_INITIATED,
+  }
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtCapabilities.aidl
new file mode 100644
index 0000000..d8e73fb
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtCapabilities.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable TwtCapabilities {
+  boolean isTwtRequesterSupported;
+  boolean isTwtResponderSupported;
+  boolean isBroadcastTwtSupported;
+  boolean isFlexibleTwtScheduleSupported;
+  int minWakeDurationMicros;
+  int maxWakeDurationMicros;
+  int minWakeIntervalMicros;
+  int maxWakeIntervalMicros;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtRequest.aidl
new file mode 100644
index 0000000..3051b94
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtRequest.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable TwtRequest {
+  int mloLinkId;
+  int minWakeDurationMicros;
+  int maxWakeDurationMicros;
+  int minWakeIntervalMicros;
+  int maxWakeIntervalMicros;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSession.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSession.aidl
new file mode 100644
index 0000000..92c2533
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSession.aidl
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable TwtSession {
+  int sessionId;
+  int mloLinkId;
+  int wakeDurationMicros;
+  int wakeIntervalMicros;
+  android.hardware.wifi.TwtSession.TwtNegotiationType negotiationType;
+  boolean isTriggerEnabled;
+  boolean isAnnounced;
+  boolean isImplicit;
+  boolean isProtected;
+  boolean isUpdatable;
+  boolean isSuspendable;
+  boolean isResponderPmModeEnabled;
+  @Backing(type="byte") @VintfStability
+  enum TwtNegotiationType {
+    INDIVIDUAL = 0,
+    BROADCAST = 1,
+  }
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSessionStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSessionStats.aidl
new file mode 100644
index 0000000..528444a
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSessionStats.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable TwtSessionStats {
+  int avgTxPktCount;
+  int avgRxPktCount;
+  int avgTxPktSize;
+  int avgRxPktSize;
+  int avgEospDurationMicros;
+  int eospCount;
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
index 03b2217..6c5451b 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
@@ -25,6 +25,8 @@
 import android.hardware.wifi.StaRoamingCapabilities;
 import android.hardware.wifi.StaRoamingConfig;
 import android.hardware.wifi.StaRoamingState;
+import android.hardware.wifi.TwtCapabilities;
+import android.hardware.wifi.TwtRequest;
 import android.hardware.wifi.WifiBand;
 import android.hardware.wifi.WifiDebugRxPacketFateReport;
 import android.hardware.wifi.WifiDebugTxPacketFateReport;
@@ -573,4 +575,113 @@
      *         |WifiStatusCode.ERROR_UNKNOWN|
      */
     CachedScanData getCachedScanData();
+
+    /**
+     * Get Target Wake Time (TWT) local device capabilities for the station interface.
+     *
+     * @return Instance of |TwtCapabilities|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    TwtCapabilities twtGetCapabilities();
+
+    /**
+     * Setup a Target Wake Time (TWT) session.
+     *
+     * Supported only if |TwtCapabilities.isTwtRequesterSupported| is set. Results in asynchronous
+     * callback |IWifiStaIfaceEventCallback.onTwtSessionCreate| on success or
+     * |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param twtRequest TWT Request parameters.
+     *  @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionSetup(in int cmdId, in TwtRequest twtRequest);
+
+    /**
+     * Update a Target Wake Time (TWT) session.
+     *
+     * Supported only if the TWT session can be updated. See |TwtSession.isUpdatable|. Results in
+     * asynchronous callback |IWifiStaIfaceEventCallback.onTwtSessionUpdate| on success or
+     * |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param sessionId TWT session id.
+     * @param twtRequest TWT Request parameters.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionUpdate(in int cmdId, in int sessionId, in TwtRequest twtRequest);
+
+    /**
+     * Suspend a Target Wake Time (TWT) session until a resume is called.
+     *
+     * Supported only if the TWT session supports suspend and resume. See
+     * |TwtSession.isSuspendable|. Results in asynchronous callback
+     * |IWifiStaIfaceEventCallback.onTwtSessionSuspend| on success or
+     * |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param sessionId TWT session id.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionSuspend(in int cmdId, in int sessionId);
+
+    /**
+     * Resume a Target Wake Time (TWT) session which is suspended.
+     *
+     * Supported only if the TWT session supports suspend and resume. See
+     * |TwtSession.isSuspendable|. Results in asynchronous callback
+     * |IWifiStaIfaceEventCallback.onTwtSessionResume| on success or
+     * |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param sessionId TWT session id.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionResume(in int cmdId, in int sessionId);
+
+    /**
+     * Teardown a Target Wake Time (TWT) session.
+     *
+     * Results in asynchronous callback |IWifiStaIfaceEventCallback.onTwtSessionTeardown| on
+     * success or |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param sessionId TWT session id.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionTeardown(in int cmdId, in int sessionId);
+
+    /**
+     * Get stats for a Target Wake Time (TWT) session.
+     *
+     * Results in asynchronous callback |IWifiStaIfaceEventCallback.onTwtSessionStats| on success
+     * or |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param sessionId TWT session id.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionGetStats(in int cmdId, in int sessionId);
 }
diff --git a/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl b/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
index 93a255f..dda7c77 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
@@ -18,6 +18,8 @@
 
 import android.hardware.wifi.StaScanData;
 import android.hardware.wifi.StaScanResult;
+import android.hardware.wifi.TwtSession;
+import android.hardware.wifi.TwtSessionStats;
 
 @VintfStability
 oneway interface IWifiStaIfaceEventCallback {
@@ -61,4 +63,104 @@
      * @param currRssi RSSI of the currently connected access point.
      */
     void onRssiThresholdBreached(in int cmdId, in byte[6] currBssid, in int currRssi);
+
+    @VintfStability
+    @Backing(type="byte")
+    enum TwtErrorCode {
+        /** Unknown failure */
+        FAILURE_UNKNOWN,
+        /** TWT session is already resumed */
+        ALREADY_RESUMED,
+        /** TWT session is already suspended */
+        ALREADY_SUSPENDED,
+        /** Invalid parameters */
+        INVALID_PARAMS,
+        /** Maximum number of sessions reached */
+        MAX_SESSION_REACHED,
+        /** Requested operation is not available */
+        NOT_AVAILABLE,
+        /** Requested operation is not supported */
+        NOT_SUPPORTED,
+        /** Requested operation is not supported by the peer */
+        PEER_NOT_SUPPORTED,
+        /** Requested operation is rejected by the peer */
+        PEER_REJECTED,
+        /** Requested operation is timed out */
+        TIMEOUT,
+    }
+
+    @VintfStability
+    @Backing(type="byte")
+    enum TwtTeardownReasonCode {
+        /** Unknown reason */
+        UNKNOWN,
+        /** Teardown requested by the framework */
+        LOCALLY_REQUESTED,
+        /** Teardown initiated internally by the firmware or driver */
+        INTERNALLY_INITIATED,
+        /** Teardown initiated by the peer */
+        PEER_INITIATED,
+    }
+
+    /**
+     * Called to indicate a TWT failure. If there is no command associated with this failure cmdId
+     * will be 0.
+     *
+     * @param cmdId Id used to identify the command. The value 0 indicates no associated command.
+     * @param error error code.
+     */
+    void onTwtFailure(in int cmdId, in TwtErrorCode error);
+
+    /**
+     * Called when a Target Wake Time session is created. See |IWifiStaIface.twtSessionSetup|.
+     *
+     * @param cmdId Id used to identify the command.
+     * @param twtSession TWT session.
+     */
+    void onTwtSessionCreate(in int cmdId, in TwtSession twtSession);
+
+    /**
+     * Called when a Target Wake Time session is updated. See |IWifiStaIface.twtSessionUpdate|.
+     *
+     * @param cmdId Id used to identify the command.
+     * @param twtSession TWT session.
+     */
+    void onTwtSessionUpdate(in int cmdId, in TwtSession twtSession);
+
+    /**
+     * Called when the Target Wake Time session is torndown.
+     * See |IWifiStaIface.twtSessionTeardown|.
+     *
+     * @param cmdId Id used to identify the command. The value 0 indicates no associated command.
+     * @param twtSessionId TWT session id.
+     * @param reasonCode reason code for the TWT teardown.
+     */
+    void onTwtSessionTeardown(
+            in int cmdId, in int twtSessionId, in TwtTeardownReasonCode reasonCode);
+
+    /**
+     * Called when TWT session stats available. See |IWifiStaIface.twtSessionGetStats|.
+     *
+     * @param cmdId Id used to identify the command.
+     * @param twtSessionId TWT session id.
+     * @param twtSessionStats TWT session stats.
+     */
+    void onTwtSessionStats(in int cmdId, in int twtSessionId, in TwtSessionStats twtSessionStats);
+
+    /**
+     * Called when the Target Wake Time session is suspended.
+     * See |IWifiStaIface.twtSessionSuspend|.
+     *
+     * @param cmdId Id used to identify the command. The value 0 indicates no associated command.
+     * @param twtSessionId TWT session id.
+     */
+    void onTwtSessionSuspend(in int cmdId, in int twtSessionId);
+
+    /**
+     * Called when the Target Wake Time session is resumed. See |IWifiStaIface.twtSessionResume|.
+     *
+     * @param cmdId Id used to identify the command. The value 0 indicates no associated command.
+     * @param twtSessionId TWT session id.
+     */
+    void onTwtSessionResume(in int cmdId, in int twtSessionId);
 }
diff --git a/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl b/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl
new file mode 100644
index 0000000..9007d0e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Target Wake Time (TWT) Capabilities supported.
+ */
+@VintfStability
+parcelable TwtCapabilities {
+    /**
+     * Whether the TWT requester mode supported.
+     */
+    boolean isTwtRequesterSupported;
+    /**
+     * Whether the TWT responder mode supported.
+     */
+    boolean isTwtResponderSupported;
+    /**
+     * Whether the Broadcast TWT mode (TWT scheduling STA) supported.
+     */
+    boolean isBroadcastTwtSupported;
+    /**
+     * Whether supports Flexible TWT schedules.
+     */
+    boolean isFlexibleTwtScheduleSupported;
+    /**
+     * Minimum TWT wake duration in microseconds.
+     */
+    int minWakeDurationMicros;
+    /**
+     * Maximum TWT wake duration in microseconds.
+     */
+    int maxWakeDurationMicros;
+    /**
+     * Minimum TWT wake interval in microseconds.
+     */
+    int minWakeIntervalMicros;
+    /**
+     * Maximum TWT wake interval in microseconds.
+     */
+    int maxWakeIntervalMicros;
+}
diff --git a/wifi/aidl/android/hardware/wifi/TwtRequest.aidl b/wifi/aidl/android/hardware/wifi/TwtRequest.aidl
new file mode 100644
index 0000000..5191713
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/TwtRequest.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Target Wake Time (TWT) Request
+ */
+@VintfStability
+parcelable TwtRequest {
+    /**
+     * MLO Link id in case TWT is requesting for MLO connection. Otherwise -1.
+     */
+    int mloLinkId;
+    /**
+     * Minimum TWT wake duration in microseconds.
+     */
+    int minWakeDurationMicros;
+    /**
+     * Maximum TWT wake duration in microseconds.
+     */
+    int maxWakeDurationMicros;
+    /**
+     * Minimum TWT wake interval in microseconds.
+     */
+    int minWakeIntervalMicros;
+    /**
+     * Maximum TWT wake interval in microseconds.
+     */
+    int maxWakeIntervalMicros;
+}
diff --git a/wifi/aidl/android/hardware/wifi/TwtSession.aidl b/wifi/aidl/android/hardware/wifi/TwtSession.aidl
new file mode 100644
index 0000000..5a7ddb1
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/TwtSession.aidl
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Target Wake Time (TWT) Session
+ */
+@VintfStability
+parcelable TwtSession {
+    @VintfStability
+    @Backing(type="byte")
+    enum TwtNegotiationType {
+        INDIVIDUAL = 0,
+        BROADCAST = 1,
+    }
+
+    /**
+     * An unique identifier for the session.
+     */
+    int sessionId;
+
+    /**
+     * MLO Link id in case of MLO connection. Otherwise -1.
+     */
+    int mloLinkId;
+
+    /**
+     * TWT service period in microseconds.
+     */
+    int wakeDurationMicros;
+
+    /**
+     * Time interval in microseconds between two successive TWT service periods.
+     */
+    int wakeIntervalMicros;
+
+    /**
+     * TWT negotiation type.
+     */
+    TwtNegotiationType negotiationType;
+
+    /**
+     * Whether the TWT session is trigger enabled or non-trigger enabled.
+     */
+    boolean isTriggerEnabled;
+
+    /**
+     * Whether the TWT session is announced or unannounced.
+     */
+    boolean isAnnounced;
+
+    /**
+     * Whether the TWT session is implicit or explicit.
+     */
+    boolean isImplicit;
+
+    /**
+     * Whether the TWT session is protected or not.
+     */
+    boolean isProtected;
+
+    /**
+     * Whether the TWT session can be updated.
+     */
+    boolean isUpdatable;
+
+    /**
+     * Whether the TWT session can be suspended and then resumed.
+     */
+    boolean isSuspendable;
+
+    /**
+     * Whether AP (TWT responder) intends to go to doze state outside of TWT Service Periods.
+     *
+     * Refer IEEE 802.11 spec, Section 10.47.7 (TWT Sleep Setup).
+     */
+    boolean isResponderPmModeEnabled;
+}
diff --git a/wifi/aidl/android/hardware/wifi/TwtSessionStats.aidl b/wifi/aidl/android/hardware/wifi/TwtSessionStats.aidl
new file mode 100644
index 0000000..e2e2d12
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/TwtSessionStats.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Target Wake Time (TWT) Session Stats
+ */
+@VintfStability
+parcelable TwtSessionStats {
+    /**
+     * Average number of Tx packets in each wake duration.
+     */
+    int avgTxPktCount;
+
+    /**
+     * Average number of Rx packets in each wake duration.
+     */
+    int avgRxPktCount;
+
+    /**
+     * Average bytes per Tx packets in each wake duration.
+     */
+    int avgTxPktSize;
+
+    /**
+     * Average bytes per Rx packets in each wake duration.
+     */
+    int avgRxPktSize;
+
+    /**
+     * Average End of Service period in microseconds.
+     */
+    int avgEospDurationMicros;
+
+    /**
+     * Count of early terminations.
+     */
+    int eospCount;
+}
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index 8ecfcea..b62b3a0 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -3576,6 +3576,132 @@
     return WifiRatePreamble::OFDM;
 }
 
+bool convertTwtCapabilitiesToAidl(legacy_hal::wifi_twt_capabilities legacy_twt_capabs,
+                                  TwtCapabilities* aidl_twt_capabs) {
+    if (!aidl_twt_capabs) {
+        return false;
+    }
+    aidl_twt_capabs->isTwtRequesterSupported = legacy_twt_capabs.is_twt_requester_supported;
+    aidl_twt_capabs->isTwtResponderSupported = legacy_twt_capabs.is_twt_responder_supported;
+    aidl_twt_capabs->isBroadcastTwtSupported = legacy_twt_capabs.is_flexible_twt_supported;
+    if (legacy_twt_capabs.min_wake_duration_micros > legacy_twt_capabs.max_wake_duration_micros) {
+        return false;
+    }
+    aidl_twt_capabs->minWakeDurationMicros = legacy_twt_capabs.min_wake_duration_micros;
+    aidl_twt_capabs->maxWakeDurationMicros = legacy_twt_capabs.max_wake_duration_micros;
+    if (legacy_twt_capabs.min_wake_interval_micros > legacy_twt_capabs.max_wake_interval_micros) {
+        return false;
+    }
+    aidl_twt_capabs->minWakeIntervalMicros = legacy_twt_capabs.min_wake_interval_micros;
+    aidl_twt_capabs->maxWakeIntervalMicros = legacy_twt_capabs.max_wake_interval_micros;
+    return true;
+}
+
+bool convertAidlTwtRequestToLegacy(const TwtRequest aidl_twt_request,
+                                   legacy_hal::wifi_twt_request* legacy_twt_request) {
+    if (legacy_twt_request == nullptr) {
+        return false;
+    }
+    legacy_twt_request->mlo_link_id = aidl_twt_request.mloLinkId;
+    if (aidl_twt_request.minWakeDurationMicros > aidl_twt_request.maxWakeDurationMicros) {
+        return false;
+    }
+    legacy_twt_request->min_wake_duration_micros = aidl_twt_request.minWakeDurationMicros;
+    legacy_twt_request->max_wake_duration_micros = aidl_twt_request.maxWakeDurationMicros;
+    if (aidl_twt_request.minWakeIntervalMicros > aidl_twt_request.maxWakeIntervalMicros) {
+        return false;
+    }
+    legacy_twt_request->min_wake_interval_micros = aidl_twt_request.minWakeIntervalMicros;
+    legacy_twt_request->max_wake_interval_micros = aidl_twt_request.maxWakeIntervalMicros;
+    return true;
+}
+
+IWifiStaIfaceEventCallback::TwtErrorCode convertLegacyHalTwtErrorCodeToAidl(
+        legacy_hal::wifi_twt_error_code legacy_error_code) {
+    switch (legacy_error_code) {
+        case WIFI_TWT_ERROR_CODE_TIMEOUT:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::TIMEOUT;
+        case WIFI_TWT_ERROR_CODE_PEER_REJECTED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::PEER_REJECTED;
+        case WIFI_TWT_ERROR_CODE_PEER_NOT_SUPPORTED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::PEER_NOT_SUPPORTED;
+        case WIFI_TWT_ERROR_CODE_NOT_SUPPORTED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::NOT_SUPPORTED;
+        case WIFI_TWT_ERROR_CODE_NOT_AVAILABLE:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::NOT_AVAILABLE;
+        case WIFI_TWT_ERROR_CODE_MAX_SESSION_REACHED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::MAX_SESSION_REACHED;
+        case WIFI_TWT_ERROR_CODE_INVALID_PARAMS:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::INVALID_PARAMS;
+        case WIFI_TWT_ERROR_CODE_ALREADY_SUSPENDED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::ALREADY_SUSPENDED;
+        case WIFI_TWT_ERROR_CODE_ALREADY_RESUMED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::ALREADY_RESUMED;
+        default:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::FAILURE_UNKNOWN;
+    }
+}
+
+IWifiStaIfaceEventCallback::TwtTeardownReasonCode convertLegacyHalTwtReasonCodeToAidl(
+        legacy_hal::wifi_twt_teardown_reason_code legacy_reason_code) {
+    switch (legacy_reason_code) {
+        case WIFI_TWT_TEARDOWN_REASON_CODE_LOCALLY_REQUESTED:
+            return IWifiStaIfaceEventCallback::TwtTeardownReasonCode::LOCALLY_REQUESTED;
+        case WIFI_TWT_TEARDOWN_REASON_CODE_INTERNALLY_INITIATED:
+            return IWifiStaIfaceEventCallback::TwtTeardownReasonCode::INTERNALLY_INITIATED;
+        case WIFI_TWT_TEARDOWN_REASON_CODE_PEER_INITIATED:
+            return IWifiStaIfaceEventCallback::TwtTeardownReasonCode::PEER_INITIATED;
+        default:
+            return IWifiStaIfaceEventCallback::TwtTeardownReasonCode::UNKNOWN;
+    }
+}
+
+bool convertLegacyHalTwtSessionToAidl(legacy_hal::wifi_twt_session twt_session,
+                                      TwtSession* aidl_twt_session) {
+    if (aidl_twt_session == nullptr) {
+        return false;
+    }
+
+    aidl_twt_session->sessionId = twt_session.session_id;
+    aidl_twt_session->mloLinkId = twt_session.mlo_link_id;
+    aidl_twt_session->wakeDurationMicros = twt_session.wake_duration_micros;
+    aidl_twt_session->wakeIntervalMicros = twt_session.wake_interval_micros;
+    switch (twt_session.negotiation_type) {
+        case WIFI_TWT_NEGO_TYPE_INDIVIDUAL:
+            aidl_twt_session->negotiationType = TwtSession::TwtNegotiationType::INDIVIDUAL;
+            break;
+        case WIFI_TWT_NEGO_TYPE_BROADCAST:
+            aidl_twt_session->negotiationType = TwtSession::TwtNegotiationType::BROADCAST;
+            break;
+        default:
+            return false;
+    }
+    aidl_twt_session->isTriggerEnabled = twt_session.is_trigger_enabled;
+    aidl_twt_session->isAnnounced = twt_session.is_announced;
+    aidl_twt_session->isImplicit = twt_session.is_implicit;
+    aidl_twt_session->isProtected = twt_session.is_protected;
+    aidl_twt_session->isUpdatable = twt_session.is_updatable;
+    aidl_twt_session->isSuspendable = twt_session.is_suspendable;
+    aidl_twt_session->isResponderPmModeEnabled = twt_session.is_responder_pm_mode_enabled;
+    return true;
+}
+
+bool convertLegacyHalTwtSessionStatsToAidl(legacy_hal::wifi_twt_session_stats twt_stats,
+                                           TwtSessionStats* aidl_twt_stats) {
+    if (aidl_twt_stats == nullptr) {
+        return false;
+    }
+
+    aidl_twt_stats->avgTxPktCount = twt_stats.avg_pkt_num_tx;
+    aidl_twt_stats->avgRxPktCount = twt_stats.avg_pkt_num_rx;
+    aidl_twt_stats->avgTxPktSize = twt_stats.avg_tx_pkt_size;
+    aidl_twt_stats->avgRxPktSize = twt_stats.avg_rx_pkt_size;
+    aidl_twt_stats->avgEospDurationMicros = twt_stats.avg_eosp_dur_us;
+    aidl_twt_stats->eospCount = twt_stats.eosp_count;
+
+    return true;
+}
+
 }  // namespace aidl_struct_util
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wifi/aidl/default/aidl_struct_util.h b/wifi/aidl/default/aidl_struct_util.h
index 1942b5f..7089363 100644
--- a/wifi/aidl/default/aidl_struct_util.h
+++ b/wifi/aidl/default/aidl_struct_util.h
@@ -218,6 +218,18 @@
 bool convertCachedScanResultToAidl(const legacy_hal::wifi_cached_scan_result& legacy_scan_result,
                                    uint64_t ts_us, CachedScanResult* aidl_scan_result);
 WifiRatePreamble convertScanResultFlagsToPreambleType(int flags);
+bool convertTwtCapabilitiesToAidl(const legacy_hal::wifi_twt_capabilities legacy_twt_capabs,
+                                  TwtCapabilities* aidl_twt_capabs);
+bool convertAidlTwtRequestToLegacy(const TwtRequest aidl_twt_request,
+                                   legacy_hal::wifi_twt_request* legacy_twt_request);
+IWifiStaIfaceEventCallback::TwtErrorCode convertLegacyHalTwtErrorCodeToAidl(
+        legacy_hal::wifi_twt_error_code legacy_error_code);
+IWifiStaIfaceEventCallback::TwtTeardownReasonCode convertLegacyHalTwtReasonCodeToAidl(
+        legacy_hal::wifi_twt_teardown_reason_code legacy_reason_code);
+bool convertLegacyHalTwtSessionToAidl(legacy_hal::wifi_twt_session twt_session,
+                                      TwtSession* aidl_twt_session);
+bool convertLegacyHalTwtSessionStatsToAidl(legacy_hal::wifi_twt_session_stats twt_stats,
+                                           TwtSessionStats* aidl_twt_stats);
 }  // namespace aidl_struct_util
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp
index 2e80183..55d6f59 100644
--- a/wifi/aidl/default/wifi_legacy_hal.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -457,6 +457,76 @@
     }
 }
 
+// Callback to be invoked for TWT failure
+std::function<void((wifi_request_id, wifi_twt_error_code error_code))>
+        on_twt_failure_internal_callback;
+void onAsyncTwtError(wifi_request_id id, wifi_twt_error_code error_code) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_failure_internal_callback) {
+        on_twt_failure_internal_callback(id, error_code);
+    }
+}
+
+// Callback to be invoked for TWT session creation
+std::function<void((wifi_request_id, wifi_twt_session twt_session))>
+        on_twt_session_create_internal_callback;
+void onAsyncTwtSessionCreate(wifi_request_id id, wifi_twt_session twt_session) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_create_internal_callback) {
+        on_twt_session_create_internal_callback(id, twt_session);
+    }
+}
+
+// Callback to be invoked for TWT session update
+std::function<void((wifi_request_id, wifi_twt_session twt_session))>
+        on_twt_session_update_internal_callback;
+void onAsyncTwtSessionUpdate(wifi_request_id id, wifi_twt_session twt_session) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_update_internal_callback) {
+        on_twt_session_update_internal_callback(id, twt_session);
+    }
+}
+
+// Callback to be invoked for TWT session teardown
+std::function<void(
+        (wifi_request_id, int twt_session_id, wifi_twt_teardown_reason_code reason_code))>
+        on_twt_session_teardown_internal_callback;
+void onAsyncTwtSessionTeardown(wifi_request_id id, int twt_session_id,
+                               wifi_twt_teardown_reason_code reason_code) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_teardown_internal_callback) {
+        on_twt_session_teardown_internal_callback(id, twt_session_id, reason_code);
+    }
+}
+
+// Callback to be invoked for TWT session get stats
+std::function<void((wifi_request_id, int twt_session_id, wifi_twt_session_stats stats))>
+        on_twt_session_stats_internal_callback;
+void onAsyncTwtSessionStats(wifi_request_id id, int twt_session_id, wifi_twt_session_stats stats) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_stats_internal_callback) {
+        on_twt_session_stats_internal_callback(id, twt_session_id, stats);
+    }
+}
+
+// Callback to be invoked for TWT session suspend
+std::function<void((wifi_request_id, int twt_session_id))> on_twt_session_suspend_internal_callback;
+void onAsyncTwtSessionSuspend(wifi_request_id id, int twt_session_id) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_suspend_internal_callback) {
+        on_twt_session_suspend_internal_callback(id, twt_session_id);
+    }
+}
+
+// Callback to be invoked for TWT session resume
+std::function<void((wifi_request_id, int twt_session_id))> on_twt_session_resume_internal_callback;
+void onAsyncTwtSessionResume(wifi_request_id id, int twt_session_id) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_resume_internal_callback) {
+        on_twt_session_resume_internal_callback(id, twt_session_id);
+    }
+}
+
 // End of the free-standing "C" style callbacks.
 
 WifiLegacyHal::WifiLegacyHal(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
@@ -1789,6 +1859,103 @@
     return global_func_table_.wifi_set_voip_mode(getIfaceHandle(iface_name), mode);
 }
 
+std::pair<wifi_twt_capabilities, wifi_error> WifiLegacyHal::twtGetCapabilities(
+        const std::string& ifaceName) {
+    wifi_twt_capabilities capabs = {};
+    wifi_error status =
+            global_func_table_.wifi_twt_get_capabilities(getIfaceHandle(ifaceName), &capabs);
+    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,
+        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) {
+    if (on_twt_failure_internal_callback || on_twt_session_create_internal_callback ||
+        on_twt_session_update_internal_callback || on_twt_session_teardown_internal_callback ||
+        on_twt_session_stats_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    on_twt_failure_internal_callback = [on_twt_failure_user_callback](
+                                               wifi_request_id id, wifi_twt_error_code error_code) {
+        on_twt_failure_user_callback(id, error_code);
+    };
+
+    on_twt_session_create_internal_callback = [on_twt_session_create_user_callback](
+                                                      wifi_request_id id,
+                                                      wifi_twt_session twt_session) {
+        on_twt_session_create_user_callback(id, twt_session);
+    };
+
+    on_twt_session_update_internal_callback = [on_twt_session_update_user_callback](
+                                                      wifi_request_id id,
+                                                      wifi_twt_session twt_session) {
+        on_twt_session_update_user_callback(id, twt_session);
+    };
+
+    on_twt_session_teardown_internal_callback = [on_twt_session_teardown_user_callback](
+                                                        wifi_request_id id, int session_id,
+                                                        wifi_twt_teardown_reason_code reason_code) {
+        on_twt_session_teardown_user_callback(id, session_id, reason_code);
+    };
+
+    on_twt_session_stats_internal_callback = [on_twt_session_stats_user_callback](
+                                                     wifi_request_id id, int session_id,
+                                                     wifi_twt_session_stats stats) {
+        on_twt_session_stats_user_callback(id, session_id, stats);
+    };
+
+    on_twt_session_suspend_internal_callback = [on_twt_session_suspend_user_callback](
+                                                       wifi_request_id id, int session_id) {
+        on_twt_session_suspend_user_callback(id, session_id);
+    };
+
+    on_twt_session_resume_internal_callback = [on_twt_session_resume_user_callback](
+                                                      wifi_request_id id, int session_id) {
+        on_twt_session_resume_user_callback(id, session_id);
+    };
+
+    return global_func_table_.wifi_twt_session_setup(
+            cmdId, getIfaceHandle(ifaceName), request,
+            {onAsyncTwtError, onAsyncTwtSessionCreate, onAsyncTwtSessionUpdate,
+             onAsyncTwtSessionTeardown, onAsyncTwtSessionStats, onAsyncTwtSessionSuspend,
+             onAsyncTwtSessionResume});
+}
+
+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,
+                                                      request);
+}
+
+wifi_error WifiLegacyHal::twtSessionSuspend(const std::string& ifaceName, uint32_t cmdId,
+                                            uint32_t sessionId) {
+    return global_func_table_.wifi_twt_session_suspend(cmdId, getIfaceHandle(ifaceName), sessionId);
+}
+
+wifi_error WifiLegacyHal::twtSessionResume(const std::string& ifaceName, uint32_t cmdId,
+                                           uint32_t sessionId) {
+    return global_func_table_.wifi_twt_session_resume(cmdId, getIfaceHandle(ifaceName), sessionId);
+}
+
+wifi_error WifiLegacyHal::twtSessionTeardown(const std::string& ifaceName, uint32_t cmdId,
+                                             uint32_t sessionId) {
+    return global_func_table_.wifi_twt_session_teardown(cmdId, getIfaceHandle(ifaceName),
+                                                        sessionId);
+}
+
+wifi_error WifiLegacyHal::twtSessionGetStats(const std::string& ifaceName, uint32_t cmdId,
+                                             uint32_t sessionId) {
+    return global_func_table_.wifi_twt_session_get_stats(cmdId, getIfaceHandle(ifaceName),
+                                                         sessionId);
+}
+
 wifi_error WifiLegacyHal::twtRegisterHandler(const std::string& iface_name,
                                              const TwtCallbackHandlers& user_callbacks) {
     on_twt_event_setup_response_callback = user_callbacks.on_setup_response;
diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h
index 17509df..121d1b5 100644
--- a/wifi/aidl/default/wifi_legacy_hal.h
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -376,6 +376,13 @@
 using ::WIFI_SCAN_FLAG_INTERRUPTED;
 using ::wifi_scan_result;
 using ::WIFI_SUCCESS;
+using ::wifi_twt_capabilities;
+using ::wifi_twt_error_code;
+using ::wifi_twt_events;
+using ::wifi_twt_request;
+using ::wifi_twt_session;
+using ::wifi_twt_session_stats;
+using ::wifi_twt_teardown_reason_code;
 using ::wifi_tx_packet_fate;
 using ::wifi_tx_report;
 using ::wifi_usable_channel;
@@ -555,6 +562,16 @@
     std::function<void(wifi_cached_scan_report*)> on_cached_scan_results;
 };
 
+using on_twt_failure = std::function<void(wifi_request_id id, wifi_twt_error_code error_code)>;
+using on_twt_session_create = std::function<void(wifi_request_id id, wifi_twt_session twt_session)>;
+using on_twt_session_update = std::function<void(wifi_request_id id, wifi_twt_session twt_session)>;
+using on_twt_session_teardown = std::function<void(wifi_request_id id, int session_id,
+                                                   wifi_twt_teardown_reason_code reason_code)>;
+using on_twt_session_stats =
+        std::function<void(wifi_request_id id, int session_id, wifi_twt_session_stats stats)>;
+using on_twt_session_suspend = std::function<void(wifi_request_id id, int session_id)>;
+using on_twt_session_resume = std::function<void(wifi_request_id id, int session_id)>;
+
 /**
  * Class that encapsulates all legacy HAL interactions.
  * This class manages the lifetime of the event loop thread used by legacy HAL.
@@ -761,19 +778,39 @@
 
     wifi_error setVoipMode(const std::string& iface_name, wifi_voip_mode mode);
 
+    // TWT functions
+    std::pair<wifi_twt_capabilities, wifi_error> twtGetCapabilities(const std::string& ifaceName);
+    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);
+    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);
+    wifi_error twtSessionResume(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId);
+    wifi_error twtSessionTeardown(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId);
+    wifi_error twtSessionGetStats(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId);
+
+    // Note: Following TWT functions are deprecated
+    // Deprecated
     wifi_error twtRegisterHandler(const std::string& iface_name,
                                   const TwtCallbackHandlers& handler);
-
+    // Deprecated by twtGetCapabilities
     std::pair<wifi_error, TwtCapabilitySet> twtGetCapability(const std::string& iface_name);
-
+    // Deprecated by twtSessionSetup
     wifi_error twtSetupRequest(const std::string& iface_name, const TwtSetupRequest& msg);
-
+    // Deprecated by twtSessionTeardown
     wifi_error twtTearDownRequest(const std::string& iface_name, const TwtTeardownRequest& msg);
-
+    // Deprecated by twtSessionSuspend and twtSessionResume
     wifi_error twtInfoFrameRequest(const std::string& iface_name, const TwtInfoFrameRequest& msg);
-
+    // Deprecated by twtSessionGetStats
     std::pair<wifi_error, TwtStats> twtGetStats(const std::string& iface_name, uint8_t configId);
-
+    // Deprecated
     wifi_error twtClearStats(const std::string& iface_name, uint8_t configId);
 
     wifi_error setScanMode(const std::string& iface_name, bool enable);
diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
index 3d59c65..3e4afd0 100644
--- a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -181,6 +181,13 @@
     populateStubFor(&hal_fn->wifi_get_supported_iface_concurrency_matrix);
     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_session_setup);
+    populateStubFor(&hal_fn->wifi_twt_session_update);
+    populateStubFor(&hal_fn->wifi_twt_session_suspend);
+    populateStubFor(&hal_fn->wifi_twt_session_resume);
+    populateStubFor(&hal_fn->wifi_twt_session_teardown);
+    populateStubFor(&hal_fn->wifi_twt_session_get_stats);
     return true;
 }
 
diff --git a/wifi/aidl/default/wifi_sta_iface.cpp b/wifi/aidl/default/wifi_sta_iface.cpp
index 0ae428f..f0509dc 100644
--- a/wifi/aidl/default/wifi_sta_iface.cpp
+++ b/wifi/aidl/default/wifi_sta_iface.cpp
@@ -224,6 +224,44 @@
                            &WifiStaIface::getCachedScanDataInternal, _aidl_return);
 }
 
+ndk::ScopedAStatus WifiStaIface::twtGetCapabilities(TwtCapabilities* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtGetCapabilitiesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionSetup(int32_t in_cmdId,
+                                                 const TwtRequest& in_twtRequest) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionSetupInternal, in_cmdId, in_twtRequest);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionUpdate(int32_t in_cmdId, int32_t in_sessionId,
+                                                  const TwtRequest& in_twtRequest) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionUpdateInternal, in_cmdId, in_sessionId,
+                           in_twtRequest);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionSuspend(int32_t in_cmdId, int32_t in_sessionId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionSuspendInternal, in_cmdId, in_sessionId);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionResume(int32_t in_cmdId, int32_t in_sessionId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionResumeInternal, in_cmdId, in_sessionId);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionTeardown(int32_t in_cmdId, int32_t in_sessionId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionTeardownInternal, in_cmdId, in_sessionId);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionGetStats(int32_t in_cmdId, int32_t in_sessionId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionGetStatsInternal, in_cmdId, in_sessionId);
+}
+
 std::pair<std::string, ndk::ScopedAStatus> WifiStaIface::getNameInternal() {
     return {ifname_, ndk::ScopedAStatus::ok()};
 }
@@ -560,6 +598,194 @@
     return {aidl_scan_data, ndk::ScopedAStatus::ok()};
 }
 
+std::pair<TwtCapabilities, ndk::ScopedAStatus> WifiStaIface::twtGetCapabilitiesInternal() {
+    legacy_hal::wifi_twt_capabilities legacyHaltwtCapabilities;
+    legacy_hal::wifi_error legacy_status;
+    std::tie(legacyHaltwtCapabilities, legacy_status) =
+            legacy_hal_.lock()->twtGetCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {TwtCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    TwtCapabilities aidlTwtCapabilities;
+    if (!aidl_struct_util::convertTwtCapabilitiesToAidl(legacyHaltwtCapabilities,
+                                                        &aidlTwtCapabilities)) {
+        return {TwtCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+    }
+    return {aidlTwtCapabilities, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionSetupInternal(int32_t cmdId,
+                                                         const TwtRequest& aidlTwtRequest) {
+    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);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionUpdateInternal(int32_t cmdId, int32_t sessionId,
+                                                          const TwtRequest& aidlTwtRequest) {
+    legacy_hal::wifi_twt_request legacyHalTwtRequest;
+    if (!aidl_struct_util::convertAidlTwtRequestToLegacy(aidlTwtRequest, &legacyHalTwtRequest)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionUpdate(ifname_, cmdId, sessionId, legacyHalTwtRequest);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionSuspendInternal(int32_t cmdId, int32_t sessionId) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionSuspend(ifname_, cmdId, sessionId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionResumeInternal(int32_t cmdId, int32_t sessionId) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionResume(ifname_, cmdId, sessionId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionTeardownInternal(int32_t cmdId, int32_t sessionId) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionTeardown(ifname_, cmdId, sessionId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionGetStatsInternal(int32_t cmdId, int32_t sessionId) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionGetStats(ifname_, cmdId, sessionId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/aidl/default/wifi_sta_iface.h b/wifi/aidl/default/wifi_sta_iface.h
index fe05c21..eb8f745 100644
--- a/wifi/aidl/default/wifi_sta_iface.h
+++ b/wifi/aidl/default/wifi_sta_iface.h
@@ -91,6 +91,14 @@
     ndk::ScopedAStatus setScanMode(bool in_enable) override;
     ndk::ScopedAStatus setDtimMultiplier(int32_t in_multiplier) override;
     ndk::ScopedAStatus getCachedScanData(CachedScanData* _aidl_return) override;
+    ndk::ScopedAStatus twtGetCapabilities(TwtCapabilities* _aidl_return) override;
+    ndk::ScopedAStatus twtSessionSetup(int in_cmdId, const TwtRequest& in_twtRequest) override;
+    ndk::ScopedAStatus twtSessionUpdate(int in_cmdId, int32_t in_sessionId,
+                                        const TwtRequest& in_twtRequest) override;
+    ndk::ScopedAStatus twtSessionSuspend(int in_cmdId, int32_t in_sessionId) override;
+    ndk::ScopedAStatus twtSessionResume(int in_cmdId, int32_t in_sessionId) override;
+    ndk::ScopedAStatus twtSessionTeardown(int in_cmdId, int32_t in_sessionId) override;
+    ndk::ScopedAStatus twtSessionGetStats(int in_cmdId, int32_t in_sessionId) override;
 
   private:
     // Corresponding worker functions for the AIDL methods.
@@ -132,6 +140,14 @@
     ndk::ScopedAStatus setScanModeInternal(bool enable);
     ndk::ScopedAStatus setDtimMultiplierInternal(const int multiplier);
     std::pair<CachedScanData, ndk::ScopedAStatus> getCachedScanDataInternal();
+    std::pair<TwtCapabilities, ndk::ScopedAStatus> twtGetCapabilitiesInternal();
+    ndk::ScopedAStatus twtSessionSetupInternal(int cmdId, const TwtRequest& twtRequest);
+    ndk::ScopedAStatus twtSessionUpdateInternal(int cmdId, int32_t sessionId,
+                                                const TwtRequest& twtRequest);
+    ndk::ScopedAStatus twtSessionSuspendInternal(int cmdId, int32_t sessionId);
+    ndk::ScopedAStatus twtSessionResumeInternal(int cmdId, int32_t sessionId);
+    ndk::ScopedAStatus twtSessionTeardownInternal(int cmdId, int32_t sessionId);
+    ndk::ScopedAStatus twtSessionGetStatsInternal(int cmdId, int32_t sessionId);
 
     void setWeakPtr(std::weak_ptr<WifiStaIface> ptr);
 
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
index 1f3aa48..917668e 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -101,5 +101,7 @@
   android.hardware.wifi.supplicant.SignalPollResult[] getSignalPollResults();
   android.hardware.wifi.supplicant.QosPolicyScsRequestStatus[] addQosPolicyRequestForScs(in android.hardware.wifi.supplicant.QosPolicyScsData[] qosPolicyData);
   android.hardware.wifi.supplicant.QosPolicyScsRequestStatus[] removeQosPolicyForScs(in byte[] scsPolicyIds);
+  void configureMscs(in android.hardware.wifi.supplicant.MscsParams params);
+  void disableMscs();
   const int MAX_POLICIES_PER_QOS_SCS_REQUEST = 16;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MscsParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MscsParams.aidl
new file mode 100644
index 0000000..aeed408
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MscsParams.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable MscsParams {
+  byte upBitmap;
+  byte upLimit;
+  int streamTimeoutUs;
+  byte frameClassifierMask;
+  @Backing(type="int") @VintfStability
+  enum FrameClassifierFields {
+    IP_VERSION = (1 << 0) /* 1 */,
+    SRC_IP_ADDR = (1 << 1) /* 2 */,
+    DST_IP_ADDR = (1 << 2) /* 4 */,
+    SRC_PORT = (1 << 3) /* 8 */,
+    DST_PORT = (1 << 4) /* 16 */,
+    DSCP = (1 << 5) /* 32 */,
+    PROTOCOL_NEXT_HDR = (1 << 6) /* 64 */,
+    FLOW_LABEL = (1 << 7) /* 128 */,
+  }
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
index d7b4e62..fb1673e 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -29,6 +29,7 @@
 import android.hardware.wifi.supplicant.IfaceType;
 import android.hardware.wifi.supplicant.KeyMgmtMask;
 import android.hardware.wifi.supplicant.MloLinksInfo;
+import android.hardware.wifi.supplicant.MscsParams;
 import android.hardware.wifi.supplicant.QosPolicyScsData;
 import android.hardware.wifi.supplicant.QosPolicyScsRequestStatus;
 import android.hardware.wifi.supplicant.QosPolicyStatus;
@@ -852,4 +853,28 @@
      *          being processed. Supplicant will only handle one request at a time.
      */
     QosPolicyScsRequestStatus[] removeQosPolicyForScs(in byte[] scsPolicyIds);
+
+    /**
+     * Enable Mirrored Stream Classification Service (MSCS) and configure using
+     * the provided configuration values.
+     *
+     * If MSCS has already been enabled/configured, this will overwrite the
+     * existing configuration.
+     *
+     * @param params |MscsParams| object containing the configuration.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID| if the configuration is invalid.
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN| if the configuration could not be set.
+     */
+    void configureMscs(in MscsParams params);
+
+    /**
+     * Disable Mirrored Stream Classification Service (MSCS).
+     *
+     * If MSCS is enabled/configured, this will send a remove request to the AP.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void disableMscs();
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MscsParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MscsParams.aidl
new file mode 100644
index 0000000..b1731ac
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MscsParams.aidl
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Mirrored Stream Classification Service (MSCS) parameters.
+ * Refer to section 3.1 of the Wi-Fi QoS Management Specification v3.0.
+ */
+@VintfStability
+parcelable MscsParams {
+    /**
+     * Bitmap indicating which User Priorities should be classified using MSCS.
+     * The least significant bit corresponds to UP 0, and the most significant
+     * bit to UP 7. Setting a bit to 1 indicates that UP should be used.
+     */
+    byte upBitmap;
+
+    /**
+     * Maximum user priority that can be assigned using the MSCS service.
+     * Value must be between 0 and 7 (inclusive).
+     */
+    byte upLimit;
+
+    /**
+     * Stream timeout in μs. Must be equivalent to 60 sec or less.
+     */
+    int streamTimeoutUs;
+
+    /**
+     * Bitmask of available fields for a Type 4 TCLAS frame classifier.
+     * See Figures 9-309 and 9-310 in the IEEE Std 802.11-2020 Standard.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum FrameClassifierFields {
+        IP_VERSION = 1 << 0,
+        SRC_IP_ADDR = 1 << 1,
+        DST_IP_ADDR = 1 << 2,
+        SRC_PORT = 1 << 3,
+        DST_PORT = 1 << 4,
+        DSCP = 1 << 5,
+        /** Indicates Protocol if using IPv4, or Next Header if using IPv6. */
+        PROTOCOL_NEXT_HDR = 1 << 6,
+        /** Only applicable if using IPv6. */
+        FLOW_LABEL = 1 << 7,
+    }
+
+    /**
+     * Bitmask of |FrameClassifierFields| for a Type 4 TCLAS frame classifier.
+     */
+    byte frameClassifierMask;
+}