Merge "rename TRIGGER_CLEAR_RAT_BLOCK to _BLOCKS" into main
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 923d42a..966ff65 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
@@ -20,33 +20,41 @@
 @Backing(type="int")
 enum VehicleApPowerStateShutdownParam {
     /**
-     * AP must shutdown immediately. Postponing is not allowed.
+     * AP must shutdown without Garage mode. Postponing is not allowed.
+     * If AP need to shutdown as soon as possible, EMERGENCY_SHUTDOWN shall be used.
      */
     SHUTDOWN_IMMEDIATELY = 1,
     /**
      * AP can enter deep sleep instead of shutting down completely.
+     * AP can postpone entering deep sleep to run Garage mode.
      */
     CAN_SLEEP = 2,
     /**
-     * AP can only shutdown with postponing allowed.
+     * AP can only shutdown.
+     * AP can postpone shutdown to run Garage mode.
      */
     SHUTDOWN_ONLY = 3,
     /**
-     * AP may enter deep sleep, but must either sleep or shut down immediately.
+     * AP can enter deep sleep, without Garage mode.
      * Postponing is not allowed.
+     * Depending on the actual implementation, it may shut down immediately
      */
     SLEEP_IMMEDIATELY = 4,
     /**
-     * AP must hibernate (suspend to disk) immediately. Postponing is not allowed.
-     * Depending on the actual implementation, it may shut down immediately
+     * AP can hibernate (suspend to disk) without Garage mode.
+     * Postponing is not allowed.
+     * Depending on the actual implementation, it may shut down immediately.
      */
     HIBERNATE_IMMEDIATELY = 5,
     /**
      * AP can enter hibernation (suspend to disk) instead of shutting down completely.
+     * AP can postpone hibernation to run Garage mode.
      */
     CAN_HIBERNATE = 6,
     /**
-     * AP must shutdown (gracefully) without a delay.
+     * AP must shutdown (gracefully) without a delay. AP cannot run Garage mode.
+     * This type must be used only in critical situations when AP must shutdown as soon as possible.
+     * CarService will only notify listeners, but will not wait for completion reports.
      */
     EMERGENCY_SHUTDOWN = 7,
 }
diff --git a/bluetooth/audio/flags/Android.bp b/bluetooth/audio/flags/Android.bp
new file mode 100644
index 0000000..0d18a4d
--- /dev/null
+++ b/bluetooth/audio/flags/Android.bp
@@ -0,0 +1,12 @@
+aconfig_declarations {
+    name: "btaudiohal_flags",
+    package: "com.android.btaudio.hal.flags",
+    srcs: ["btaudiohal.aconfig"],
+}
+
+cc_aconfig_library {
+    name: "btaudiohal_flags_c_lib",
+    aconfig_declarations: "btaudiohal_flags",
+    vendor: true,
+    host_supported: true,
+}
diff --git a/bluetooth/audio/flags/btaudiohal.aconfig b/bluetooth/audio/flags/btaudiohal.aconfig
new file mode 100644
index 0000000..763777e
--- /dev/null
+++ b/bluetooth/audio/flags/btaudiohal.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.btaudio.hal.flags"
+
+flag {
+    name: "dsa_lea"
+    namespace: "pixel_bluetooth"
+    description: "Flag for DSA Over LEA"
+    bug: "270987427"
+}
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index f5f8163..c0817f5 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -63,6 +63,10 @@
         "libhidlbase",
         "libxml2",
         "libflatbuffers-cpp",
+        "server_configurable_flags",
+    ],
+    static_libs: [
+        "btaudiohal_flags_c_lib",
     ],
     generated_sources: ["le_audio_codec_capabilities"],
     generated_headers: [
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 3519ace..c057505 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -20,6 +20,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android/binder_manager.h>
+#include <com_android_btaudio_hal_flags.h>
 #include <hardware/audio.h>
 
 #include "BluetoothAudioSession.h"
@@ -36,6 +37,14 @@
 static constexpr int kWritePollMs = 1;  // polled non-blocking interval
 static constexpr int kReadPollMs = 1;   // polled non-blocking interval
 
+static std::string toString(const std::vector<LatencyMode>& latencies) {
+  std::stringstream latencyModesStr;
+  for (LatencyMode mode : latencies) {
+    latencyModesStr << " " << toString(mode);
+  }
+  return latencyModesStr.str();
+}
+
 BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
     : session_type_(session_type), stack_iface_(nullptr), data_mq_(nullptr) {}
 
@@ -65,6 +74,7 @@
     stack_iface_ = stack_iface;
     latency_modes_ = latency_modes;
     LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " - All LatencyModes=" << toString(latency_modes)
               << ", AudioConfiguration=" << audio_config.toString();
     ReportSessionStatus();
   }
@@ -604,31 +614,46 @@
     return std::vector<LatencyMode>();
   }
 
-  std::vector<LatencyMode> supported_latency_modes;
-  if (session_type_ ==
-      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
-    for (LatencyMode mode : latency_modes_) {
-      if (mode == LatencyMode::LOW_LATENCY) {
-        // LOW_LATENCY is not supported for LE_HARDWARE_OFFLOAD_ENC sessions
-        continue;
+  if (com::android::btaudio::hal::flags::dsa_lea()) {
+    std::vector<LatencyMode> supported_latency_modes;
+    if (session_type_ ==
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+      for (LatencyMode mode : latency_modes_) {
+        if (mode == LatencyMode::LOW_LATENCY) {
+          // LOW_LATENCY is not supported for LE_HARDWARE_OFFLOAD_ENC sessions
+          continue;
+        }
+        supported_latency_modes.push_back(mode);
       }
-      supported_latency_modes.push_back(mode);
+    } else {
+      for (LatencyMode mode : latency_modes_) {
+        if (!low_latency_allowed_ && mode == LatencyMode::LOW_LATENCY) {
+          // ignore LOW_LATENCY mode if Bluetooth stack doesn't allow
+          continue;
+        }
+        if (mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE ||
+            mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
+          // DSA_SW and DSA_HW only supported for LE_HARDWARE_OFFLOAD_ENC
+          // sessions
+          continue;
+        }
+        supported_latency_modes.push_back(mode);
+      }
     }
-  } else {
-    for (LatencyMode mode : latency_modes_) {
-      if (!low_latency_allowed_ && mode == LatencyMode::LOW_LATENCY) {
-        // ignore LOW_LATENCY mode if Bluetooth stack doesn't allow
-        continue;
-      }
-      if (mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE ||
-          mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
-        // DSA_SW and DSA_HW only supported for LE_HARDWARE_OFFLOAD_ENC sessions
-        continue;
-      }
-      supported_latency_modes.push_back(mode);
-    }
+    LOG(DEBUG) << __func__ << " - Supported LatencyMode="
+               << toString(supported_latency_modes);
+    return supported_latency_modes;
   }
-  return supported_latency_modes;
+
+  if (low_latency_allowed_) return latency_modes_;
+  std::vector<LatencyMode> modes;
+  for (LatencyMode mode : latency_modes_) {
+    if (mode == LatencyMode::LOW_LATENCY)
+      // ignore those low latency mode if Bluetooth stack doesn't allow
+      continue;
+    modes.push_back(mode);
+  }
+  return modes;
 }
 
 void BluetoothAudioSession::SetLatencyMode(const LatencyMode& latency_mode) {
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
index e7fad4d..8fc77ae 100644
--- a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
@@ -35,6 +35,7 @@
 @VintfStability
 parcelable ChannelSoudingRawData {
   int procedureCounter;
+  int[] frequencyCompensation;
   boolean aborted;
   android.hardware.bluetooth.ranging.ChannelSoundingSingleSideData initiatorData;
   android.hardware.bluetooth.ranging.ChannelSoundingSingleSideData reflectorData;
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
index 9fe85da..ddaba72 100644
--- a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
@@ -38,6 +38,7 @@
   @nullable byte[] packetQuality;
   @nullable byte[] packetRssiDbm;
   @nullable android.hardware.bluetooth.ranging.Nadm[] packetNadm;
+  @nullable int[] measuredFreqOffset;
   @nullable List<android.hardware.bluetooth.ranging.ComplexNumber> packetPct1;
   @nullable List<android.hardware.bluetooth.ranging.ComplexNumber> packetPct2;
   byte referencePowerDbm;
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl
index a51ba37..4125748 100644
--- a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl
@@ -36,6 +36,7 @@
 parcelable StepTonePct {
   List<android.hardware.bluetooth.ranging.ComplexNumber> tonePcts;
   byte[] toneQualityIndicator;
+  byte toneExtensionAntennaIndex;
   const int TONE_QUALITY_GOOD = 0;
   const int TONE_QUALITY_MEDIUM = 1;
   const int TONE_QUALITY_LOW = 2;
@@ -44,4 +45,9 @@
   const int EXTENSION_SLOT_TONE_NOT_EXPECTED_TO_BE_PRESENT = 1;
   const int EXTENSION_SLOT_TONE_EXPECTED_TO_BE_PRESENT = 2;
   const int EXTENSION_SLOT_SHIFT_AMOUNT = 4;
+  const byte TONE_EXTENSION_ANTENNA_1 = 0x0;
+  const byte TONE_EXTENSION_ANTENNA_2 = 0x1;
+  const byte TONE_EXTENSION_ANTENNA_3 = 0x2;
+  const byte TONE_EXTENSION_ANTENNA_4 = 0x3;
+  const byte TONE_EXTENSION_UNUSED = 0xFFu8;
 }
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
index 3c8a62f..0106865 100644
--- a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
@@ -29,6 +29,11 @@
      */
     int procedureCounter;
     /**
+     * Frequency Compensation indicates fractional frequency
+     * offset (FFO) value of initiator, in 0.01ppm
+     */
+    int[] frequencyCompensation;
+    /**
      * Indicate if the procedure aborted.
      */
     boolean aborted;
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
index 2c3f201..942fc0d 100644
--- a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
@@ -42,6 +42,10 @@
      */
     @nullable Nadm[] packetNadm;
     /**
+     * Measured Frequency Offset from mode 0, relative to the remote device, in 0.01ppm
+     */
+    @nullable int[] measuredFreqOffset;
+    /**
      * Packet_PCT1 or packet_PCT2 of mode-1 or mode-3, if sounding sequence is used and sounding
      * phase-based ranging is supported.
      */
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
index 99c6d65..4650861 100644
--- a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
@@ -23,6 +23,10 @@
  */
 @VintfStability
 parcelable StepTonePct {
+    /**
+     * PCT measured from mode-2 or mode-3 steps
+     * (in ascending order of antenna position with tone extension data at the end).
+     */
     List<ComplexNumber> tonePcts;
     const int TONE_QUALITY_GOOD = 0;
     const int TONE_QUALITY_MEDIUM = 1;
@@ -52,4 +56,20 @@
      * See: https://bluetooth.com/specifications/specs/channel-sounding-cr-pr/
      */
     byte[] toneQualityIndicator;
+
+    const byte TONE_EXTENSION_ANTENNA_1 = 0x0;
+    const byte TONE_EXTENSION_ANTENNA_2 = 0x1;
+    const byte TONE_EXTENSION_ANTENNA_3 = 0x2;
+    const byte TONE_EXTENSION_ANTENNA_4 = 0x3;
+    const byte TONE_EXTENSION_UNUSED = 0xFFu8;
+    /**
+     * Tone Extension Antenna Index indicates the Antenna position used in tone extension slot
+     *
+     * 0x00 = A1
+     * 0x01 = A2
+     * 0x02 = A3
+     * 0x03 = A4
+     * 0xFF = Tone extension not used
+     */
+    byte toneExtensionAntennaIndex;
 }
diff --git a/power/aidl/Android.bp b/power/aidl/Android.bp
index 7643926..8900fb8 100644
--- a/power/aidl/Android.bp
+++ b/power/aidl/Android.bp
@@ -28,11 +28,20 @@
         "android/hardware/power/*.aidl",
     ],
     stability: "vintf",
+    imports: [
+        "android.hardware.common.fmq-V1",
+        "android.hardware.common-V2",
+    ],
     backend: {
         cpp: {
+            enabled: false,
+        },
+        ndk: {
             enabled: true,
         },
         java: {
+            sdk_version: "module_current",
+            enabled: true,
             platform_apis: true,
         },
     },
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelConfig.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelConfig.aidl
new file mode 100644
index 0000000..d3caca4
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.power;
+@VintfStability
+parcelable ChannelConfig {
+  android.hardware.common.fmq.MQDescriptor<android.hardware.power.ChannelMessage,android.hardware.common.fmq.SynchronizedReadWrite> channelDescriptor;
+  @nullable android.hardware.common.fmq.MQDescriptor<byte,android.hardware.common.fmq.SynchronizedReadWrite> eventFlagDescriptor;
+  int readFlagBitmask;
+  int writeFlagBitmask;
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelMessage.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelMessage.aidl
new file mode 100644
index 0000000..25f01c0
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelMessage.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.power;
+@FixedSize @VintfStability
+parcelable ChannelMessage {
+  int sessionID;
+  android.hardware.power.ChannelMessage.ChannelMessageContents data;
+  @FixedSize @VintfStability
+  union ChannelMessageContents {
+    int[20] tids = {(-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */};
+    long targetDuration;
+    android.hardware.power.SessionHint hint;
+    android.hardware.power.ChannelMessage.ChannelMessageContents.SessionModeSetter mode;
+    android.hardware.power.WorkDurationFixedV1 workDuration;
+    @FixedSize @VintfStability
+    parcelable SessionModeSetter {
+      android.hardware.power.SessionMode modeInt;
+      boolean enabled;
+    }
+  }
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
index ae03313..8acdaf2 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
@@ -40,4 +40,7 @@
   boolean isBoostSupported(in android.hardware.power.Boost type);
   android.hardware.power.IPowerHintSession createHintSession(in int tgid, in int uid, in int[] threadIds, in long durationNanos);
   long getHintSessionPreferredRate();
+  android.hardware.power.IPowerHintSession createHintSessionWithConfig(in int tgid, in int uid, in int[] threadIds, in long durationNanos, in android.hardware.power.SessionTag tag, out android.hardware.power.SessionConfig config);
+  android.hardware.power.ChannelConfig getSessionChannel(in int tgid, in int uid);
+  oneway void closeSessionChannel(in int tgid, in int uid);
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
index 6bc663e..010f815 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
@@ -42,4 +42,5 @@
   oneway void sendHint(android.hardware.power.SessionHint hint);
   void setThreads(in int[] threadIds);
   oneway void setMode(android.hardware.power.SessionMode type, boolean enabled);
+  android.hardware.power.SessionConfig getSessionConfig();
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionConfig.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionConfig.aidl
new file mode 100644
index 0000000..b03cfb2
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionConfig.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.power;
+@VintfStability
+parcelable SessionConfig {
+  long id;
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl
new file mode 100644
index 0000000..80848a4
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.power;
+@Backing(type="int") @VintfStability
+enum SessionTag {
+  OTHER,
+  SURFACEFLINGER,
+  HWUI,
+  GAME,
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDurationFixedV1.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDurationFixedV1.aidl
new file mode 100644
index 0000000..8cd246d
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDurationFixedV1.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.power;
+@FixedSize @VintfStability
+parcelable WorkDurationFixedV1 {
+  long timeStampNanos;
+  long durationNanos;
+  long workPeriodStartTimestampNanos;
+  long cpuDurationNanos;
+  long gpuDurationNanos;
+}
diff --git a/power/aidl/android/hardware/power/ChannelConfig.aidl b/power/aidl/android/hardware/power/ChannelConfig.aidl
new file mode 100644
index 0000000..4da292e
--- /dev/null
+++ b/power/aidl/android/hardware/power/ChannelConfig.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.
+ */
+
+package android.hardware.power;
+
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.hardware.power.ChannelMessage;
+
+@VintfStability
+parcelable ChannelConfig {
+    /**
+     * The message queue descriptor that provides the information necessary for
+     * a client to write to this channel.
+     */
+    MQDescriptor<ChannelMessage, SynchronizedReadWrite> channelDescriptor;
+
+    /**
+     * A message queue descriptor used to pass an optional event flag to clients,
+     * used to synchronize multiple message queues using the same flag. If not
+     * defined, the flag from the channelDescriptor should be used.
+     */
+    @nullable MQDescriptor<byte, SynchronizedReadWrite> eventFlagDescriptor;
+
+    /**
+     * The read flag bitmask to be used with the event flag, specifying the
+     * bits used by this channel to mark that the buffer has been read from.
+     * If set to 0, the default bitmask will be used.
+     */
+    int readFlagBitmask;
+
+    /**
+     * The write flag bitmask to be used with the event flag, specifying the
+     * bits used by this channel to mark that the buffer has been written to.
+     * If set to 0, the default bitmask will be used.
+     */
+    int writeFlagBitmask;
+}
diff --git a/power/aidl/android/hardware/power/ChannelMessage.aidl b/power/aidl/android/hardware/power/ChannelMessage.aidl
new file mode 100644
index 0000000..4747d90
--- /dev/null
+++ b/power/aidl/android/hardware/power/ChannelMessage.aidl
@@ -0,0 +1,94 @@
+/*
+ * 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.power;
+
+import android.hardware.power.SessionHint;
+import android.hardware.power.SessionMode;
+import android.hardware.power.WorkDurationFixedV1;
+
+/**
+ * Data sent through the FMQ must follow this structure. It's important to note
+ * that such data may come from the app itself, so the HAL must validate all
+ * data received through this interface, and reject any calls not guaranteed to be
+ * valid. Each of the types defined in the inner union maps to an equivalent call
+ * on IPowerHintSession, and is merely being used to expedite the use of that API
+ * in cases where it is safe to bypass the HintManagerService.
+ */
+@FixedSize
+@VintfStability
+parcelable ChannelMessage {
+    /**
+     * The ID of the specific session sending the hint, used to enable a single
+     * channel to be multiplexed across all sessions in a single process.
+     */
+    int sessionID;
+
+    /**
+     * A union defining the different messages that can be passed through the
+     * channel. Each type corresponds to a different call in IPowerHintSession.
+     */
+    ChannelMessageContents data;
+
+    @FixedSize
+    @VintfStability
+    union ChannelMessageContents {
+        /**
+         * List of TIDs for this session to change to. Can be used in cases
+         * where HintManagerService is not needed to validate the TIDs, such as
+         * when all TIDs directly belong to the process that owns the session.
+         */
+        int[20] tids = {
+                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+
+        /**
+         * Setting this field will update the session’s target duration, equivalent
+         * to calling updateTargetWorkDuration(targetDuration).
+         */
+        long targetDuration;
+
+        /**
+         * Setting this field will send a hint to the session, equivalent to
+         * calling sendHint(hint).
+         */
+        SessionHint hint;
+
+        /**
+         * Setting this field will send a hint to the session, equivalent to
+         * calling setMode(mode.modeInt, mode.enabled).
+         */
+        SessionModeSetter mode;
+
+        /**
+         * Setting this field will update the session’s actual duration, equivalent
+         * to calling reportActualWorkDuration([workDuration]). Only one duration
+         * can be passed at a time; this API expects durations to be reported
+         * immediately each frame, since the overhead of this call is much lower.
+         */
+        WorkDurationFixedV1 workDuration;
+
+        /**
+         * This structure is used to fit both the mode and the state within one
+         * entry in the union.
+         */
+        @FixedSize
+        @VintfStability
+        parcelable SessionModeSetter {
+            SessionMode modeInt;
+            boolean enabled;
+        }
+    }
+}
diff --git a/power/aidl/android/hardware/power/IPower.aidl b/power/aidl/android/hardware/power/IPower.aidl
index ee8e5a3..e25714f 100644
--- a/power/aidl/android/hardware/power/IPower.aidl
+++ b/power/aidl/android/hardware/power/IPower.aidl
@@ -17,8 +17,11 @@
 package android.hardware.power;
 
 import android.hardware.power.Boost;
+import android.hardware.power.ChannelConfig;
 import android.hardware.power.IPowerHintSession;
 import android.hardware.power.Mode;
+import android.hardware.power.SessionConfig;
+import android.hardware.power.SessionTag;
 
 @VintfStability
 interface IPower {
@@ -103,4 +106,42 @@
      *         EX_UNSUPPORTED_OPERATION if hint session is not supported.
      */
     long getHintSessionPreferredRate();
+
+    /**
+     * A version of createHintSession that returns an additional bundle of session
+     * data, useful to help the session immediately communicate via an FMQ channel
+     * for more efficient updates.
+     *
+     * @return  the new session if it is supported on this device, otherwise return
+     *          with EX_UNSUPPORTED_OPERATION error if hint session is not
+     *          supported on this device.
+     * @param   tgid The TGID to be associated with this session.
+     * @param   uid The UID to be associated with this session.
+     * @param   threadIds The list of threads to be associated with this session.
+     * @param   durationNanos The desired duration in nanoseconds for this session.
+     * @param   config Extra session metadata to be returned to the caller.
+     */
+    IPowerHintSession createHintSessionWithConfig(in int tgid, in int uid, in int[] threadIds,
+            in long durationNanos, in SessionTag tag, out SessionConfig config);
+
+    /**
+     * Used to get an FMQ channel, per-process. The channel should be unique to
+     * that process, and should return the same ChannelConfig if called multiple
+     * times from that same process.
+     *
+     * @return  the channel config if hint sessions are supported on this device,
+     *          otherwise return with EX_UNSUPPORTED_OPERATION.
+     * @param   tgid The TGID to be associated with this channel.
+     * @param   uid The UID to be associated with this channel.
+     */
+    ChannelConfig getSessionChannel(in int tgid, in int uid);
+
+    /**
+     * Used to close a channel once it is no longer needed by a process, or that
+     * process dies.
+     *
+     * @param   tgid The TGID to be associated with this channel.
+     * @param   uid The UID to be associated with this channel.
+     */
+    oneway void closeSessionChannel(in int tgid, in int uid);
 }
diff --git a/power/aidl/android/hardware/power/IPowerHintSession.aidl b/power/aidl/android/hardware/power/IPowerHintSession.aidl
index 62263c8..9dd251f 100644
--- a/power/aidl/android/hardware/power/IPowerHintSession.aidl
+++ b/power/aidl/android/hardware/power/IPowerHintSession.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.power;
 
+import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionHint;
 import android.hardware.power.SessionMode;
 import android.hardware.power.WorkDuration;
@@ -91,4 +92,11 @@
      * @param enabled True to enable the mode, false to disable it
      */
     oneway void setMode(SessionMode type, boolean enabled);
+
+    /**
+     * This method provides direct access to a session's config data.
+     *
+     * @return  the config data for this session
+     */
+    SessionConfig getSessionConfig();
 }
diff --git a/power/aidl/android/hardware/power/SessionConfig.aidl b/power/aidl/android/hardware/power/SessionConfig.aidl
new file mode 100644
index 0000000..93dc9a2
--- /dev/null
+++ b/power/aidl/android/hardware/power/SessionConfig.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.power;
+
+/**
+ * Additional session to be passed to the hint session during creation, or acquired
+ * after creation from the session directly.
+ */
+@VintfStability
+parcelable SessionConfig {
+    /**
+     * The session's unique ID, used to identify the session for debugging and
+     * for multiplexing on the per-process FMQ channel.
+     */
+    long id;
+}
diff --git a/power/aidl/android/hardware/power/SessionTag.aidl b/power/aidl/android/hardware/power/SessionTag.aidl
new file mode 100644
index 0000000..c1d48e4
--- /dev/null
+++ b/power/aidl/android/hardware/power/SessionTag.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.power;
+
+@VintfStability
+@Backing(type="int")
+enum SessionTag {
+    /**
+     * This tag is used to mark uncategorized hint sessions.
+     */
+    OTHER,
+
+    /**
+     * This tag is used to mark the SurfaceFlinger hint session.
+     */
+    SURFACEFLINGER,
+
+    /**
+     * This tag is used to mark HWUI hint sessions.
+     */
+    HWUI,
+
+    /**
+     * This tag is used to mark Game hint sessions.
+     */
+    GAME,
+}
diff --git a/power/aidl/android/hardware/power/WorkDurationFixedV1.aidl b/power/aidl/android/hardware/power/WorkDurationFixedV1.aidl
new file mode 100644
index 0000000..2d202ff
--- /dev/null
+++ b/power/aidl/android/hardware/power/WorkDurationFixedV1.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.power;
+
+@FixedSize
+@VintfStability
+parcelable WorkDurationFixedV1 {
+    /**
+     * Timestamp in nanoseconds based on CLOCK_MONOTONIC when the duration
+     * sample was measured.
+     */
+    long timeStampNanos;
+
+    /**
+     * Total work duration in nanoseconds.
+     */
+    long durationNanos;
+
+    /**
+     * Timestamp in nanoseconds based on CLOCK_MONOTONIC when the work starts.
+     * The work period start timestamp could be zero if the call is from
+     * the legacy SDK/NDK reportActualWorkDuration API.
+     */
+    long workPeriodStartTimestampNanos;
+
+    /**
+     * CPU work duration in nanoseconds.
+     * The CPU work duration could be the same as the total work duration if
+     * the call is from the legacy SDK/NDK reportActualWorkDuration API.
+     */
+    long cpuDurationNanos;
+
+    /**
+     * GPU work duration in nanoseconds.
+     * The GPU work duration could be zero if the call is from the legacy
+     * SDK/NDK reportActualWorkDuration API.
+     */
+    long gpuDurationNanos;
+}
diff --git a/power/aidl/default/Android.bp b/power/aidl/default/Android.bp
index e3af179..b4ccc7d 100644
--- a/power/aidl/default/Android.bp
+++ b/power/aidl/default/Android.bp
@@ -29,8 +29,12 @@
     vintf_fragments: [":android.hardware.power.xml"],
     vendor: true,
     shared_libs: [
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
         "libbase",
         "libbinder_ndk",
+        "libcutils",
+        "libfmq",
     ],
     srcs: [
         "main.cpp",
diff --git a/power/aidl/default/Power.cpp b/power/aidl/default/Power.cpp
index 8fe370c..8f15663 100644
--- a/power/aidl/default/Power.cpp
+++ b/power/aidl/default/Power.cpp
@@ -18,6 +18,8 @@
 #include "PowerHintSession.h"
 
 #include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
 
 namespace aidl {
 namespace android {
@@ -27,6 +29,10 @@
 namespace example {
 
 using namespace std::chrono_literals;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::power::ChannelMessage;
+using ::android::AidlMessageQueue;
 
 using ndk::ScopedAStatus;
 
@@ -70,6 +76,27 @@
     return ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Power::createHintSessionWithConfig(
+        int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
+        SessionTag, SessionConfig* config, std::shared_ptr<IPowerHintSession>* _aidl_return) {
+    auto out = createHintSession(tgid, uid, threadIds, durationNanos, _aidl_return);
+    static_cast<PowerHintSession*>(_aidl_return->get())->getSessionConfig(config);
+    return out;
+}
+
+ndk::ScopedAStatus Power::getSessionChannel(int32_t, int32_t, ChannelConfig* _aidl_return) {
+    static AidlMessageQueue<ChannelMessage, SynchronizedReadWrite> stubQueue{1, true};
+    _aidl_return->channelDescriptor = stubQueue.dupeDesc();
+    _aidl_return->readFlagBitmask = 0;
+    _aidl_return->writeFlagBitmask = 0;
+    _aidl_return->eventFlagDescriptor = std::nullopt;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Power::closeSessionChannel(int32_t, int32_t) {
+    return ndk::ScopedAStatus::ok();
+}
+
 ScopedAStatus Power::getHintSessionPreferredRate(int64_t* outNanoseconds) {
     *outNanoseconds = std::chrono::nanoseconds(1ms).count();
     return ScopedAStatus::ok();
diff --git a/power/aidl/default/Power.h b/power/aidl/default/Power.h
index 7f8405e..baabaa7 100644
--- a/power/aidl/default/Power.h
+++ b/power/aidl/default/Power.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/power/BnPower.h>
+#include "aidl/android/hardware/power/SessionTag.h"
 
 namespace aidl {
 namespace android {
@@ -35,7 +36,14 @@
                                          const std::vector<int32_t>& threadIds,
                                          int64_t durationNanos,
                                          std::shared_ptr<IPowerHintSession>* _aidl_return) override;
+    ndk::ScopedAStatus createHintSessionWithConfig(
+            int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
+            SessionTag tag, SessionConfig* config,
+            std::shared_ptr<IPowerHintSession>* _aidl_return) override;
     ndk::ScopedAStatus getHintSessionPreferredRate(int64_t* outNanoseconds) override;
+    ndk::ScopedAStatus getSessionChannel(int32_t tgid, int32_t uid,
+                                         ChannelConfig* _aidl_return) override;
+    ndk::ScopedAStatus closeSessionChannel(int32_t tgid, int32_t uid) override;
 
   private:
     std::vector<std::shared_ptr<IPowerHintSession>> mPowerHintSessions;
diff --git a/power/aidl/default/PowerHintSession.cpp b/power/aidl/default/PowerHintSession.cpp
index 452e435..847a42e 100644
--- a/power/aidl/default/PowerHintSession.cpp
+++ b/power/aidl/default/PowerHintSession.cpp
@@ -17,6 +17,7 @@
 #include "PowerHintSession.h"
 
 #include <android-base/logging.h>
+#include "android/binder_auto_utils.h"
 
 namespace aidl::android::hardware::power::impl::example {
 
@@ -63,4 +64,9 @@
     return ScopedAStatus::ok();
 }
 
+ScopedAStatus PowerHintSession::getSessionConfig(SessionConfig* _aidl_return) {
+    _aidl_return->id = 1;
+    return ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/default/PowerHintSession.h b/power/aidl/default/PowerHintSession.h
index b488bf1..2ed5588 100644
--- a/power/aidl/default/PowerHintSession.h
+++ b/power/aidl/default/PowerHintSession.h
@@ -35,6 +35,7 @@
     ndk::ScopedAStatus sendHint(SessionHint hint) override;
     ndk::ScopedAStatus setThreads(const std::vector<int32_t>& threadIds) override;
     ndk::ScopedAStatus setMode(SessionMode mode, bool enabled) override;
+    ndk::ScopedAStatus getSessionConfig(SessionConfig* _aidl_return) override;
 };
 
 }  // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/vts/Android.bp b/power/aidl/vts/Android.bp
index eb98b8b..c9285f4 100644
--- a/power/aidl/vts/Android.bp
+++ b/power/aidl/vts/Android.bp
@@ -31,6 +31,11 @@
     srcs: ["VtsHalPowerTargetTest.cpp"],
     shared_libs: [
         "libbinder_ndk",
+        "libfmq",
+    ],
+    static_libs: [
+        "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.common-V2-ndk",
     ],
     test_suites: [
         "general-tests",
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index 96995a0..11d44b8 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -24,12 +24,22 @@
 #include <android/binder_process.h>
 #include <android/binder_status.h>
 
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
+
 #include <unistd.h>
+#include <cstdint>
+#include "aidl/android/hardware/common/fmq/SynchronizedReadWrite.h"
+#include "fmq/EventFlag.h"
 
 namespace aidl::android::hardware::power {
 namespace {
 
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
 using android::hardware::power::Boost;
+using android::hardware::power::ChannelConfig;
+using android::hardware::power::ChannelMessage;
 using android::hardware::power::IPower;
 using android::hardware::power::IPowerHintSession;
 using android::hardware::power::Mode;
@@ -37,6 +47,8 @@
 using android::hardware::power::SessionMode;
 using android::hardware::power::WorkDuration;
 
+using SessionMessageQueue = AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>;
+
 const std::vector<Boost> kBoosts{ndk::enum_range<Boost>().begin(), ndk::enum_range<Boost>().end()};
 
 const std::vector<Mode> kModes{ndk::enum_range<Mode>().begin(), ndk::enum_range<Mode>().end()};
@@ -190,6 +202,31 @@
     ASSERT_GE(rate, 1000000);
 }
 
+TEST_P(PowerAidl, createHintSessionWithConfig) {
+    if (mServiceVersion < 5) {
+        GTEST_SKIP() << "DEVICE not launching with Power V5 and beyond.";
+    }
+    std::shared_ptr<IPowerHintSession> session;
+    SessionConfig config;
+
+    auto status = power->createHintSessionWithConfig(getpid(), getuid(), kSelfTids, 16666666L,
+                                                     SessionTag::OTHER, &config, &session);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_NE(nullptr, session);
+}
+
+TEST_P(PowerAidl, getAndCloseSessionChannel) {
+    if (mServiceVersion < 5) {
+        GTEST_SKIP() << "DEVICE not launching with Power V5 and beyond.";
+    }
+    ChannelConfig config;
+    auto status = power->getSessionChannel(getpid(), getuid(), &config);
+    ASSERT_TRUE(status.isOk());
+    auto messageQueue = std::make_shared<SessionMessageQueue>(config.channelDescriptor, true);
+    ASSERT_TRUE(messageQueue->isValid());
+    ASSERT_TRUE(power->closeSessionChannel(getpid(), getuid()).isOk());
+}
+
 TEST_P(HintSessionAidl, createAndCloseHintSession) {
     ASSERT_TRUE(mSession->pause().isOk());
     ASSERT_TRUE(mSession->resume().isOk());
@@ -252,6 +289,14 @@
     }
 }
 
+TEST_P(HintSessionAidl, getSessionConfig) {
+    if (mServiceVersion < 5) {
+        GTEST_SKIP() << "DEVICE not launching with Power V5 and beyond.";
+    }
+    SessionConfig config;
+    ASSERT_TRUE(mSession->getSessionConfig(&config).isOk());
+}
+
 // FIXED_PERFORMANCE mode is required for all devices which ship on Android 11
 // or later
 TEST_P(PowerAidl, hasFixedPerformance) {
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
index c130a3a..7fc7a70 100644
--- a/security/secretkeeper/aidl/vts/Android.bp
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -25,6 +25,7 @@
         "general-tests",
         "vts",
     ],
+    test_config: "AndroidTest.xml",
     rustlibs: [
         "libsecretkeeper_comm_nostd",
         "libsecretkeeper_core_nostd",
@@ -36,6 +37,7 @@
         "libbinder_rs",
         "libcoset",
         "liblog_rust",
+        "liblogger",
     ],
     require_root: true,
 }
diff --git a/security/secretkeeper/aidl/vts/AndroidTest.xml b/security/secretkeeper/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..4fee78f
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for Secretkeeper VTS tests.">
+  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="push-file" key="VtsSecretkeeperTargetTest" value="/data/local/tmp/VtsSecretkeeperTargetTest" />
+  </target_preparer>
+
+  <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+    <option name="test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="VtsSecretkeeperTargetTest" />
+    <!-- Rust tests are run in parallel by default. Run these ones
+         single-threaded, so that one test's secrets don't affect
+         the behaviour of a different test. -->
+    <option name="native-test-flag" value="--test-threads=1" />
+  </test>
+</configuration>
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
index b5cca27..6a70d02 100644
--- a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -14,27 +14,28 @@
  * limitations under the License.
  */
 
-#[cfg(test)]
+#![cfg(test)]
+
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::SecretId::SecretId;
+use authgraph_vts_test as ag_vts;
+use authgraph_boringssl as boring;
+use authgraph_core::key;
 use binder::StatusCode;
 use coset::{CborSerializable, CoseEncrypt0};
-use log::warn;
+use log::{info, 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::{
     GetVersionRequest, GetVersionResponse, GetSecretRequest, GetSecretResponse, StoreSecretRequest,
     StoreSecretResponse };
-use secretkeeper_comm::data_types::{Id, ID_SIZE, Secret, SECRET_SIZE};
+use secretkeeper_comm::data_types::{Id, Secret};
 use secretkeeper_comm::data_types::response::Response;
 use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
-use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
-use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::SecretId::SecretId;
-use authgraph_vts_test as ag_vts;
-use authgraph_boringssl as boring;
-use authgraph_core::key;
 
-const SECRETKEEPER_IDENTIFIER: &str =
-    "android.hardware.security.secretkeeper.ISecretkeeper/nonsecure";
+const SECRETKEEPER_SERVICE: &str = "android.hardware.security.secretkeeper.ISecretkeeper";
+const SECRETKEEPER_INSTANCES: [&'static str; 2] = ["nonsecure", "default"];
 const CURRENT_VERSION: u64 = 1;
 
 // TODO(b/291238565): This will change once libdice_policy switches to Explicit-key DiceCertChain
@@ -47,38 +48,62 @@
 ];
 
 // Random bytes (of ID_SIZE/SECRET_SIZE) generated for tests.
-const ID_EXAMPLE: [u8; ID_SIZE] = [
+const ID_EXAMPLE: Id = Id([
     0xF1, 0xB2, 0xED, 0x3B, 0xD1, 0xBD, 0xF0, 0x7D, 0xE1, 0xF0, 0x01, 0xFC, 0x61, 0x71, 0xD3, 0x42,
     0xE5, 0x8A, 0xAF, 0x33, 0x6C, 0x11, 0xDC, 0xC8, 0x6F, 0xAE, 0x12, 0x5C, 0x26, 0x44, 0x6B, 0x86,
     0xCC, 0x24, 0xFD, 0xBF, 0x91, 0x4A, 0x54, 0x84, 0xF9, 0x01, 0x59, 0x25, 0x70, 0x89, 0x38, 0x8D,
     0x5E, 0xE6, 0x91, 0xDF, 0x68, 0x60, 0x69, 0x26, 0xBE, 0xFE, 0x79, 0x58, 0xF7, 0xEA, 0x81, 0x7D,
-];
-const ID_EXAMPLE_2: [u8; ID_SIZE] = [
+]);
+const ID_EXAMPLE_2: Id = Id([
     0x6A, 0xCC, 0xB1, 0xEB, 0xBB, 0xAB, 0xE3, 0xEA, 0x44, 0xBD, 0xDC, 0x75, 0x75, 0x7D, 0xC0, 0xE5,
     0xC7, 0x86, 0x41, 0x56, 0x39, 0x66, 0x96, 0x10, 0xCB, 0x43, 0x10, 0x79, 0x03, 0xDC, 0xE6, 0x9F,
     0x12, 0x2B, 0xEF, 0x28, 0x9C, 0x1E, 0x32, 0x46, 0x5F, 0xA3, 0xE7, 0x8D, 0x53, 0x63, 0xE8, 0x30,
     0x5A, 0x17, 0x6F, 0xEF, 0x42, 0xD6, 0x58, 0x7A, 0xF0, 0xCB, 0xD4, 0x40, 0x58, 0x96, 0x32, 0xF4,
-];
-const ID_NOT_STORED: [u8; ID_SIZE] = [
+]);
+const ID_NOT_STORED: Id = Id([
     0x56, 0xD0, 0x4E, 0xAA, 0xC1, 0x7B, 0x55, 0x6B, 0xA0, 0x2C, 0x65, 0x43, 0x39, 0x0A, 0x6C, 0xE9,
     0x1F, 0xD0, 0x0E, 0x20, 0x3E, 0xFB, 0xF5, 0xF9, 0x3F, 0x5B, 0x11, 0x1B, 0x18, 0x73, 0xF6, 0xBB,
     0xAB, 0x9F, 0xF2, 0xD6, 0xBD, 0xBA, 0x25, 0x68, 0x22, 0x30, 0xF2, 0x1F, 0x90, 0x05, 0xF3, 0x64,
     0xE7, 0xEF, 0xC6, 0xB6, 0xA0, 0x85, 0xC9, 0x40, 0x40, 0xF0, 0xB4, 0xB9, 0xD8, 0x28, 0xEE, 0x9C,
-];
-const SECRET_EXAMPLE: [u8; SECRET_SIZE] = [
+]);
+const SECRET_EXAMPLE: Secret = Secret([
     0xA9, 0x89, 0x97, 0xFE, 0xAE, 0x97, 0x55, 0x4B, 0x32, 0x35, 0xF0, 0xE8, 0x93, 0xDA, 0xEA, 0x24,
     0x06, 0xAC, 0x36, 0x8B, 0x3C, 0x95, 0x50, 0x16, 0x67, 0x71, 0x65, 0x26, 0xEB, 0xD0, 0xC3, 0x98,
-];
+]);
 
-fn get_connection() -> Option<binder::Strong<dyn ISecretkeeper>> {
-    match binder::get_interface(SECRETKEEPER_IDENTIFIER) {
-        Ok(sk) => Some(sk),
-        Err(StatusCode::NAME_NOT_FOUND) => None,
-        Err(e) => {
-            panic!(
-                "unexpected error while fetching connection to Secretkeeper {:?}",
-                e
-            );
+fn get_connection() -> Option<(binder::Strong<dyn ISecretkeeper>, String)> {
+    // Initialize logging (which is OK to call multiple times).
+    logger::init(logger::Config::default().with_min_level(log::Level::Debug));
+
+    // TODO: replace this with a parameterized set of tests that run for each available instance of
+    // ISecretkeeper (rather than having a fixed set of instance names to look for).
+    for instance in &SECRETKEEPER_INSTANCES {
+        let name = format!("{SECRETKEEPER_SERVICE}/{instance}");
+        match binder::get_interface(&name) {
+            Ok(sk) => {
+                info!("Running test against /{instance}");
+                return Some((sk, name));
+            }
+            Err(StatusCode::NAME_NOT_FOUND) => {
+                info!("No /{instance} instance of ISecretkeeper present");
+            }
+            Err(e) => {
+                panic!("unexpected error while fetching connection to Secretkeeper {:?}", e);
+            }
+        }
+    }
+    None
+}
+
+/// Macro to perform test setup. Invokes `return` if no Secretkeeper instance available.
+macro_rules! setup_client {
+    {} => {
+        match SkClient::new() {
+            Some(sk) => sk,
+            None => {
+                warn!("Secretkeeper HAL is unavailable, skipping test");
+                return;
+            }
         }
     }
 }
@@ -86,42 +111,86 @@
 /// Secretkeeper client information.
 struct SkClient {
     sk: binder::Strong<dyn ISecretkeeper>,
+    name: String,
     aes_keys: [key::AesKey; 2],
     session_id: Vec<u8>,
 }
 
+impl Drop for SkClient {
+    fn drop(&mut self) {
+        // Delete any IDs that may be left over.
+        self.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
+    }
+}
+
 impl SkClient {
     fn new() -> Option<Self> {
-        let sk = get_connection()?;
+        let (sk, name) = get_connection()?;
         let (aes_keys, session_id) = authgraph_key_exchange(sk.clone());
-        Some(Self {
-            sk,
-            aes_keys,
-            session_id,
-        })
+        Some(Self { sk, name, 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 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_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()
     }
+
+    /// Helper method to store a secret.
+    fn store(&self, id: &Id, secret: &Secret) {
+        let store_request = StoreSecretRequest {
+            id: id.clone(),
+            secret: secret.clone(),
+            sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+        };
+        let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+
+        let store_response = self.secret_management_request(&store_request);
+        let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+
+        assert_eq!(store_response.response_type().unwrap(), ResponseType::Success);
+        // Really just checking that the response is indeed StoreSecretResponse
+        let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+    }
+
+    /// Helper method to get a secret.
+    fn get(&self, id: &Id) -> Option<Secret> {
+        let get_request = GetSecretRequest { id: id.clone(), updated_sealing_policy: None };
+        let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+
+        let get_response = self.secret_management_request(&get_request);
+        let get_response = ResponsePacket::from_slice(&get_response).unwrap();
+
+        if get_response.response_type().unwrap() == ResponseType::Success {
+            let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
+            Some(Secret(get_response.secret.0))
+        } else {
+            // Only expect a not-found failure.
+            let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
+            assert_eq!(err, SecretkeeperError::EntryNotFound);
+            None
+        }
+    }
+
+    /// Helper method to delete secrets.
+    fn delete(&self, ids: &[&Id]) {
+        let ids: Vec<SecretId> = ids.iter().map(|id| SecretId { id: id.0.to_vec() }).collect();
+        self.sk.deleteIds(&ids).unwrap();
+    }
+
+    /// Helper method to delete everything.
+    fn delete_all(&self) {
+        self.sk.deleteAll().unwrap();
+    }
 }
 
 /// Perform AuthGraph key exchange, returning the session keys and session ID.
@@ -135,7 +204,7 @@
 /// mainline key exchange against a local source implementation.
 #[test]
 fn authgraph_mainline() {
-    let sk = match get_connection() {
+    let (sk, _) = match get_connection() {
         Some(sk) => sk,
         None => {
             warn!("Secretkeeper HAL is unavailable, skipping test");
@@ -149,7 +218,7 @@
 /// a corrupted session ID signature.
 #[test]
 fn authgraph_corrupt_sig() {
-    let sk = match get_connection() {
+    let (sk, _) = match get_connection() {
         Some(sk) => sk,
         None => {
             warn!("Secretkeeper HAL is unavailable, skipping test");
@@ -165,7 +234,7 @@
 /// when corrupted keys are returned to it.
 #[test]
 fn authgraph_corrupt_keys() {
-    let sk = match get_connection() {
+    let (sk, _) = match get_connection() {
         Some(sk) => sk,
         None => {
             warn!("Secretkeeper HAL is unavailable, skipping test");
@@ -182,13 +251,7 @@
 
 #[test]
 fn secret_management_get_version() {
-    let sk_client = match SkClient::new() {
-        Some(sk) => sk,
-        None => {
-            warn!("Secretkeeper HAL is unavailable, skipping test");
-            return;
-        }
-    };
+    let sk_client = setup_client!();
 
     let request = GetVersionRequest {};
     let request_packet = request.serialize_to_packet();
@@ -197,10 +260,7 @@
     let response_bytes = sk_client.secret_management_request(&request_bytes);
 
     let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
-    assert_eq!(
-        response_packet.response_type().unwrap(),
-        ResponseType::Success
-    );
+    assert_eq!(response_packet.response_type().unwrap(), ResponseType::Success);
     let get_version_response =
         *GetVersionResponse::deserialize_from_packet(response_packet).unwrap();
     assert_eq!(get_version_response.version, CURRENT_VERSION);
@@ -208,13 +268,7 @@
 
 #[test]
 fn secret_management_malformed_request() {
-    let sk_client = match SkClient::new() {
-        Some(sk) => sk,
-        None => {
-            warn!("Secretkeeper HAL is unavailable, skipping test");
-            return;
-        }
-    };
+    let sk_client = setup_client!();
 
     let request = GetVersionRequest {};
     let request_packet = request.serialize_to_packet();
@@ -226,268 +280,112 @@
     let response_bytes = sk_client.secret_management_request(&request_bytes);
 
     let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
-    assert_eq!(
-        response_packet.response_type().unwrap(),
-        ResponseType::Error
-    );
+    assert_eq!(response_packet.response_type().unwrap(), ResponseType::Error);
     let err = *SecretkeeperError::deserialize_from_packet(response_packet).unwrap();
     assert_eq!(err, SecretkeeperError::RequestMalformed);
 }
 
 #[test]
 fn secret_management_store_get_secret_found() {
-    let sk_client = match SkClient::new() {
-        Some(sk) => sk,
-        None => {
-            warn!("Secretkeeper HAL is unavailable, skipping test");
-            return;
-        }
-    };
+    let sk_client = setup_client!();
 
-    let store_request = StoreSecretRequest {
-        id: Id(ID_EXAMPLE),
-        secret: Secret(SECRET_EXAMPLE),
-        sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
-    };
-
-    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
-
-    let store_response = sk_client.secret_management_request(&store_request);
-    let store_response = ResponsePacket::from_slice(&store_response).unwrap();
-
-    assert_eq!(
-        store_response.response_type().unwrap(),
-        ResponseType::Success
-    );
-    // Really just checking that the response is indeed StoreSecretResponse
-    let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
 
     // Get the secret that was just stored
-    let get_request = GetSecretRequest {
-        id: Id(ID_EXAMPLE),
-        updated_sealing_policy: None,
-    };
-    let get_request = get_request.serialize_to_packet().to_vec().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();
-    assert_eq!(get_response.secret.0, SECRET_EXAMPLE);
+    assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
 }
 
 #[test]
 fn secret_management_store_get_secret_not_found() {
-    let sk_client = match SkClient::new() {
-        Some(sk) => sk,
-        None => {
-            warn!("Secretkeeper HAL is unavailable, skipping test");
-            return;
-        }
-    };
+    let sk_client = setup_client!();
 
     // Store a secret (corresponding to an id).
-    let store_request = StoreSecretRequest {
-        id: Id(ID_EXAMPLE),
-        secret: Secret(SECRET_EXAMPLE),
-        sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
-    };
-
-    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
-    let store_response = sk_client.secret_management_request(&store_request);
-    let store_response = ResponsePacket::from_slice(&store_response).unwrap();
-
-    assert_eq!(
-        store_response.response_type().unwrap(),
-        ResponseType::Success
-    );
-    // Really just checking that the response is indeed StoreSecretResponse
-    let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
 
     // Get the secret that was never stored
-    let get_request = GetSecretRequest {
-        id: Id(ID_NOT_STORED),
-        updated_sealing_policy: None,
-    };
-    let get_request = get_request.serialize_to_packet().to_vec().unwrap();
-
-    let get_response = sk_client.secret_management_request(&get_request);
-
-    // Expect the entry not to be found.
-    let get_response = ResponsePacket::from_slice(&get_response).unwrap();
-    assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
-    let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
-    assert_eq!(err, SecretkeeperError::EntryNotFound);
+    assert_eq!(sk_client.get(&ID_NOT_STORED), None);
 }
 
 #[test]
 fn secretkeeper_store_delete_ids() {
-    let sk_client = match SkClient::new() {
-        Some(sk) => sk,
-        None => {
-            warn!("Secretkeeper HAL is unavailable, skipping test");
-            return;
-        }
-    };
+    let sk_client = setup_client!();
 
-    let store_request = StoreSecretRequest {
-        id: Id(ID_EXAMPLE),
-        secret: Secret(SECRET_EXAMPLE),
-        sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
-    };
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    sk_client.delete(&[&ID_EXAMPLE]);
 
-    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
-    let store_response = sk_client.secret_management_request(&store_request);
-    let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
 
-    assert_eq!(
-        store_response.response_type().unwrap(),
-        ResponseType::Success
-    );
-    // Really just checking that the response is indeed StoreSecretResponse
-    let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+    sk_client.delete(&[&ID_EXAMPLE_2]);
 
-    sk_client
-        .sk
-        .deleteIds(&[SecretId {
-            id: ID_EXAMPLE.to_vec(),
-        }])
-        .unwrap();
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
+}
 
-    // Try to get the secret that was just stored & deleted
-    let get_request = GetSecretRequest {
-        id: Id(ID_EXAMPLE),
-        updated_sealing_policy: None,
-    };
-    let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+#[test]
+fn secretkeeper_store_delete_multiple_ids() {
+    let sk_client = setup_client!();
 
-    let get_response = sk_client.secret_management_request(&get_request);
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
 
-    // Expect the entry not to be found.
-    let get_response = ResponsePacket::from_slice(&get_response).unwrap();
-    assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
-    let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
-    assert_eq!(err, SecretkeeperError::EntryNotFound);
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
+}
+
+#[test]
+fn secretkeeper_store_delete_duplicate_ids() {
+    let sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    // Delete the same secret twice.
+    sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
+}
+
+#[test]
+fn secretkeeper_store_delete_nonexistent() {
+    let sk_client = setup_client!();
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
+    sk_client.delete(&[&ID_NOT_STORED]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), Some(SECRET_EXAMPLE));
+    assert_eq!(sk_client.get(&ID_NOT_STORED), None);
 }
 
 #[test]
 fn secretkeeper_store_delete_all() {
-    let sk_client = match SkClient::new() {
-        Some(sk) => sk,
-        None => {
-            warn!("Secretkeeper HAL is unavailable, skipping test");
-            return;
-        }
-    };
+    let sk_client = setup_client!();
 
-    let store_request = StoreSecretRequest {
-        id: Id(ID_EXAMPLE),
-        secret: Secret(SECRET_EXAMPLE),
-        sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
-    };
+    if sk_client.name != "nonsecure" {
+        // Don't run deleteAll() on a secure device, as it might affect
+        // real secrets.
+        warn!("skipping deleteAll test due to real impl");
+        return;
+    }
 
-    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
-    let store_response = sk_client.secret_management_request(&store_request);
-    let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
 
-    assert_eq!(
-        store_response.response_type().unwrap(),
-        ResponseType::Success
-    );
-    // Really just checking that the response is indeed StoreSecretResponse
-    let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+    sk_client.delete_all();
 
-    let store_request = StoreSecretRequest {
-        id: Id(ID_EXAMPLE_2),
-        secret: Secret(SECRET_EXAMPLE),
-        sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
-    };
-
-    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
-    let store_response = sk_client.secret_management_request(&store_request);
-    let store_response = ResponsePacket::from_slice(&store_response).unwrap();
-
-    assert_eq!(
-        store_response.response_type().unwrap(),
-        ResponseType::Success
-    );
-    // Really just checking that the response is indeed StoreSecretResponse
-    let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
-
-    sk_client.sk.deleteAll().unwrap();
-
-    // Get the first secret that was just stored before deleteAll
-    let get_request = GetSecretRequest {
-        id: Id(ID_EXAMPLE),
-        updated_sealing_policy: None,
-    };
-    let get_request = get_request.serialize_to_packet().to_vec().unwrap();
-
-    let get_response = sk_client.secret_management_request(&get_request);
-
-    // Expect the entry not to be found.
-    let get_response = ResponsePacket::from_slice(&get_response).unwrap();
-    assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
-    let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
-    assert_eq!(err, SecretkeeperError::EntryNotFound);
-
-    // Get the second secret that was just stored before deleteAll
-    let get_request = GetSecretRequest {
-        id: Id(ID_EXAMPLE_2),
-        updated_sealing_policy: None,
-    };
-    let get_request = get_request.serialize_to_packet().to_vec().unwrap();
-
-    let get_response = sk_client.secret_management_request(&get_request);
-
-    // Expect the entry not to be found.
-    let get_response = ResponsePacket::from_slice(&get_response).unwrap();
-    assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
-    let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
-    assert_eq!(err, SecretkeeperError::EntryNotFound);
+    assert_eq!(sk_client.get(&ID_EXAMPLE), None);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2), None);
 
     // Store a new secret (corresponding to an id).
-    let store_request = StoreSecretRequest {
-        id: Id(ID_EXAMPLE),
-        secret: Secret(SECRET_EXAMPLE),
-        sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
-    };
-
-    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
-    let store_response = sk_client.secret_management_request(&store_request);
-    let store_response = ResponsePacket::from_slice(&store_response).unwrap();
-
-    assert_eq!(
-        store_response.response_type().unwrap(),
-        ResponseType::Success
-    );
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
 
     // Get the restored secret.
-    let get_request = GetSecretRequest {
-        id: Id(ID_EXAMPLE),
-        updated_sealing_policy: None,
-    };
-    let get_request = get_request.serialize_to_packet().to_vec().unwrap();
-
-    let get_response = sk_client.secret_management_request(&get_request);
-    let get_response = ResponsePacket::from_slice(&get_response).unwrap();
-
-    // Get the secret that was just re-stored.
-    assert_eq!(get_response.response_type().unwrap(), ResponseType::Success);
-    let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
-    assert_eq!(get_response.secret.0, SECRET_EXAMPLE);
+    assert_eq!(sk_client.get(&ID_EXAMPLE), Some(SECRET_EXAMPLE));
 
     // (Try to) Get the secret that was never stored
-    let get_request = GetSecretRequest {
-        id: Id(ID_NOT_STORED),
-        updated_sealing_policy: None,
-    };
-    let get_request = get_request.serialize_to_packet().to_vec().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();
-    assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
-    let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
-    assert_eq!(err, SecretkeeperError::EntryNotFound);
+    assert_eq!(sk_client.get(&ID_NOT_STORED), None);
 }
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
index d8e73fb..d6ed62e 100644
--- 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
@@ -40,6 +40,6 @@
   boolean isFlexibleTwtScheduleSupported;
   int minWakeDurationMicros;
   int maxWakeDurationMicros;
-  int minWakeIntervalMicros;
-  int maxWakeIntervalMicros;
+  long minWakeIntervalMicros;
+  long 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
index 3051b94..06c7ae2 100644
--- 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
@@ -37,6 +37,6 @@
   int mloLinkId;
   int minWakeDurationMicros;
   int maxWakeDurationMicros;
-  int minWakeIntervalMicros;
-  int maxWakeIntervalMicros;
+  long minWakeIntervalMicros;
+  long 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
index 92c2533..4e5ca44 100644
--- 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
@@ -37,7 +37,7 @@
   int sessionId;
   int mloLinkId;
   int wakeDurationMicros;
-  int wakeIntervalMicros;
+  long wakeIntervalMicros;
   android.hardware.wifi.TwtSession.TwtNegotiationType negotiationType;
   boolean isTriggerEnabled;
   boolean isAnnounced;
diff --git a/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl b/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl
index 9007d0e..4012c3e 100644
--- a/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl
+++ b/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl
@@ -48,9 +48,9 @@
     /**
      * Minimum TWT wake interval in microseconds.
      */
-    int minWakeIntervalMicros;
+    long minWakeIntervalMicros;
     /**
      * Maximum TWT wake interval in microseconds.
      */
-    int maxWakeIntervalMicros;
+    long maxWakeIntervalMicros;
 }
diff --git a/wifi/aidl/android/hardware/wifi/TwtRequest.aidl b/wifi/aidl/android/hardware/wifi/TwtRequest.aidl
index 5191713..b063da3 100644
--- a/wifi/aidl/android/hardware/wifi/TwtRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/TwtRequest.aidl
@@ -36,9 +36,9 @@
     /**
      * Minimum TWT wake interval in microseconds.
      */
-    int minWakeIntervalMicros;
+    long minWakeIntervalMicros;
     /**
      * Maximum TWT wake interval in microseconds.
      */
-    int maxWakeIntervalMicros;
+    long maxWakeIntervalMicros;
 }
diff --git a/wifi/aidl/android/hardware/wifi/TwtSession.aidl b/wifi/aidl/android/hardware/wifi/TwtSession.aidl
index 5a7ddb1..6b780f8 100644
--- a/wifi/aidl/android/hardware/wifi/TwtSession.aidl
+++ b/wifi/aidl/android/hardware/wifi/TwtSession.aidl
@@ -46,7 +46,7 @@
     /**
      * Time interval in microseconds between two successive TWT service periods.
      */
-    int wakeIntervalMicros;
+    long wakeIntervalMicros;
 
     /**
      * TWT negotiation type.