Merge "Wifi: Allow reporting MULTIPLE_MLD_ON_SAP feature flag to userspace." into main
diff --git a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
index cfe001e..9b7fea2 100644
--- a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -188,6 +188,14 @@
          * In the 'DRAINING' state the producer is inactive, the consumer is
          * finishing up on the buffer contents, emptying it up. As soon as it
          * gets empty, the stream transfers itself into the next state.
+         *
+         * Note that "early notify" draining is a more complex procedure
+         * intended for transitioning between two clips. Both 'DRAINING' and
+         * 'DRAIN_PAUSED' states have "sub-states" not visible via the API. See
+         * the details in the 'stream-out-async-sm.gv' state machine
+         * description. In the HAL API V3 this behavior is enabled when the
+         * HAL exposes "aosp.clipTransitionSupport" property, and in the HAL
+         * API V4 it is the default behavior.
          */
         DRAINING = 5,
         /**
@@ -234,9 +242,15 @@
         /**
          * Used with output streams only, the HAL module indicates drain
          * completion shortly before all audio data has been consumed in order
-         * to give the client an opportunity to provide data for the next track
+         * to give the client an opportunity to provide data for the next clip
          * for gapless playback. The exact amount of provided time is specific
          * to the HAL implementation.
+         *
+         * In the HAL API V3, the HAL sends two 'onDrainReady' notifications:
+         * one to indicate readiness to receive next clip data, and another when
+         * the previous clip has finished playing. This behavior is enabled when
+         * the HAL exposes "aosp.clipTransitionSupport" property, and in the HAL
+         * API V4 it is the default behavior.
          */
         DRAIN_EARLY_NOTIFY = 2,
     }
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
index e2da90d..bf75594 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -32,27 +32,78 @@
     IDLE -> TRANSFERRING [label="burst"];             // producer -> active
     IDLE -> ACTIVE [label="burst"];                   // full write
     ACTIVE -> PAUSED [label="pause"];                 // consumer -> passive (not consuming)
-    ACTIVE -> DRAINING [label="drain"];               // producer -> passive
+    ACTIVE -> DRAINING [label="drain(ALL)"];          // producer -> passive
+    ACTIVE -> DRAINING_en [label="drain(EARLY_NOTIFY)"];  // prepare for clip transition
     ACTIVE -> TRANSFERRING [label="burst"];           // early unblocking
     ACTIVE -> ACTIVE [label="burst"];                 // full write
     TRANSFERRING -> ACTIVE [label="←IStreamCallback.onTransferReady"];
     TRANSFERRING -> TRANSFER_PAUSED [label="pause"];  // consumer -> passive (not consuming)
-    TRANSFERRING -> DRAINING [label="drain"];         // producer -> passive
+    TRANSFERRING -> DRAINING [label="drain(ALL)"];    // producer -> passive
+    TRANSFERRING -> DRAINING_en [label="drain(EARLY_NOTIFY)"]; // prepare for clip transition
     TRANSFER_PAUSED -> TRANSFERRING [label="start"];  // consumer -> active
-    TRANSFER_PAUSED -> DRAIN_PAUSED [label="drain"];  // producer -> passive
+    TRANSFER_PAUSED -> DRAIN_PAUSED [label="drain(ALL)"];  // producer -> passive
     TRANSFER_PAUSED -> IDLE [label="flush"];          // buffer is cleared
     PAUSED -> PAUSED [label="burst"];
     PAUSED -> ACTIVE [label="start"];                 // consumer -> active
     PAUSED -> IDLE [label="flush"];                   // producer -> passive, buffer is cleared
     DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
-    DRAINING -> DRAINING [label="←IStreamCallback.onDrainReady"];  // allowed for `DRAIN_EARLY_NOTIFY`
-    DRAINING -> IDLE [label="<empty buffer>"];        // allowed for `DRAIN_EARLY_NOTIFY`
     DRAINING -> TRANSFERRING [label="burst"];         // producer -> active
     DRAINING -> ACTIVE [label="burst"];               // full write
     DRAINING -> DRAIN_PAUSED [label="pause"];         // consumer -> passive (not consuming)
     DRAIN_PAUSED -> DRAINING [label="start"];         // consumer -> active
     DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"];  // producer -> active
     DRAIN_PAUSED -> IDLE [label="flush"];             // buffer is cleared
+    // Note that the states in both clusters are combined with 'DRAINING' and 'DRAIN_PAUSED'
+    // state at the API level. The 'en' and 'en_sent' attributes only belong to the internal
+    // state of the stream and are not observable outside.
+    subgraph cluster_early_notify_entering {
+        // The stream is preparing for a transition between two clips. After
+        // receiving 'drain(EARLY_NOTIFY)' command, the stream continues playing
+        // the current clip, and at some point notifies the client that it is
+        // ready for the next clip data by issuing the first 'onDrainReady'
+        // callback.
+        label="EARLY_NOTIFY (entering)";
+        color=gray;
+        // Getting 'burst' or 'flush' command in these states resets the "clip
+        // transition" mode.
+        DRAINING_en;
+        DRAIN_PAUSED_en;
+    }
+    subgraph cluster_early_notify_notification_sent {
+        // After the stream has sent "onDrainReady", the client can now send
+        // 'burst' commands with the data of the next clip. These 'bursts' are
+        // always "early unblocking" because the previous clip is still playing
+        // thus the stream is unable to play any of the received data
+        // synchronously (in other words, it can not do a "full write"). To
+        // indicate readiness to accept the next burst the stream uses the usual
+        // 'onTransferReady' callback.
+        label="EARLY_NOTIFY (notification sent)";
+        color=gray;
+        // The state machine remains in these states until the current clip ends
+        // playing. When it ends, the stream sends 'onDrainReady' (note that
+        // it's the second 'onDrainReady' for the same 'drain(EARLY_NOTIFY)'),
+        // and transitions either to 'IDLE' if there is no data for the next
+        // clip, or to 'TRANSFERRING' otherwise. Note that it can not transition
+        // to 'ACTIVE' because that transition is associated with
+        // 'onTransferReady' callback.
+        DRAINING_en_sent;
+        DRAIN_PAUSED_en_sent;
+    }
+    DRAINING_en -> TRANSFERRING [label="burst"];                  // producer -> active
+    DRAINING_en -> ACTIVE [label="burst"];                        // full write
+    DRAINING_en -> DRAIN_PAUSED_en [label="pause"];               // consumer -> passive (not consuming)
+    DRAINING_en -> DRAINING_en_sent [label="←IStreamCallback.onDrainReady"];
+    DRAIN_PAUSED_en -> DRAINING_en [label="start"];               // consumer -> active
+    DRAIN_PAUSED_en -> TRANSFER_PAUSED [label="burst"];           // producer -> active
+    DRAIN_PAUSED_en -> IDLE [label="flush"];                      // buffer is cleared
+    DRAINING_en_sent -> DRAINING_en_sent [label="burst"];
+    DRAINING_en_sent -> DRAINING_en_sent [label="←IStreamCallback.onTransferReady"];
+    DRAINING_en_sent -> DRAIN_PAUSED_en_sent [label="pause"];     // consumer -> passive (not consuming)
+    DRAINING_en_sent -> TRANSFERRING [label="←IStreamCallback.onDrainReady"];
+    DRAINING_en_sent -> IDLE [label="←IStreamCallback.onDrainReady"];
+    DRAIN_PAUSED_en_sent -> DRAINING_en_sent [label="start"];     // consumer -> active
+    DRAIN_PAUSED_en_sent -> DRAIN_PAUSED_en_sent [label="burst"]; // producer -> active
+    DRAIN_PAUSED_en_sent -> IDLE [label="flush"];                 // buffer is cleared
     ANY_STATE -> ERROR [label="←IStreamCallback.onError"];
     ANY_STATE -> CLOSED [label="→IStream*.close"];
     CLOSED -> F;
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 077d80b..aa624ff 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -214,24 +214,33 @@
     StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
                                           mVendorDebug.forceTransientBurst,
                                           mVendorDebug.forceSynchronousDrain};
-    std::unique_ptr<StreamContext::DataMQ> dataMQ = nullptr;
-    std::shared_ptr<IStreamCallback> streamAsyncCallback = nullptr;
     std::shared_ptr<ISoundDose> soundDose;
     if (!getSoundDose(&soundDose).isOk()) {
         LOG(ERROR) << __func__ << ": could not create sound dose instance";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
-    if (!hasMmapFlag(flags)) {
-        dataMQ = std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames);
-        streamAsyncCallback = asyncCallback;
+    StreamContext temp;
+    if (hasMmapFlag(flags)) {
+        MmapBufferDescriptor mmapDesc;
+        RETURN_STATUS_IF_ERROR(
+                createMmapBuffer(*portConfigIt, in_bufferSizeFrames, frameSize, &mmapDesc));
+        temp = StreamContext(
+                std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
+                std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
+                portConfigIt->format.value(), portConfigIt->channelMask.value(),
+                portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
+                portConfigIt->ext.get<AudioPortExt::mix>().handle, std::move(mmapDesc),
+                outEventCallback, mSoundDose.getInstance(), params);
+    } else {
+        temp = StreamContext(
+                std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
+                std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
+                portConfigIt->format.value(), portConfigIt->channelMask.value(),
+                portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
+                portConfigIt->ext.get<AudioPortExt::mix>().handle,
+                std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
+                asyncCallback, outEventCallback, mSoundDose.getInstance(), params);
     }
-    StreamContext temp(
-            std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
-            std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
-            portConfigIt->format.value(), portConfigIt->channelMask.value(),
-            portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
-            portConfigIt->ext.get<AudioPortExt::mix>().handle, std::move(dataMQ),
-            streamAsyncCallback, outEventCallback, mSoundDose.getInstance(), params);
     if (temp.isValid()) {
         *out_context = std::move(temp);
     } else {
@@ -394,9 +403,10 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
-ndk::ScopedAStatus Module::createMmapBuffer(
-        const ::aidl::android::hardware::audio::core::StreamContext& context __unused,
-        ::aidl::android::hardware::audio::core::StreamDescriptor* desc __unused) {
+ndk::ScopedAStatus Module::createMmapBuffer(const AudioPortConfig& portConfig __unused,
+                                            int32_t bufferSizeFrames __unused,
+                                            int32_t frameSizeBytes __unused,
+                                            MmapBufferDescriptor* desc __unused) {
     LOG(ERROR) << __func__ << ": " << mType << ": is not implemented";
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
@@ -612,6 +622,15 @@
     return ndk::ScopedAStatus::ok();
 }
 
+binder_status_t Module::dump(int fd, const char** args, uint32_t numArgs) {
+    for (const auto& portConfig : getConfig().portConfigs) {
+        if (portConfig.ext.getTag() == AudioPortExt::Tag::mix) {
+            getStreams().dump(portConfig.id, fd, args, numArgs);
+        }
+    }
+    return STATUS_OK;
+}
+
 ndk::ScopedAStatus Module::setModuleDebug(
         const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) {
     LOG(DEBUG) << __func__ << ": " << mType << ": old flags:" << mDebug.toString()
@@ -968,9 +987,6 @@
     RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
                                                nullptr, nullptr, &context));
     context.fillDescriptor(&_aidl_return->desc);
-    if (hasMmapFlag(context.getFlags())) {
-        RETURN_STATUS_IF_ERROR(createMmapBuffer(context, &_aidl_return->desc));
-    }
     std::shared_ptr<StreamIn> stream;
     RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata,
                                              getMicrophoneInfos(), &stream));
@@ -1018,9 +1034,6 @@
                                                isNonBlocking ? in_args.callback : nullptr,
                                                in_args.eventCallback, &context));
     context.fillDescriptor(&_aidl_return->desc);
-    if (hasMmapFlag(context.getFlags())) {
-        RETURN_STATUS_IF_ERROR(createMmapBuffer(context, &_aidl_return->desc));
-    }
     std::shared_ptr<StreamOut> stream;
     RETURN_STATUS_IF_ERROR(createOutputStream(std::move(context), in_args.sourceMetadata,
                                               in_args.offloadInfo, &stream));
@@ -1546,6 +1559,7 @@
 
 const std::string Module::VendorDebug::kForceTransientBurstName = "aosp.forceTransientBurst";
 const std::string Module::VendorDebug::kForceSynchronousDrainName = "aosp.forceSynchronousDrain";
+const std::string Module::kClipTransitionSupportName = "aosp.clipTransitionSupport";
 
 ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
                                                std::vector<VendorParameter>* _aidl_return) {
@@ -1560,6 +1574,10 @@
             VendorParameter forceSynchronousDrain{.id = id};
             forceSynchronousDrain.ext.setParcelable(Boolean{mVendorDebug.forceSynchronousDrain});
             _aidl_return->push_back(std::move(forceSynchronousDrain));
+        } else if (id == kClipTransitionSupportName) {
+            VendorParameter clipTransitionSupport{.id = id};
+            clipTransitionSupport.ext.setParcelable(Boolean{true});
+            _aidl_return->push_back(std::move(clipTransitionSupport));
         } else {
             allParametersKnown = false;
             LOG(VERBOSE) << __func__ << ": " << mType << ": unrecognized parameter \"" << id << "\"";
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index c6c1b5d..873fc48 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -65,18 +65,26 @@
     if (mReplyMQ) {
         desc->reply = mReplyMQ->dupeDesc();
     }
+    desc->frameSizeBytes = getFrameSize();
+    desc->bufferSizeFrames = getBufferSizeInFrames();
     if (mDataMQ) {
-        desc->frameSizeBytes = getFrameSize();
-        desc->bufferSizeFrames = getBufferSizeInFrames();
         desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
+    } else {
+        MmapBufferDescriptor mmapDesc;  // Move-only due to `fd`.
+        mmapDesc.sharedMemory.fd = mMmapBufferDesc.sharedMemory.fd.dup();
+        mmapDesc.sharedMemory.size = mMmapBufferDesc.sharedMemory.size;
+        mmapDesc.burstSizeFrames = mMmapBufferDesc.burstSizeFrames;
+        mmapDesc.flags = mMmapBufferDesc.flags;
+        desc->audio.set<StreamDescriptor::AudioBuffer::Tag::mmap>(std::move(mmapDesc));
     }
 }
 
 size_t StreamContext::getBufferSizeInFrames() const {
     if (mDataMQ) {
         return mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / getFrameSize();
+    } else {
+        return mMmapBufferDesc.sharedMemory.size / getFrameSize();
     }
-    return 0;
 }
 
 size_t StreamContext::getFrameSize() const {
@@ -96,9 +104,13 @@
         LOG(ERROR) << "frame size is invalid";
         return false;
     }
-    if (!hasMmapFlag(mFlags) && mDataMQ && !mDataMQ->isValid()) {
+    if (!isMmap() && mDataMQ && !mDataMQ->isValid()) {
         LOG(ERROR) << "data FMQ is invalid";
         return false;
+    } else if (isMmap() &&
+               (mMmapBufferDesc.sharedMemory.fd.get() == -1 ||
+                mMmapBufferDesc.sharedMemory.size == 0 || mMmapBufferDesc.burstSizeFrames == 0)) {
+        LOG(ERROR) << "mmap info is invalid" << mMmapBufferDesc.toString();
     }
     return true;
 }
@@ -115,6 +127,7 @@
     mCommandMQ.reset();
     mReplyMQ.reset();
     mDataMQ.reset();
+    mMmapBufferDesc.sharedMemory.fd.set(-1);
 }
 
 pid_t StreamWorkerCommonLogic::getTid() const {
@@ -128,7 +141,7 @@
 std::string StreamWorkerCommonLogic::init() {
     if (mContext->getCommandMQ() == nullptr) return "Command MQ is null";
     if (mContext->getReplyMQ() == nullptr) return "Reply MQ is null";
-    if (!hasMmapFlag(mContext->getFlags())) {
+    if (!mContext->isMmap()) {
         StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
         if (dataMQ == nullptr) return "Data MQ is null";
         if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
@@ -167,7 +180,7 @@
     } else {
         reply->observable = reply->hardware = kUnknownPosition;
     }
-    if (hasMmapFlag(mContext->getFlags())) {
+    if (mContext->isMmap()) {
         if (auto status = mDriver->getMmapPositionAndLatency(&reply->hardware, &reply->latencyMs);
             status != ::android::OK) {
             reply->hardware = kUnknownPosition;
@@ -252,9 +265,9 @@
                     mState == StreamDescriptor::State::ACTIVE ||
                     mState == StreamDescriptor::State::PAUSED ||
                     mState == StreamDescriptor::State::DRAINING) {
-                    if (hasMmapFlag(mContext->getFlags())) {
-                        populateReply(&reply, mIsConnected);
-                    } else if (!read(fmqByteCount, &reply)) {
+                    if (bool success =
+                                mContext->isMmap() ? readMmap(&reply) : read(fmqByteCount, &reply);
+                        !success) {
                         mState = StreamDescriptor::State::ERROR;
                     }
                     if (mState == StreamDescriptor::State::IDLE ||
@@ -383,16 +396,38 @@
     return !fatal;
 }
 
+bool StreamInWorkerLogic::readMmap(StreamDescriptor::Reply* reply) {
+    void* buffer = nullptr;
+    size_t frameCount = 0;
+    size_t actualFrameCount = 0;
+    int32_t latency = mContext->getNominalLatencyMs();
+    // use default-initialized parameter values for mmap stream.
+    if (::android::status_t status =
+                mDriver->transfer(buffer, frameCount, &actualFrameCount, &latency);
+        status == ::android::OK) {
+        populateReply(reply, mIsConnected);
+        reply->latencyMs = latency;
+        return true;
+    } else {
+        LOG(ERROR) << __func__ << ": transfer failed: " << status;
+        return false;
+    }
+}
+
 const std::string StreamOutWorkerLogic::kThreadName = "writer";
 
 void StreamOutWorkerLogic::onBufferStateChange(size_t bufferFramesLeft) {
     const StreamDescriptor::State state = mState;
-    LOG(DEBUG) << __func__ << ": state: " << toString(state)
+    const DrainState drainState = mDrainState;
+    LOG(DEBUG) << __func__ << ": state: " << toString(state) << ", drainState: " << drainState
                << ", bufferFramesLeft: " << bufferFramesLeft;
-    if (state == StreamDescriptor::State::TRANSFERRING) {
-        mState = StreamDescriptor::State::ACTIVE;
+    if (state == StreamDescriptor::State::TRANSFERRING || drainState == DrainState::EN_SENT) {
+        if (state == StreamDescriptor::State::TRANSFERRING) {
+            mState = StreamDescriptor::State::ACTIVE;
+        }
         std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
         if (asyncCallback != nullptr) {
+            LOG(VERBOSE) << __func__ << ": sending onTransferReady";
             ndk::ScopedAStatus status = asyncCallback->onTransferReady();
             if (!status.isOk()) {
                 LOG(ERROR) << __func__ << ": error from onTransferReady: " << status;
@@ -411,8 +446,10 @@
         mState =
                 hasNextClip ? StreamDescriptor::State::TRANSFERRING : StreamDescriptor::State::IDLE;
         mDrainState = DrainState::NONE;
-        if (drainState == DrainState::ALL && asyncCallback != nullptr) {
+        if ((drainState == DrainState::ALL || drainState == DrainState::EN_SENT) &&
+            asyncCallback != nullptr) {
             LOG(DEBUG) << __func__ << ": sending onDrainReady";
+            // For EN_SENT, this is the second onDrainReady which notifies about clip transition.
             ndk::ScopedAStatus status = asyncCallback->onDrainReady();
             if (!status.isOk()) {
                 LOG(ERROR) << __func__ << ": error from onDrainReady: " << status;
@@ -523,9 +560,9 @@
                 if (mState != StreamDescriptor::State::ERROR &&
                     mState != StreamDescriptor::State::TRANSFERRING &&
                     mState != StreamDescriptor::State::TRANSFER_PAUSED) {
-                    if (hasMmapFlag(mContext->getFlags())) {
-                        populateReply(&reply, mIsConnected);
-                    } else if (!write(fmqByteCount, &reply)) {
+                    if (bool success = mContext->isMmap() ? writeMmap(&reply)
+                                                          : write(fmqByteCount, &reply);
+                        !success) {
                         mState = StreamDescriptor::State::ERROR;
                     }
                     std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
@@ -539,13 +576,17 @@
                             mState = StreamDescriptor::State::TRANSFER_PAUSED;
                         }
                     } else if (mState == StreamDescriptor::State::IDLE ||
-                               mState == StreamDescriptor::State::DRAINING ||
-                               mState == StreamDescriptor::State::ACTIVE) {
+                               mState == StreamDescriptor::State::ACTIVE ||
+                               (mState == StreamDescriptor::State::DRAINING &&
+                                mDrainState != DrainState::EN_SENT)) {
                         if (asyncCallback == nullptr || reply.fmqByteCount == fmqByteCount) {
                             mState = StreamDescriptor::State::ACTIVE;
                         } else {
                             switchToTransientState(StreamDescriptor::State::TRANSFERRING);
                         }
+                    } else if (mState == StreamDescriptor::State::DRAINING &&
+                               mDrainState == DrainState::EN_SENT) {
+                        // keep mState
                     }
                 } else {
                     populateReplyWrongState(&reply, command);
@@ -700,6 +741,24 @@
     return !fatal;
 }
 
+bool StreamOutWorkerLogic::writeMmap(StreamDescriptor::Reply* reply) {
+    void* buffer = nullptr;
+    size_t frameCount = 0;
+    size_t actualFrameCount = 0;
+    int32_t latency = mContext->getNominalLatencyMs();
+    // use default-initialized parameter values for mmap stream.
+    if (::android::status_t status =
+                mDriver->transfer(buffer, frameCount, &actualFrameCount, &latency);
+        status == ::android::OK) {
+        populateReply(reply, mIsConnected);
+        reply->latencyMs = latency;
+        return true;
+    } else {
+        LOG(ERROR) << __func__ << ": transfer failed: " << status;
+        return false;
+    }
+}
+
 StreamCommonImpl::~StreamCommonImpl() {
     // It is responsibility of the class that implements 'DriverInterface' to call 'cleanupWorker'
     // in the destructor. Note that 'cleanupWorker' can not be properly called from this destructor
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 6a43102..379264d 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -61,6 +61,8 @@
     // The vendor extension done via inheritance can override interface methods and augment
     // a call to the base implementation.
 
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
     ndk::ScopedAStatus setModuleDebug(
             const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
     ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
@@ -159,6 +161,7 @@
     // Multimap because both ports and configs can be used by multiple patches.
     using Patches = std::multimap<int32_t, int32_t>;
 
+    static const std::string kClipTransitionSupportName;
     const Type mType;
     std::unique_ptr<Configuration> mConfig;
     ModuleDebug mDebug;
@@ -209,8 +212,8 @@
             const ::aidl::android::media::audio::common::AudioFormatDescription &format,
             int32_t latencyMs, int32_t sampleRateHz, int32_t *bufferSizeFrames);
     virtual ndk::ScopedAStatus createMmapBuffer(
-            const ::aidl::android::hardware::audio::core::StreamContext& context,
-            ::aidl::android::hardware::audio::core::StreamDescriptor* desc);
+            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig,
+            int32_t bufferSizeFrames, int32_t frameSizeBytes, MmapBufferDescriptor* desc);
 
     // Utility and helper functions accessible to subclasses.
     static int32_t calculateBufferSizeFramesForPcm(int32_t latencyMs, int32_t sampleRateHz) {
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index f0139b4..bb790e9 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -104,6 +104,27 @@
           mOutEventCallback(outEventCallback),
           mStreamDataProcessor(streamDataProcessor),
           mDebugParameters(debugParameters) {}
+    StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
+                  const ::aidl::android::media::audio::common::AudioFormatDescription& format,
+                  const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
+                  int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags,
+                  int32_t nominalLatencyMs, int32_t mixPortHandle, MmapBufferDescriptor&& mmapDesc,
+                  std::shared_ptr<IStreamOutEventCallback> outEventCallback,
+                  std::weak_ptr<sounddose::StreamDataProcessorInterface> streamDataProcessor,
+                  DebugParameters debugParameters)
+        : mCommandMQ(std::move(commandMQ)),
+          mInternalCommandCookie(std::rand() | 1 /* make sure it's not 0 */),
+          mReplyMQ(std::move(replyMQ)),
+          mFormat(format),
+          mChannelLayout(channelLayout),
+          mSampleRate(sampleRate),
+          mFlags(flags),
+          mNominalLatencyMs(nominalLatencyMs),
+          mMixPortHandle(mixPortHandle),
+          mMmapBufferDesc(std::move(mmapDesc)),
+          mOutEventCallback(outEventCallback),
+          mStreamDataProcessor(streamDataProcessor),
+          mDebugParameters(debugParameters) {}
 
     void fillDescriptor(StreamDescriptor* desc);
     std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
@@ -136,6 +157,7 @@
     bool isInput() const {
         return mFlags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::input;
     }
+    bool isMmap() const { return ::aidl::android::hardware::audio::common::hasMmapFlag(mFlags); }
     bool isValid() const;
     // 'reset' is called on a Binder thread when closing the stream. Does not use
     // locking because it only cleans MQ pointers which were also set on the Binder thread.
@@ -155,7 +177,9 @@
     ::aidl::android::media::audio::common::AudioIoFlags mFlags;
     int32_t mNominalLatencyMs;
     int32_t mMixPortHandle;
+    // Only one of `mDataMQ` or `mMapBufferDesc` can be active, depending on `isMmap`
     std::unique_ptr<DataMQ> mDataMQ;
+    MmapBufferDescriptor mMmapBufferDesc;
     std::shared_ptr<IStreamCallback> mAsyncCallback;
     std::shared_ptr<IStreamOutEventCallback> mOutEventCallback;  // Only used by output streams
     std::weak_ptr<sounddose::StreamDataProcessorInterface> mStreamDataProcessor;
@@ -307,6 +331,7 @@
 
   private:
     bool read(size_t clientSize, StreamDescriptor::Reply* reply);
+    bool readMmap(StreamDescriptor::Reply* reply);
 };
 using StreamInWorker = StreamWorkerImpl<StreamInWorkerLogic>;
 
@@ -325,6 +350,7 @@
 
   private:
     bool write(size_t clientSize, StreamDescriptor::Reply* reply);
+    bool writeMmap(StreamDescriptor::Reply* reply);
 
     std::shared_ptr<IStreamOutEventCallback> mEventCallback;
 
@@ -651,6 +677,12 @@
         return ndk::ScopedAStatus::ok();
     }
 
+    void dump(int fd, const char** args, uint32_t numArgs) const {
+        auto s = ::ndk::ICInterface::asInterface(mStreamBinder.get());
+        if (s) s->dump(fd, args, numArgs);
+        return;
+    }
+
   private:
     std::weak_ptr<StreamCommonInterface> mStream;
     ndk::SpAIBinder mStreamBinder;
@@ -692,6 +724,12 @@
         }
         return ndk::ScopedAStatus::ok();
     }
+    void dump(int32_t portConfigId, int fd, const char** args, uint32_t numArgs) const {
+        if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
+            it->second.dump(fd, args, numArgs);
+        }
+        return;
+    }
 
   private:
     // Maps port ids and port config ids to streams. Multimap because a port
diff --git a/audio/aidl/default/include/core-impl/StreamOffloadStub.h b/audio/aidl/default/include/core-impl/StreamOffloadStub.h
index 67abe95..24e98c2 100644
--- a/audio/aidl/default/include/core-impl/StreamOffloadStub.h
+++ b/audio/aidl/default/include/core-impl/StreamOffloadStub.h
@@ -26,14 +26,16 @@
 namespace aidl::android::hardware::audio::core {
 
 struct DspSimulatorState {
+    static constexpr int64_t kSkipBufferNotifyFrames = -1;
+
     const std::string formatEncoding;
     const int sampleRate;
     const int64_t earlyNotifyFrames;
-    const int64_t bufferNotifyFrames;
     DriverCallbackInterface* callback = nullptr;  // set before starting DSP worker
     std::mutex lock;
     std::vector<int64_t> clipFramesLeft GUARDED_BY(lock);
-    int64_t bufferFramesLeft GUARDED_BY(lock);
+    int64_t bufferFramesLeft GUARDED_BY(lock) = 0;
+    int64_t bufferNotifyFrames GUARDED_BY(lock) = kSkipBufferNotifyFrames;
 };
 
 class DspSimulatorLogic : public ::android::hardware::audio::common::StreamLogic {
@@ -68,6 +70,7 @@
   private:
     ::android::status_t startWorkerIfNeeded();
 
+    const int64_t mBufferNotifyFrames;
     DspSimulatorState mState;
     DspSimulatorWorker mDspWorker;
     bool mDspWorkerStarted = false;
diff --git a/audio/aidl/default/stub/StreamOffloadStub.cpp b/audio/aidl/default/stub/StreamOffloadStub.cpp
index 95cef35..155f76d 100644
--- a/audio/aidl/default/stub/StreamOffloadStub.cpp
+++ b/audio/aidl/default/stub/StreamOffloadStub.cpp
@@ -42,14 +42,13 @@
     const int64_t clipFramesPlayed =
             (::android::uptimeNanos() - timeBeginNs) * mSharedState.sampleRate / NANOS_PER_SECOND;
     const int64_t bufferFramesConsumed = clipFramesPlayed / 2;  // assume 1:2 compression ratio
-    int64_t bufferFramesLeft = 0;
+    int64_t bufferFramesLeft = 0, bufferNotifyFrames = DspSimulatorState::kSkipBufferNotifyFrames;
     {
         std::lock_guard l(mSharedState.lock);
         mSharedState.bufferFramesLeft =
                 mSharedState.bufferFramesLeft > bufferFramesConsumed
                         ? mSharedState.bufferFramesLeft - bufferFramesConsumed
                         : 0;
-        bufferFramesLeft = mSharedState.bufferFramesLeft;
         int64_t framesPlayed = clipFramesPlayed;
         while (framesPlayed > 0 && !mSharedState.clipFramesLeft.empty()) {
             LOG(VERBOSE) << __func__ << ": clips: "
@@ -65,10 +64,21 @@
                 clipNotifies.emplace_back(0 /*clipFramesLeft*/, hasNextClip);
                 framesPlayed -= mSharedState.clipFramesLeft[0];
                 mSharedState.clipFramesLeft.erase(mSharedState.clipFramesLeft.begin());
+                if (!hasNextClip) {
+                    // Since it's a simulation, the buffer consumption rate it not real,
+                    // thus 'bufferFramesLeft' might still have something, need to erase it.
+                    mSharedState.bufferFramesLeft = 0;
+                }
             }
         }
+        bufferFramesLeft = mSharedState.bufferFramesLeft;
+        bufferNotifyFrames = mSharedState.bufferNotifyFrames;
+        if (bufferFramesLeft <= bufferNotifyFrames) {
+            // Suppress further notifications.
+            mSharedState.bufferNotifyFrames = DspSimulatorState::kSkipBufferNotifyFrames;
+        }
     }
-    if (bufferFramesLeft <= mSharedState.bufferNotifyFrames) {
+    if (bufferFramesLeft <= bufferNotifyFrames) {
         LOG(DEBUG) << __func__ << ": sending onBufferStateChange: " << bufferFramesLeft;
         mSharedState.callback->onBufferStateChange(bufferFramesLeft);
     }
@@ -82,9 +92,9 @@
 
 DriverOffloadStubImpl::DriverOffloadStubImpl(const StreamContext& context)
     : DriverStubImpl(context, 0 /*asyncSleepTimeUs*/),
+      mBufferNotifyFrames(static_cast<int64_t>(context.getBufferSizeInFrames()) / 2),
       mState{context.getFormat().encoding, context.getSampleRate(),
-             250 /*earlyNotifyMs*/ * context.getSampleRate() / MILLIS_PER_SECOND,
-             static_cast<int64_t>(context.getBufferSizeInFrames()) / 2},
+             250 /*earlyNotifyMs*/ * context.getSampleRate() / MILLIS_PER_SECOND},
       mDspWorker(mState) {
     LOG_IF(FATAL, !mIsAsynchronous) << "The steam must be used in asynchronous mode";
 }
@@ -111,6 +121,7 @@
             mState.clipFramesLeft.resize(1);
         }
     }
+    mState.bufferNotifyFrames = DspSimulatorState::kSkipBufferNotifyFrames;
     return ::android::OK;
 }
 
@@ -121,6 +132,7 @@
         std::lock_guard l(mState.lock);
         mState.clipFramesLeft.clear();
         mState.bufferFramesLeft = 0;
+        mState.bufferNotifyFrames = DspSimulatorState::kSkipBufferNotifyFrames;
     }
     return ::android::OK;
 }
@@ -128,6 +140,10 @@
 ::android::status_t DriverOffloadStubImpl::pause() {
     RETURN_STATUS_IF_ERROR(DriverStubImpl::pause());
     mDspWorker.pause();
+    {
+        std::lock_guard l(mState.lock);
+        mState.bufferNotifyFrames = DspSimulatorState::kSkipBufferNotifyFrames;
+    }
     return ::android::OK;
 }
 
@@ -140,6 +156,7 @@
         hasClips = !mState.clipFramesLeft.empty();
         LOG(DEBUG) << __func__
                    << ": clipFramesLeft: " << ::android::internal::ToString(mState.clipFramesLeft);
+        mState.bufferNotifyFrames = DspSimulatorState::kSkipBufferNotifyFrames;
     }
     if (hasClips) {
         mDspWorker.resume();
@@ -184,6 +201,7 @@
     {
         std::lock_guard l(mState.lock);
         mState.bufferFramesLeft = *actualFrameCount;
+        mState.bufferNotifyFrames = mBufferNotifyFrames;
     }
     mDspWorker.resume();
     return ::android::OK;
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 21b7aff..806c93f 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -1025,6 +1025,7 @@
             auto [eventSeq, event] = mEventReceiver->waitForEvent(mLastEventSeq);
             mLastEventSeq = eventSeq;
             if (event != *expEvent) {
+                // TODO: Make available as an error so it can be displayed by GTest
                 LOG(ERROR) << __func__ << ": expected event " << toString(*expEvent) << ", got "
                            << toString(event);
                 return {};
@@ -1327,7 +1328,8 @@
   public:
     // To avoid timing out the whole test suite in case no event is received
     // from the HAL, use a local timeout for event waiting.
-    static constexpr auto kEventTimeoutMs = std::chrono::milliseconds(1000);
+    // TODO: The timeout for 'onTransferReady' should depend on the buffer size.
+    static constexpr auto kEventTimeoutMs = std::chrono::milliseconds(3000);
 
     StreamEventReceiver* getEventReceiver() { return this; }
     std::tuple<int, Event> getLastEvent() const override {
@@ -4236,15 +4238,17 @@
 enum {
     NAMED_CMD_NAME,
     NAMED_CMD_MIN_INTERFACE_VERSION,
+    NAMED_CMD_FEATURE_PROPERTY,
     NAMED_CMD_DELAY_MS,
     NAMED_CMD_STREAM_TYPE,
     NAMED_CMD_CMDS,
     NAMED_CMD_VALIDATE_POS_INCREASE
 };
-enum class StreamTypeFilter { ANY, SYNC, ASYNC };
+enum class StreamTypeFilter { ANY, SYNC, ASYNC, OFFLOAD };
 using NamedCommandSequence =
-        std::tuple<std::string, int /*minInterfaceVersion*/, int /*cmdDelayMs*/, StreamTypeFilter,
-                   std::shared_ptr<StateSequence>, bool /*validatePositionIncrease*/>;
+        std::tuple<std::string, int /*minInterfaceVersion*/, std::string /*featureProperty*/,
+                   int /*cmdDelayMs*/, StreamTypeFilter, std::shared_ptr<StateSequence>,
+                   bool /*validatePositionIncrease*/>;
 enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
 using StreamIoTestParameters =
         std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
@@ -4255,11 +4259,24 @@
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(SetUpImpl(std::get<PARAM_MODULE_NAME>(GetParam())));
         ASSERT_GE(aidlVersion, kAidlVersion1);
-        if (const int minVersion =
-                    std::get<NAMED_CMD_MIN_INTERFACE_VERSION>(std::get<PARAM_CMD_SEQ>(GetParam()));
-            aidlVersion < minVersion) {
+        const int minVersion =
+                std::get<NAMED_CMD_MIN_INTERFACE_VERSION>(std::get<PARAM_CMD_SEQ>(GetParam()));
+        if (aidlVersion < minVersion) {
             GTEST_SKIP() << "Skip for audio HAL version lower than " << minVersion;
         }
+        // When an associated feature property is defined, need to check that either that the HAL
+        // exposes this property, or it's of the version 'NAMED_CMD_MIN_INTERFACE_VERSION' + 1
+        // which must have this functionality implemented by default.
+        if (const std::string featureProperty =
+                    std::get<NAMED_CMD_FEATURE_PROPERTY>(std::get<PARAM_CMD_SEQ>(GetParam()));
+            !featureProperty.empty() && aidlVersion < (minVersion + 1)) {
+            std::vector<VendorParameter> parameters;
+            ScopedAStatus result = module->getVendorParameters({featureProperty}, &parameters);
+            if (!result.isOk() || parameters.size() != 1) {
+                GTEST_SKIP() << "Skip as audio HAL does not support feature \"" << featureProperty
+                             << "\"";
+            }
+        }
         ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
     }
 
@@ -4300,10 +4317,18 @@
                             isBitPositionFlagSet(portConfig.flags.value()
                                                          .template get<AudioIoFlags::Tag::output>(),
                                                  AudioOutputFlags::NON_BLOCKING);
+            const bool isOffload =
+                    IOTraits<Stream>::is_input
+                            ? false
+                            : isBitPositionFlagSet(
+                                      portConfig.flags.value()
+                                              .template get<AudioIoFlags::Tag::output>(),
+                                      AudioOutputFlags::COMPRESS_OFFLOAD);
             if (auto streamType =
                         std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(GetParam()));
                 (isNonBlocking && streamType == StreamTypeFilter::SYNC) ||
-                (!isNonBlocking && streamType == StreamTypeFilter::ASYNC)) {
+                (!isNonBlocking && streamType == StreamTypeFilter::ASYNC) ||
+                (!isOffload && streamType == StreamTypeFilter::OFFLOAD)) {
                 continue;
             }
             WithDebugFlags delayTransientStates = WithDebugFlags::createNested(*debug);
@@ -4760,6 +4785,18 @@
 
 // TODO: Add async test cases for input once it is implemented.
 
+// Allow optional routing via the TRANSFERRING state on bursts.
+StateDag::Node makeAsyncBurstCommands(StateDag* d, size_t burstCount, StateDag::Node last) {
+    using State = StreamDescriptor::State;
+    std::reference_wrapper<std::remove_reference_t<StateDag::Node>> prev = last;
+    for (size_t i = 0; i < burstCount; ++i) {
+        StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, prev);
+        active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, prev));
+        prev = active;
+    }
+    return prev;
+}
+
 std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount,
                                                  bool standbyInputWhenDone) {
     using State = StreamDescriptor::State;
@@ -4776,25 +4813,21 @@
                 d->makeNodes(State::ACTIVE, kBurstCommand, burstCount, last));
         d->makeNode(State::STANDBY, kStartCommand, idle);
     } else {
-        StateDag::Node active2 = d->makeNode(State::ACTIVE, kBurstCommand, last);
-        StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, active2);
+        StateDag::Node active = makeAsyncBurstCommands(d.get(), burstCount, last);
         StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
-        // Allow optional routing via the TRANSFERRING state on bursts.
-        active2.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last));
-        active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active2));
         idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
         d->makeNode(State::STANDBY, kStartCommand, idle);
     }
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kReadSeq =
-        std::make_tuple(std::string("Read"), kAidlVersion1, 0, StreamTypeFilter::ANY,
+        std::make_tuple(std::string("Read"), kAidlVersion1, "", 0, StreamTypeFilter::ANY,
                         makeBurstCommands(true), true /*validatePositionIncrease*/);
 static const NamedCommandSequence kWriteSyncSeq =
-        std::make_tuple(std::string("Write"), kAidlVersion1, 0, StreamTypeFilter::SYNC,
+        std::make_tuple(std::string("Write"), kAidlVersion1, "", 0, StreamTypeFilter::SYNC,
                         makeBurstCommands(true), true /*validatePositionIncrease*/);
 static const NamedCommandSequence kWriteAsyncSeq =
-        std::make_tuple(std::string("Write"), kAidlVersion1, 0, StreamTypeFilter::ASYNC,
+        std::make_tuple(std::string("Write"), kAidlVersion1, "", 0, StreamTypeFilter::ASYNC,
                         makeBurstCommands(false), true /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
@@ -4824,10 +4857,10 @@
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kWriteDrainAsyncSeq = std::make_tuple(
-        std::string("WriteDrain"), kAidlVersion1, kStreamTransientStateTransitionDelayMs,
+        std::string("WriteDrain"), kAidlVersion1, "", kStreamTransientStateTransitionDelayMs,
         StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false), false /*validatePositionIncrease*/);
 static const NamedCommandSequence kDrainInSeq =
-        std::make_tuple(std::string("Drain"), kAidlVersion1, 0, StreamTypeFilter::ANY,
+        std::make_tuple(std::string("Drain"), kAidlVersion1, "", 0, StreamTypeFilter::ANY,
                         makeAsyncDrainCommands(true), false /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
@@ -4849,10 +4882,10 @@
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kDrainOutSyncSeq =
-        std::make_tuple(std::string("Drain"), kAidlVersion1, 0, StreamTypeFilter::SYNC,
+        std::make_tuple(std::string("Drain"), kAidlVersion1, "", 0, StreamTypeFilter::SYNC,
                         makeDrainOutCommands(true), false /*validatePositionIncrease*/);
 static const NamedCommandSequence kDrainOutAsyncSeq =
-        std::make_tuple(std::string("Drain"), kAidlVersion3, 0, StreamTypeFilter::ASYNC,
+        std::make_tuple(std::string("Drain"), kAidlVersion3, "", 0, StreamTypeFilter::ASYNC,
                         makeDrainOutCommands(false), false /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makeDrainEarlyOutCommands() {
@@ -4873,9 +4906,32 @@
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kDrainEarlyOutAsyncSeq =
-        std::make_tuple(std::string("DrainEarly"), kAidlVersion3, 0, StreamTypeFilter::ASYNC,
+        std::make_tuple(std::string("DrainEarly"), kAidlVersion3, "", 0, StreamTypeFilter::ASYNC,
                         makeDrainEarlyOutCommands(), false /*validatePositionIncrease*/);
 
+// DRAINING_en ->(onDrainReady) DRAINING_en_sent ->(onDrainReady) IDLE | TRANSFERRING
+std::shared_ptr<StateSequence> makeDrainEarlyOffloadCommands() {
+    using State = StreamDescriptor::State;
+    auto d = std::make_unique<StateDag>();
+    StateDag::Node lastIdle = d->makeFinalNode(State::IDLE);
+    StateDag::Node lastTransferring = d->makeFinalNode(State::TRANSFERRING);
+    // The second onDrainReady event.
+    StateDag::Node continueDraining =
+            d->makeNode(State::DRAINING, kDrainReadyEvent, lastIdle, lastTransferring);
+    // The first onDrainReady event.
+    StateDag::Node draining = d->makeNode(State::DRAINING, kDrainReadyEvent, continueDraining);
+    StateDag::Node drain = d->makeNode(State::ACTIVE, kDrainOutEarlyCommand, draining);
+    StateDag::Node active = makeAsyncBurstCommands(d.get(), 10, drain);
+    StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+    idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
+    d->makeNode(State::STANDBY, kStartCommand, idle);
+    return std::make_shared<StateSequenceFollower>(std::move(d));
+}
+static const NamedCommandSequence kDrainEarlyOffloadSeq =
+        std::make_tuple(std::string("DrainEarly"), kAidlVersion3, "aosp.clipTransitionSupport", 0,
+                        StreamTypeFilter::OFFLOAD, makeDrainEarlyOffloadCommands(),
+                        true /*validatePositionIncrease*/);
+
 std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
     using State = StreamDescriptor::State;
     auto d = std::make_unique<StateDag>();
@@ -4896,11 +4952,11 @@
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kDrainPauseOutSyncSeq =
-        std::make_tuple(std::string("DrainPause"), kAidlVersion1,
+        std::make_tuple(std::string("DrainPause"), kAidlVersion1, "",
                         kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC,
                         makeDrainPauseOutCommands(true), false /*validatePositionIncrease*/);
 static const NamedCommandSequence kDrainPauseOutAsyncSeq =
-        std::make_tuple(std::string("DrainPause"), kAidlVersion1,
+        std::make_tuple(std::string("DrainPause"), kAidlVersion1, "",
                         kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
                         makeDrainPauseOutCommands(false), false /*validatePositionIncrease*/);
 
@@ -4919,7 +4975,7 @@
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kDrainEarlyPauseOutAsyncSeq =
-        std::make_tuple(std::string("DrainEarlyPause"), kAidlVersion3,
+        std::make_tuple(std::string("DrainEarlyPause"), kAidlVersion3, "",
                         kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
                         makeDrainEarlyPauseOutCommands(), false /*validatePositionIncrease*/);
 
@@ -4963,13 +5019,13 @@
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kStandbyInSeq =
-        std::make_tuple(std::string("Standby"), kAidlVersion1, 0, StreamTypeFilter::ANY,
+        std::make_tuple(std::string("Standby"), kAidlVersion1, "", 0, StreamTypeFilter::ANY,
                         makeStandbyCommands(true, false), false /*validatePositionIncrease*/);
 static const NamedCommandSequence kStandbyOutSyncSeq =
-        std::make_tuple(std::string("Standby"), kAidlVersion1, 0, StreamTypeFilter::SYNC,
+        std::make_tuple(std::string("Standby"), kAidlVersion1, "", 0, StreamTypeFilter::SYNC,
                         makeStandbyCommands(false, true), false /*validatePositionIncrease*/);
 static const NamedCommandSequence kStandbyOutAsyncSeq =
-        std::make_tuple(std::string("Standby"), kAidlVersion1,
+        std::make_tuple(std::string("Standby"), kAidlVersion1, "",
                         kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
                         makeStandbyCommands(false, false), false /*validatePositionIncrease*/);
 
@@ -5006,15 +5062,15 @@
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kPauseInSeq =
-        std::make_tuple(std::string("Pause"), kAidlVersion1, 0, StreamTypeFilter::ANY,
+        std::make_tuple(std::string("Pause"), kAidlVersion1, "", 0, StreamTypeFilter::ANY,
                         makePauseCommands(true, false), false /*validatePositionIncrease*/);
 static const NamedCommandSequence kPauseOutSyncSeq =
-        std::make_tuple(std::string("Pause"), kAidlVersion1, 0, StreamTypeFilter::SYNC,
+        std::make_tuple(std::string("Pause"), kAidlVersion1, "", 0, StreamTypeFilter::SYNC,
                         makePauseCommands(false, true), false /*validatePositionIncrease*/);
 static const NamedCommandSequence kPauseOutAsyncSeq =
-        std::make_tuple(std::string("Pause"), kAidlVersion3, kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::ASYNC, makePauseCommands(false, false),
-                        false /*validatePositionIncrease*/);
+        std::make_tuple(std::string("Pause"), kAidlVersion3, "",
+                        kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+                        makePauseCommands(false, false), false /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
     using State = StreamDescriptor::State;
@@ -5042,15 +5098,15 @@
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kFlushInSeq =
-        std::make_tuple(std::string("Flush"), kAidlVersion1, 0, StreamTypeFilter::ANY,
+        std::make_tuple(std::string("Flush"), kAidlVersion1, "", 0, StreamTypeFilter::ANY,
                         makeFlushCommands(true, false), false /*validatePositionIncrease*/);
 static const NamedCommandSequence kFlushOutSyncSeq =
-        std::make_tuple(std::string("Flush"), kAidlVersion1, 0, StreamTypeFilter::SYNC,
+        std::make_tuple(std::string("Flush"), kAidlVersion1, "", 0, StreamTypeFilter::SYNC,
                         makeFlushCommands(false, true), false /*validatePositionIncrease*/);
 static const NamedCommandSequence kFlushOutAsyncSeq =
-        std::make_tuple(std::string("Flush"), kAidlVersion1, kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::ASYNC, makeFlushCommands(false, false),
-                        false /*validatePositionIncrease*/);
+        std::make_tuple(std::string("Flush"), kAidlVersion1, "",
+                        kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+                        makeFlushCommands(false, false), false /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
     using State = StreamDescriptor::State;
@@ -5070,11 +5126,11 @@
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
-        std::make_tuple(std::string("DrainPauseFlush"), kAidlVersion1,
+        std::make_tuple(std::string("DrainPauseFlush"), kAidlVersion1, "",
                         kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC,
                         makeDrainPauseFlushOutCommands(true), false /*validatePositionIncrease*/);
 static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq =
-        std::make_tuple(std::string("DrainPauseFlush"), kAidlVersion1,
+        std::make_tuple(std::string("DrainPauseFlush"), kAidlVersion1, "",
                         kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
                         makeDrainPauseFlushOutCommands(false), false /*validatePositionIncrease*/);
 
@@ -5087,6 +5143,8 @@
             return "Sync";
         case StreamTypeFilter::ASYNC:
             return "Async";
+        case StreamTypeFilter::OFFLOAD:
+            return "Offload";
     }
     return std::string("Unknown").append(std::to_string(static_cast<int32_t>(filter)));
 }
@@ -5119,7 +5177,8 @@
                                          kDrainPauseOutAsyncSeq, kDrainEarlyPauseOutAsyncSeq,
                                          kStandbyOutSyncSeq, kStandbyOutAsyncSeq, kPauseOutSyncSeq,
                                          kPauseOutAsyncSeq, kFlushOutSyncSeq, kFlushOutAsyncSeq,
-                                         kDrainPauseFlushOutSyncSeq, kDrainPauseFlushOutAsyncSeq),
+                                         kDrainPauseFlushOutSyncSeq, kDrainPauseFlushOutAsyncSeq,
+                                         kDrainEarlyOffloadSeq),
                          testing::Values(false, true)),
         GetStreamIoTestName);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoOut);
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
index 74f00c0..2ce7b51 100644
--- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -596,10 +596,10 @@
 }
 
 DynamicsProcessing::EqBandConfig creatEqBandConfig(int channel, int band, float cutOffFreqHz,
-                                                   float gainDb) {
+                                                   float gainDb, bool enable) {
     return DynamicsProcessing::EqBandConfig{.channel = channel,
                                             .band = band,
-                                            .enable = true,
+                                            .enable = enable,
                                             .cutoffFrequencyHz = cutOffFreqHz,
                                             .gainDb = gainDb};
 }
@@ -1092,7 +1092,8 @@
     int bandCount = cutOffFreqs.size();
     for (int i = 0; i < bandCount; i++) {
         cfgs.push_back(creatEqBandConfig(std::get<EQ_BAND_CHANNEL>(params), cutOffFreqs[i].first,
-                                         cutOffFreqs[i].second, std::get<EQ_BAND_GAIN>(params)));
+                                         cutOffFreqs[i].second, std::get<EQ_BAND_GAIN>(params),
+                                         true));
     }
 }
 
@@ -1240,15 +1241,16 @@
     }
 
     void fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig>& cfgs, int channelIndex,
-                          int bandIndex, int cutOffFreqHz, float gainDb) {
+                          int bandIndex, int cutOffFreqHz, float gainDb, bool enable) {
         cfgs.push_back(creatEqBandConfig(channelIndex, bandIndex, static_cast<float>(cutOffFreqHz),
-                                         gainDb));
+                                         gainDb, enable));
     }
 
-    void validateOutput(const std::vector<float>& output, float gainDb, size_t bandIndex) {
+    void validateOutput(const std::vector<float>& output, float gainDb, size_t bandIndex,
+                        bool enable) {
         std::vector<float> outputMag(mBinOffsets.size());
         EXPECT_NO_FATAL_FAILURE(getMagnitudeValue(output, outputMag));
-        if (gainDb == 0) {
+        if (gainDb == 0 || !enable) {
             EXPECT_NO_FATAL_FAILURE(checkInputAndOutputEquality(outputMag));
         } else if (gainDb > 0) {
             // For positive gain, current band's magnitude is greater than the other band's
@@ -1260,19 +1262,19 @@
         }
     }
 
-    void analyseMultiBandOutput(float gainDb, bool isPreEq) {
+    void analyseMultiBandOutput(float gainDb, bool isPreEq, bool enable = true) {
         std::vector<float> output(mInput.size());
         roundToFreqCenteredToFftBin(mMultitoneTestFrequencies, mBinOffsets, kBinWidth);
         // Set Equalizer values for two bands
         for (size_t i = 0; i < kCutoffFreqHz.size(); i++) {
             for (int channelIndex = 0; channelIndex < mChannelCount; channelIndex++) {
-                fillEqBandConfig(mCfgs, channelIndex, i, kCutoffFreqHz[i], gainDb);
-                fillEqBandConfig(mCfgs, channelIndex, i ^ 1, kCutoffFreqHz[i ^ 1], 0);
+                fillEqBandConfig(mCfgs, channelIndex, i, kCutoffFreqHz[i], gainDb, enable);
+                fillEqBandConfig(mCfgs, channelIndex, i ^ 1, kCutoffFreqHz[i ^ 1], 0, enable);
             }
             ASSERT_NO_FATAL_FAILURE(setEqParamAndProcess(output, isPreEq));
 
             if (isAllParamsValid()) {
-                ASSERT_NO_FATAL_FAILURE(validateOutput(output, gainDb, i));
+                ASSERT_NO_FATAL_FAILURE(validateOutput(output, gainDb, i, enable));
             }
             cleanUpEqConfig();
         }
@@ -1308,6 +1310,16 @@
     }
 }
 
+TEST_P(DynamicsProcessingEqBandConfigDataTest, PreEqEnableDisable) {
+    ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(10 /*gain dB*/, true /*pre-equalizer*/,
+                                                   false /*disable equalizer*/));
+}
+
+TEST_P(DynamicsProcessingEqBandConfigDataTest, PostEqEnableDisable) {
+    ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(10 /*gain dB*/, false /*post-equalizer*/,
+                                                   false /*disable equalizer*/));
+}
+
 INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingEqBandConfigDataTest,
                          testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
                                  IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
index 0c931ff..86177fc 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -18,10 +18,10 @@
 #include <string>
 #include <vector>
 
+#define LOG_TAG "VtsHalEqualizerTest"
 #include <aidl/Gtest.h>
 #include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
-#define LOG_TAG "VtsHalEqualizerTest"
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android/binder_interface_utils.h>
@@ -48,8 +48,8 @@
  */
 
 enum ParamName { PARAM_INSTANCE_NAME, PARAM_PRESET, PARAM_BAND_LEVEL };
-using EqualizerParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int,
-                                           std::vector<Equalizer::BandLevel>>;
+using EqualizerTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int,
+                                      std::vector<Equalizer::BandLevel>>;
 
 /*
 Testing parameter range, assuming the parameter supported by effect is in this range.
@@ -58,38 +58,34 @@
 */
 const std::vector<int> kBandLevels = {0, -10, 10};  // needs update with implementation
 
-class EqualizerTest : public ::testing::TestWithParam<EqualizerParamTestParam>,
-                      public EffectHelper {
+class EqualizerTestHelper : public EffectHelper {
   public:
-    EqualizerTest()
-        : mPresetIndex(std::get<PARAM_PRESET>(GetParam())),
-          mBandLevel(std::get<PARAM_BAND_LEVEL>(GetParam())) {
-        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    EqualizerTestHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> descPair,
+                        int presetIndex = 0,
+                        std::vector<Equalizer::BandLevel> bandLevel =
+                                std::vector<Equalizer::BandLevel>{
+                                        Equalizer::BandLevel({.index = 0, .levelMb = 0})})
+        : mFactory(descPair.first), mPresetIndex(presetIndex), mBandLevel(bandLevel) {
+        mDescriptor = descPair.second;
     }
 
-    void SetUp() override {
+    void SetUpEqualizer() {
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Common common = createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
-        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &mOpenEffectReturn, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
     }
-    void TearDown() override {
+
+    void TearDownEqualizer() {
         ASSERT_NO_FATAL_FAILURE(close(mEffect));
         ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+        mOpenEffectReturn = IEffect::OpenEffectReturn{};
     }
 
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
-    std::shared_ptr<IFactory> mFactory;
-    std::shared_ptr<IEffect> mEffect;
-    Descriptor mDescriptor;
-    int mPresetIndex;
-    std::vector<Equalizer::BandLevel> mBandLevel;
-
     void SetAndGetEqualizerParameters() {
         ASSERT_NE(nullptr, mEffect);
         for (auto& it : mTags) {
@@ -167,26 +163,45 @@
         mTags.push_back({Equalizer::preset, Equalizer::make<Equalizer::preset>(preset)});
     }
 
-    void addBandLevelsParam(std::vector<Equalizer::BandLevel>& bandLevels) {
+    void addBandLevelsParam(const std::vector<Equalizer::BandLevel>& bandLevels) {
         mTags.push_back(
                 {Equalizer::bandLevels, Equalizer::make<Equalizer::bandLevels>(bandLevels)});
     }
 
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    const std::shared_ptr<IFactory> mFactory;
+    const int mPresetIndex;
+    const std::vector<Equalizer::BandLevel> mBandLevel;
+    std::shared_ptr<IEffect> mEffect;
+    IEffect::OpenEffectReturn mOpenEffectReturn;
+
   private:
     std::vector<std::pair<Equalizer::Tag, Equalizer>> mTags;
-
     void CleanUp() { mTags.clear(); }
 };
 
-TEST_P(EqualizerTest, SetAndGetParams) {
+class EqualizerParamTest : public ::testing::TestWithParam<EqualizerTestParam>,
+                           public EqualizerTestHelper {
+  public:
+    EqualizerParamTest()
+        : EqualizerTestHelper(std::get<PARAM_INSTANCE_NAME>(GetParam()),
+                              std::get<PARAM_PRESET>(GetParam()),
+                              std::get<PARAM_BAND_LEVEL>(GetParam())) {}
+
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpEqualizer()); }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownEqualizer()); }
+};
+
+TEST_P(EqualizerParamTest, SetAndGetParams) {
     addBandLevelsParam(mBandLevel);
     addPresetParam(mPresetIndex);
-    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+    ASSERT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
 }
 
 std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
 INSTANTIATE_TEST_SUITE_P(
-        EqualizerTest, EqualizerTest,
+        EqualizerParamTest, EqualizerParamTest,
         ::testing::Combine(
                 testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
                                           IFactory::descriptor, getEffectTypeUuidEqualizer())),
@@ -200,7 +215,7 @@
                                 [](std::set<std::vector<Equalizer::BandLevel>>& bandLevels) {
                                     return bandLevels;
                                 }))),
-        [](const testing::TestParamInfo<EqualizerTest::ParamType>& info) {
+        [](const testing::TestParamInfo<EqualizerParamTest::ParamType>& info) {
             auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
             std::string bandLevel =
                     ::android::internal::ToString(std::get<PARAM_BAND_LEVEL>(info.param));
@@ -211,7 +226,7 @@
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
         });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerParamTest);
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index 9ca4366..cb1b94b 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -40,7 +40,8 @@
      * Note that this property only represents the minimum value at boot time
      * and may not represent the current actual minimum value.
      *
-     * Only applicable for {@code INT32} type property. Ignored for other types.
+     * Only applicable for {@code INT32} type property. For other types, must be
+     * 0.
      *
      * For certain properties, this field must be specified, see
      * {@code VehicleProperty} documentation.
@@ -60,10 +61,13 @@
      * boot time, both {@code minInt32Value} and {@code maxInt32Value} must be
      * set to 0.
      *
-     * Note that this property only represents the minimum value at boot time
-     * and may not represent the current actual minimum value.
+     * Note that this property only represents the maximum value at boot time
+     * and may not represent the current actual maximum value.
      *
-     * Only applicable for {@code INT32} type property. Ignored for other types.
+     * Only applicable for {@code INT32} type property. For other types, must be
+     * 0.
+     *
+     * Must be larger or equal to {@code minInt32Value}.
      *
      * For certain properties, this field must be specified, see
      * {@code VehicleProperty} documentation.
@@ -86,7 +90,8 @@
      * Note that this property only represents the minimum value at boot time
      * and may not represent the current actual minimum value.
      *
-     * Only applicable for {@code INT64} type property. Ignored for other types.
+     * Only applicable for {@code INT64} type property. For other types, must be
+     * 0.
      *
      * For certain properties, this field must be specified, see
      * {@code VehicleProperty} documentation.
@@ -106,10 +111,13 @@
      * boot time, both {@code minInt64Value} and {@code maxInt64Value} must be
      * set to 0.
      *
-     * Note that this property only represents the minimum value at boot time
-     * and may not represent the current actual minimum value.
+     * Note that this property only represents the maximum value at boot time
+     * and may not represent the current actual maximum value.
      *
-     * Only applicable for {@code INT64} type property. Ignored for other types.
+     * Only applicable for {@code INT64} type property. For other types, must be
+     * 0.
+     *
+     * Must be larger or equal to {@code minInt64Value}.
      *
      * For certain properties, this field must be specified, see
      * {@code VehicleProperty} documentation.
@@ -132,7 +140,8 @@
      * Note that this property only represents the minimum value at boot time
      * and may not represent the current actual minimum value.
      *
-     * Only applicable for {@code FLOAT} type property. Ignored for other types.
+     * Only applicable for {@code FLOAT} type property. For other types, must be
+     * 0.
      *
      * For certain properties, this field must be specified, see
      * {@code VehicleProperty} documentation.
@@ -152,10 +161,13 @@
      * boot time, both {@code minFloatValue} and {@code maxFloatValue} must be
      * set to 0.
      *
-     * Note that this property only represents the minimum value at boot time
-     * and may not represent the current actual minimum value.
+     * Note that this property only represents the maximum value at boot time
+     * and may not represent the current actual maximum value.
      *
-     * Only applicable for {@code FLOAT} type property. Ignored for other types.
+     * Only applicable for {@code FLOAT} type property. For other types, must be
+     * 0.
+     *
+     * Must be larger or equal to {@code minFloatValue}.
      *
      * For certain properties, this field must be specified, see
      * {@code VehicleProperty} documentation.
diff --git a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
index 92681de..e7c03ad 100644
--- a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
+++ b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
@@ -1215,7 +1215,7 @@
             {
                 "name": "REMOVE_USER",
                 "value": 299896586,
-                "description": "Called by the Android System after an Android user was removed.\nThe HAL can use this property to remove its equivalent user.\nThis is write-only call - the Android System is not expecting a reply from the HAL. Hence, this request should not fail - if the equivalent HAL user cannot be removed, then HAL should mark it as inactive or recover in some other way.\nThe request is made by setting the VehiclePropValue with the contents defined by RemoveUserRequest.\nFor example, if system had 3 users (0, 10, and 11) and user 11 was removed, the request would be:\nint32[0]: 42  \/\/ request id int32[1]: 11  \/\/ (Android user id of the removed user) int32[2]: 0   \/\/ (Android user flags of the removed user) int32[3]: 10  \/\/ current user int32[4]: 0   \/\/ current user flags (none) int32[5]: 2   \/\/ number of users int32[6]: 0   \/\/ 1st user (user 0) int32[7]: 0   \/\/ 1st user flags (none) int32[8]: 10  \/\/ 2nd user (user 10) int32[9]: 0   \/\/ 2nd user flags (none)"
+                "description": "Called by the Android System after an Android user was removed.\nThe HAL can use this property to remove its equivalent user.\nThis is write-only call - the Android System is not expecting a reply from the HAL. Hence, this request should not fail - if the equivalent HAL user cannot be removed, then HAL should mark it as inactive or recover in some other way.\nThe request is made by setting the VehiclePropValue with the contents defined by RemoveUserRequest.\nFor example, if system had 3 users (0, 10, and 11) and user 11 was removed, the request would be:\nint32[0]: 42  \/\/ request id int32[1]: 11  \/\/ (Android user id of the removed user) int32[2]: 0   \/\/ (Android user flags of the removed user) int32[3]: 10  \/\/ current user int32[4]: 0   \/\/ current user flags (none) int32[5]: 2   \/\/ number of users int32[6]: 0   \/\/ 1st user (user 0) int32[7]: 0   \/\/ 1st user flags (none) int32[8]: 10  \/\/ 2nd user (user 10) int32[9]: 0   \/\/ 2nd user flags (none)\nBefore Android B, this property's change mode was defined as STATIC although the property value may be updated from Android side. For backward compatibility, we still allow STATIC as change mode, but for new implementations, ON_CHANGE should be used instead."
             },
             {
                 "name": "USER_IDENTIFICATION_ASSOCIATION",
diff --git a/automotive/vehicle/aidl/generated_lib/4/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/4/cpp/ChangeModeForVehicleProperty.h
index ca07ecf..685b010 100644
--- a/automotive/vehicle/aidl/generated_lib/4/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/4/cpp/ChangeModeForVehicleProperty.h
@@ -235,7 +235,7 @@
         {VehicleProperty::INITIAL_USER_INFO, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SWITCH_USER, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::CREATE_USER, VehiclePropertyChangeMode::ON_CHANGE},
-        {VehicleProperty::REMOVE_USER, VehiclePropertyChangeMode::STATIC},
+        {VehicleProperty::REMOVE_USER, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::EVS_SERVICE_REQUEST, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::POWER_POLICY_REQ, VehiclePropertyChangeMode::ON_CHANGE},
diff --git a/automotive/vehicle/aidl/generated_lib/4/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/4/java/ChangeModeForVehicleProperty.java
index cf44887..39a9c42 100644
--- a/automotive/vehicle/aidl/generated_lib/4/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/4/java/ChangeModeForVehicleProperty.java
@@ -233,7 +233,7 @@
         Map.entry(VehicleProperty.INITIAL_USER_INFO, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SWITCH_USER, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.CREATE_USER, VehiclePropertyChangeMode.ON_CHANGE),
-        Map.entry(VehicleProperty.REMOVE_USER, VehiclePropertyChangeMode.STATIC),
+        Map.entry(VehicleProperty.REMOVE_USER, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.USER_IDENTIFICATION_ASSOCIATION, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.EVS_SERVICE_REQUEST, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.POWER_POLICY_REQ, VehiclePropertyChangeMode.ON_CHANGE),
diff --git a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 4eb84dd..be909c5 100644
--- a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -2091,7 +2091,7 @@
     }
 
     triggerSupportedValueChange(propId, areaId);
-    return StringPrintf("Min/Max supported value for propId: %s, areaId: %s set",
+    return StringPrintf("Min/Max supported value for propId: %s, areaId: %s set\n",
                         maybeInfo->propIdStr.c_str(), maybeInfo->propIdStr.c_str());
 }
 
@@ -2135,7 +2135,7 @@
                 *maybeSupportedValues;
     }
     triggerSupportedValueChange(maybeInfo->propId, maybeInfo->areaId);
-    return StringPrintf("Supported values list for propId: %s, areaId: %s set",
+    return StringPrintf("Supported values list for propId: %s, areaId: %s set\n",
                         maybeInfo->propIdStr.c_str(), maybeInfo->propIdStr.c_str());
 }
 
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 2f1b277..cf9ea10 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -5716,7 +5716,11 @@
      * int32[8]: 10  // 2nd user (user 10)
      * int32[9]: 0   // 2nd user flags (none)
      *
-     * @change_mode VehiclePropertyChangeMode.STATIC
+     * Before Android B, this property's change mode was defined as STATIC although the property
+     * value may be updated from Android side. For backward compatibility, we still allow STATIC
+     * as change mode, but for new implementations, ON_CHANGE should be used instead.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
      * @version 2
      */
diff --git a/automotive/vehicle/tools/generate_annotation_enums.py b/automotive/vehicle/tools/generate_annotation_enums.py
index 44a810e..592cadd 100755
--- a/automotive/vehicle/tools/generate_annotation_enums.py
+++ b/automotive/vehicle/tools/generate_annotation_enums.py
@@ -51,17 +51,17 @@
 SCRIPT_PATH = 'hardware/interfaces/automotive/vehicle/tools/generate_annotation_enums.py'
 
 TAB = '    '
-RE_ENUM_START = re.compile('\s*enum VehicleProperty \{')
-RE_ENUM_END = re.compile('\s*\}\;')
-RE_COMMENT_BEGIN = re.compile('\s*\/\*\*?')
-RE_COMMENT_END = re.compile('\s*\*\/')
-RE_CHANGE_MODE = re.compile('\s*\* @change_mode (\S+)\s*')
-RE_VERSION = re.compile('\s*\* @version (\S+)\s*')
-RE_ACCESS = re.compile('\s*\* @access (\S+)\s*')
-RE_DATA_ENUM = re.compile('\s*\* @data_enum (\S+)\s*')
-RE_UNIT = re.compile('\s*\* @unit (\S+)\s+')
-RE_VALUE = re.compile('\s*(\w+)\s*=(.*)')
-RE_ANNOTATION = re.compile('\s*\* @(\S+)\s*')
+RE_ENUM_START = re.compile(r'\s*enum VehicleProperty \{')
+RE_ENUM_END = re.compile(r'\s*\}\;')
+RE_COMMENT_BEGIN = re.compile(r'\s*\/\*\*?')
+RE_COMMENT_END = re.compile(r'\s*\*\/')
+RE_CHANGE_MODE = re.compile(r'\s*\* @change_mode (\S+)\s*')
+RE_VERSION = re.compile(r'\s*\* @version (\S+)\s*')
+RE_ACCESS = re.compile(r'\s*\* @access (\S+)\s*')
+RE_DATA_ENUM = re.compile(r'\s*\* @data_enum (\S+)\s*')
+RE_UNIT = re.compile(r'\s*\* @unit (\S+)\s+')
+RE_VALUE = re.compile(r'\s*(\w+)\s*=(.*)')
+RE_ANNOTATION = re.compile(r'\s*\* @(\S+)\s*')
 
 SUPPORTED_ANNOTATIONS = ['change_mode', 'access', 'unit', 'data_enum', 'data_enum_bit_flags',
     'version', 'require_min_max_supported_value', 'require_supported_values_list',
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 7f5e06d..f249cf6 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -1248,9 +1248,21 @@
         }
     }
 
-    EXPECT_EQ(actualChangeMode, expectedChangeMode)
-            << StringPrintf("Expect to get VehiclePropertyChangeMode: %i, got %i",
-                            expectedChangeMode, actualChangeMode);
+    if (actualPropId != toInt(VehicleProperty::REMOVE_USER)) {
+        EXPECT_EQ(actualChangeMode, expectedChangeMode)
+                << StringPrintf("Expect to get VehiclePropertyChangeMode: %i, got %i",
+                                expectedChangeMode, actualChangeMode);
+    } else {
+        // Special logic for REMOVE_USER property. We allow both STATIC and ON_CHANGE change mode
+        // because historically we define the change mode to be STATIC which is incorrect, it should
+        // be on_change. For backward compatibility, we have to allow both.
+        EXPECT_THAT(actualChangeMode, ::testing::AnyOf(toInt(VehiclePropertyChangeMode::STATIC),
+                                                       toInt(VehiclePropertyChangeMode::ON_CHANGE)))
+                << StringPrintf(
+                           "Expect to get VehiclePropertyChangeMode as one of: "
+                           "[STATIC, ON_CHANGE], got %i",
+                           actualChangeMode);
+    }
 
     std::unordered_set<std::string> annotations;
     auto it = AnnotationsForVehicleProperty.find(param.propId);
diff --git a/bluetooth/audio/flags/btaudiohal.aconfig b/bluetooth/audio/flags/btaudiohal.aconfig
index 13e2116..35e84de 100644
--- a/bluetooth/audio/flags/btaudiohal.aconfig
+++ b/bluetooth/audio/flags/btaudiohal.aconfig
@@ -13,4 +13,11 @@
     namespace: "pixel_bluetooth"
     description: "Flag for reporting lea broadcast audio config to HAL"
     bug: "321168976"
-}
\ No newline at end of file
+}
+
+flag {
+    name: "leaudio_sw_offload"
+    namespace: "pixel_bluetooth"
+    description: "Flag for using sw offload path to send premium audio"
+    bug: "398885696"
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AlertUrgency.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AlertUrgency.aidl
index c7bfdbc..daebb4e 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/AlertUrgency.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AlertUrgency.aidl
@@ -17,7 +17,7 @@
 package android.hardware.broadcastradio;
 
 /**
- * The severity of the subject event of the emergency alert message.
+ * The urgency of the subject event of the emergency alert message.
  *
  * <p>(see ITU-T X.1303 bis for more info).
  */
diff --git a/compatibility_matrices/compatibility_matrix.202504.xml b/compatibility_matrices/compatibility_matrix.202504.xml
index 8d5a50a..85702e2 100644
--- a/compatibility_matrices/compatibility_matrix.202504.xml
+++ b/compatibility_matrices/compatibility_matrix.202504.xml
@@ -523,6 +523,14 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" exclusive-to="virtual-machine">
+        <name>android.hardware.security.see.storage</name>
+        <version>1</version>
+        <interface>
+            <name>ISecureStorage</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.security.secureclock</name>
         <version>1</version>
diff --git a/compatibility_matrices/compatibility_matrix.202604.xml b/compatibility_matrices/compatibility_matrix.202604.xml
index 793b166..46b04c9 100644
--- a/compatibility_matrices/compatibility_matrix.202604.xml
+++ b/compatibility_matrices/compatibility_matrix.202604.xml
@@ -523,6 +523,14 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" exclusive-to="virtual-machine">
+        <name>android.hardware.security.see.storage</name>
+        <version>1</version>
+        <interface>
+            <name>ISecureStorage</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.security.secureclock</name>
         <version>1</version>
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 4f2ed2f..7810213 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -58,12 +58,6 @@
         for (const auto& display : mAllDisplays) {
             // explicitly disable vsync
             EXPECT_TRUE(mComposerClient->setVsync(display.getDisplayId(), /*enable*/ false).isOk());
-
-            DisplayProperties& displayProperties = mDisplayProperties.at(display.getDisplayId());
-            if (ReadbackHelper::readbackSupported(displayProperties.pixelFormat,
-                                                  displayProperties.dataspace)) {
-                mDisplaysWithReadbackBuffers.push_back(&display);
-            }
         }
 
         mComposerClient->setVsyncAllowed(/*isAllowed*/ false);
@@ -150,12 +144,35 @@
             DisplayProperties displayProperties(displayId, testColorModes,
                                                 std::move(testRenderEngine),
                                                 std::move(clientCompositionDisplaySettings),
-                                                std::move(readBackBufferAttributes));
+                                                std::move(readBackBufferAttributes.format));
 
             mDisplayProperties.emplace(displayId, std::move(displayProperties));
         }
     }
 
+    // Get the dataspace and check if readback is supported given the default pixel format and the
+    // current dataspace. Dataspace can get updated after calls to
+    // ComposerClientWrapper::setColorMode so it's essential to get the latest dataspace.
+    std::pair<common::Dataspace, bool> GetDataspaceAndIfReadBackSupported(int64_t displayId) {
+        auto [status, readBackBufferAttributes] =
+                mComposerClient->getReadbackBufferAttributes(displayId);
+        if (status.isOk()) {
+            auto dataspace = readBackBufferAttributes.dataspace;
+
+            // We are making an assumption that Pixel Format never changes, so assert for this
+            // assumption. If this is not the case on any display, then we should stop caching it.
+            // The cached format is used in initializing TestRenderEngine.
+            assertPixelFormatConsistency(displayId, readBackBufferAttributes.format);
+
+            return std::make_pair(std::move(dataspace),
+                                  ReadbackHelper::readbackSupported(
+                                          mDisplayProperties.at(displayId).pixelFormat, dataspace));
+        }
+        EXPECT_NO_FATAL_FAILURE(
+                assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
+        return {common::Dataspace::UNKNOWN, false};
+    }
+
     int64_t getInvalidDisplayId() const { return mComposerClient->getInvalidDisplayId(); }
 
     void assertServiceSpecificError(const ScopedAStatus& status, int32_t serviceSpecificError) {
@@ -163,6 +180,10 @@
         ASSERT_EQ(status.getServiceSpecificError(), serviceSpecificError);
     }
 
+    void assertPixelFormatConsistency(int64_t displayId, common::PixelFormat currentPixelFormat) {
+        ASSERT_EQ(mDisplayProperties.at(displayId).pixelFormat, currentPixelFormat);
+    }
+
     std::pair<bool, ::android::sp<::android::GraphicBuffer>> allocateBuffer(
             const DisplayWrapper& display, uint32_t usage) {
         const auto width = static_cast<uint32_t>(display.getDisplayWidth());
@@ -201,10 +222,9 @@
         DisplayProperties(int64_t displayId, std::vector<ColorMode> testColorModes,
                           std::unique_ptr<TestRenderEngine> testRenderEngine,
                           ::android::renderengine::DisplaySettings clientCompositionDisplaySettings,
-                          ReadbackBufferAttributes readBackBufferAttributes)
+                          common::PixelFormat pixelFormat)
             : testColorModes(testColorModes),
-              pixelFormat(readBackBufferAttributes.format),
-              dataspace(readBackBufferAttributes.dataspace),
+              pixelFormat(pixelFormat),
               testRenderEngine(std::move(testRenderEngine)),
               clientCompositionDisplaySettings(std::move(clientCompositionDisplaySettings)),
               writer(displayId),
@@ -212,7 +232,6 @@
 
         std::vector<ColorMode> testColorModes = {};
         common::PixelFormat pixelFormat = common::PixelFormat::UNSPECIFIED;
-        common::Dataspace dataspace = common::Dataspace::UNKNOWN;
         std::unique_ptr<TestRenderEngine> testRenderEngine = nullptr;
         ::android::renderengine::DisplaySettings clientCompositionDisplaySettings = {};
         ComposerClientWriter writer;
@@ -221,7 +240,6 @@
 
     std::shared_ptr<ComposerClientWrapper> mComposerClient;
     std::vector<DisplayWrapper> mAllDisplays;
-    std::vector<const DisplayWrapper*> mDisplaysWithReadbackBuffers;
     std::unordered_map<int64_t, DisplayProperties> mDisplayProperties;
 
     static constexpr uint32_t kClientTargetSlotCount = 64;
@@ -234,19 +252,25 @@
 };
 
 TEST_P(GraphicsCompositionTest, SingleSolidColorLayer) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        auto& testColorModes = mDisplayProperties.at(display->getDisplayId()).testColorModes;
+    for (const DisplayWrapper display : mAllDisplays) {
+        auto& testColorModes = mDisplayProperties.at(display.getDisplayId()).testColorModes;
         for (ColorMode mode : testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
 
             auto layer = std::make_shared<TestColorLayer>(
-                    mComposerClient, display->getDisplayId(),
-                    mDisplayProperties.at(display->getDisplayId()).writer);
+                    mComposerClient, display.getDisplayId(),
+                    mDisplayProperties.at(display.getDisplayId()).writer);
             common::Rect coloredSquare(
-                    {0, 0, display->getDisplayWidth(), display->getDisplayHeight()});
+                    {0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
             layer->setColor(BLUE);
             layer->setDisplayFrame(coloredSquare);
             layer->setZOrder(10);
@@ -255,40 +279,38 @@
 
             // expected color for each pixel
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(),
-                                           coloredSquare, BLUE);
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), coloredSquare,
+                                           BLUE);
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
+            execute(display.getDisplayId());
             // if hwc cannot handle and asks for composition change, just skip the test on this
             // display->
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -297,71 +319,74 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetLayerBuffer) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        auto& testColorModes = mDisplayProperties.at(display->getDisplayId()).testColorModes;
+    for (const DisplayWrapper display : mAllDisplays) {
+        auto& testColorModes = mDisplayProperties.at(display.getDisplayId()).testColorModes;
         for (ColorMode mode : testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
+
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
             ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, 0, display->getDisplayWidth(), display->getDisplayHeight() / 4}, RED);
+                    expectedColors, display.getDisplayWidth(),
+                    {0, 0, display.getDisplayWidth(), display.getDisplayHeight() / 4}, RED);
             ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, display->getDisplayHeight() / 4, display->getDisplayWidth(),
-                     display->getDisplayHeight() / 2},
+                    expectedColors, display.getDisplayWidth(),
+                    {0, display.getDisplayHeight() / 4, display.getDisplayWidth(),
+                     display.getDisplayHeight() / 2},
                     GREEN);
-            ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, display->getDisplayHeight() / 2, display->getDisplayWidth(),
-                     display->getDisplayHeight()},
-                    BLUE);
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
+                                           {0, display.getDisplayHeight() / 2,
+                                            display.getDisplayWidth(), display.getDisplayHeight()},
+                                           BLUE);
 
             auto layer = std::make_shared<TestBufferLayer>(
                     mComposerClient,
-                    *mDisplayProperties.at(display->getDisplayId()).testRenderEngine,
-                    display->getDisplayId(), display->getDisplayWidth(),
-                    display->getDisplayHeight(), common::PixelFormat::RGBA_8888,
-                    mDisplayProperties.at(display->getDisplayId()).writer);
-            layer->setDisplayFrame({0, 0, display->getDisplayWidth(), display->getDisplayHeight()});
+                    *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
+                    display.getDisplayId(), display.getDisplayWidth(), display.getDisplayHeight(),
+                    common::PixelFormat::RGBA_8888,
+                    mDisplayProperties.at(display.getDisplayId()).writer);
+            layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
             layer->setZOrder(10);
             layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
             ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
 
             std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
+            execute(display.getDisplayId());
 
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -370,64 +395,69 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        auto& testColorModes = mDisplayProperties.at(display->getDisplayId()).testColorModes;
+    for (const DisplayWrapper display : mAllDisplays) {
+        auto& testColorModes = mDisplayProperties.at(display.getDisplayId()).testColorModes;
         for (ColorMode mode : testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
 
-            auto& writer = mDisplayProperties.at(display->getDisplayId()).writer;
-            auto layer = std::make_shared<TestColorLayer>(mComposerClient, display->getDisplayId(),
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
+
+            auto& writer = mDisplayProperties.at(display.getDisplayId()).writer;
+            auto layer = std::make_shared<TestColorLayer>(mComposerClient, display.getDisplayId(),
                                                           writer);
             common::Rect coloredSquare(
-                    {0, 0, display->getDisplayWidth(), display->getDisplayHeight()});
+                    {0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
             layer->setColor(BLUE);
             layer->setDisplayFrame(coloredSquare);
             layer->setZOrder(10);
-            layer->write(mDisplayProperties.at(display->getDisplayId()).writer);
+            layer->write(mDisplayProperties.at(display.getDisplayId()).writer);
 
             // This following buffer call should have no effect
             const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
                                static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
-            const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(*display, usage);
+            const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(display, usage);
             ASSERT_TRUE(graphicBufferStatus);
             const auto& buffer = graphicBuffer->handle;
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.setLayerBuffer(display->getDisplayId(), layer->getLayer(), /*slot*/ 0,
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.setLayerBuffer(display.getDisplayId(), layer->getLayer(), /*slot*/ 0,
                                            buffer,
                                            /*acquireFence*/ -1);
 
             // expected color for each pixel
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(),
-                                           coloredSquare, BLUE);
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), coloredSquare,
+                                           BLUE);
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
+            execute(display.getDisplayId());
 
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
         }
@@ -435,20 +465,31 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetReadbackBuffer) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        ReadbackBuffer readbackBuffer(display->getDisplayId(), mComposerClient,
-                                      display->getDisplayWidth(), display->getDisplayHeight(),
-                                      mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                                      mDisplayProperties.at(display->getDisplayId()).dataspace);
+    for (const DisplayWrapper display : mAllDisplays) {
+        auto [dataspace, readbackSupported] =
+                GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+        if (!readbackSupported) {
+            continue;
+        }
+
+        ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                      display.getDisplayWidth(), display.getDisplayHeight(),
+                                      mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                      dataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
     }
 }
 
 TEST_P(GraphicsCompositionTest, SetReadbackBuffer_BadDisplay) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
+    for (const DisplayWrapper display : mAllDisplays) {
+        auto [_, readbackSupported] = GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+        if (!readbackSupported) {
+            continue;
+        }
+
         const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
                            static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
-        const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(*display, usage);
+        const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(display, usage);
         ASSERT_TRUE(graphicBufferStatus);
         const auto& bufferHandle = graphicBuffer->handle;
         ::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
@@ -463,10 +504,15 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetReadbackBuffer_BadParameter) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
+    for (const DisplayWrapper display : mAllDisplays) {
+        auto [_, readbackSupported] = GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+        if (!readbackSupported) {
+            continue;
+        }
+
         const native_handle_t bufferHandle{};
         ndk::ScopedFileDescriptor releaseFence = ndk::ScopedFileDescriptor(-1);
-        const auto status = mComposerClient->setReadbackBuffer(display->getDisplayId(),
+        const auto status = mComposerClient->setReadbackBuffer(display.getDisplayId(),
                                                                &bufferHandle, releaseFence);
 
         EXPECT_FALSE(status.isOk());
@@ -476,9 +522,13 @@
 }
 
 TEST_P(GraphicsCompositionTest, GetReadbackBufferFenceInactive) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
+    for (const DisplayWrapper display : mAllDisplays) {
+        auto [_, readbackSupported] = GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+        if (!readbackSupported) {
+            continue;
+        }
         const auto& [status, releaseFence] =
-                mComposerClient->getReadbackBufferFence(display->getDisplayId());
+                mComposerClient->getReadbackBufferFence(display.getDisplayId());
 
         EXPECT_FALSE(status.isOk());
         EXPECT_NO_FATAL_FAILURE(
@@ -488,64 +538,67 @@
 }
 
 TEST_P(GraphicsCompositionTest, ClientComposition) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
+    for (const DisplayWrapper display : mAllDisplays) {
         EXPECT_TRUE(
                 mComposerClient
-                        ->setClientTargetSlotCount(display->getDisplayId(), kClientTargetSlotCount)
+                        ->setClientTargetSlotCount(display.getDisplayId(), kClientTargetSlotCount)
                         .isOk());
 
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
             ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, 0, display->getDisplayWidth(), display->getDisplayHeight() / 4}, RED);
+                    expectedColors, display.getDisplayWidth(),
+                    {0, 0, display.getDisplayWidth(), display.getDisplayHeight() / 4}, RED);
             ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, display->getDisplayHeight() / 4, display->getDisplayWidth(),
-                     display->getDisplayHeight() / 2},
+                    expectedColors, display.getDisplayWidth(),
+                    {0, display.getDisplayHeight() / 4, display.getDisplayWidth(),
+                     display.getDisplayHeight() / 2},
                     GREEN);
-            ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, display->getDisplayHeight() / 2, display->getDisplayWidth(),
-                     display->getDisplayHeight()},
-                    BLUE);
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
+                                           {0, display.getDisplayHeight() / 2,
+                                            display.getDisplayWidth(), display.getDisplayHeight()},
+                                           BLUE);
 
             auto layer = std::make_shared<TestBufferLayer>(
                     mComposerClient,
-                    *mDisplayProperties.at(display->getDisplayId()).testRenderEngine,
-                    display->getDisplayId(), display->getDisplayWidth(),
-                    display->getDisplayHeight(), PixelFormat::RGBA_8888,
-                    mDisplayProperties.at(display->getDisplayId()).writer);
-            layer->setDisplayFrame({0, 0, display->getDisplayWidth(), display->getDisplayHeight()});
+                    *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
+                    display.getDisplayId(), display.getDisplayWidth(), display.getDisplayHeight(),
+                    PixelFormat::RGBA_8888, mDisplayProperties.at(display.getDisplayId()).writer);
+            layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
             layer->setZOrder(10);
             layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
 
             std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
+            execute(display.getDisplayId());
 
             auto changedCompositionTypes =
-                    mDisplayProperties.at(display->getDisplayId())
-                            .reader.takeChangedCompositionTypes(display->getDisplayId());
+                    mDisplayProperties.at(display.getDisplayId())
+                            .reader.takeChangedCompositionTypes(display.getDisplayId());
             if (!changedCompositionTypes.empty()) {
                 ASSERT_EQ(1, changedCompositionTypes.size());
                 ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
@@ -556,11 +609,11 @@
                         static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
                         static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET));
                 Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
-                common::Rect damage{0, 0, display->getDisplayWidth(), display->getDisplayHeight()};
+                common::Rect damage{0, 0, display.getDisplayWidth(), display.getDisplayHeight()};
 
                 // create client target buffer
                 const auto& [graphicBufferStatus, graphicBuffer] =
-                        allocateBuffer(*display, clientUsage);
+                        allocateBuffer(display, clientUsage);
                 ASSERT_TRUE(graphicBufferStatus);
                 const auto& buffer = graphicBuffer->handle;
                 void* clientBufData;
@@ -576,29 +629,28 @@
                 int32_t clientFence;
                 const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
                 ASSERT_EQ(::android::OK, unlockStatus);
-                mDisplayProperties.at(display->getDisplayId())
-                        .writer.setClientTarget(display->getDisplayId(), /*slot*/ 0, buffer,
+                mDisplayProperties.at(display.getDisplayId())
+                        .writer.setClientTarget(display.getDisplayId(), /*slot*/ 0, buffer,
                                                 clientFence, clientDataspace,
                                                 std::vector<common::Rect>(1, damage), 1.f);
-                layer->setToClientComposition(
-                        mDisplayProperties.at(display->getDisplayId()).writer);
-                mDisplayProperties.at(display->getDisplayId())
-                        .writer.validateDisplay(display->getDisplayId(),
+                layer->setToClientComposition(mDisplayProperties.at(display.getDisplayId()).writer);
+                mDisplayProperties.at(display.getDisplayId())
+                        .writer.validateDisplay(display.getDisplayId(),
                                                 ComposerClientWriter::kNoTimestamp,
                                                 ComposerClientWrapper::kNoFrameIntervalNs);
-                execute(display->getDisplayId());
+                execute(display.getDisplayId());
                 changedCompositionTypes =
-                        mDisplayProperties.at(display->getDisplayId())
-                                .reader.takeChangedCompositionTypes(display->getDisplayId());
+                        mDisplayProperties.at(display.getDisplayId())
+                                .reader.takeChangedCompositionTypes(display.getDisplayId());
                 ASSERT_TRUE(changedCompositionTypes.empty());
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
 
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
         }
@@ -634,12 +686,12 @@
         GTEST_SKIP();
     }
 
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
+    for (const DisplayWrapper display : mAllDisplays) {
         ASSERT_TRUE(
                 mComposerClient
-                        ->setClientTargetSlotCount(display->getDisplayId(), kClientTargetSlotCount)
+                        ->setClientTargetSlotCount(display.getDisplayId(), kClientTargetSlotCount)
                         .isOk());
-        auto& testColorModes = mDisplayProperties.at(display->getDisplayId()).testColorModes;
+        auto& testColorModes = mDisplayProperties.at(display.getDisplayId()).testColorModes;
 
         for (const auto& lutProperties : *properties.lutProperties) {
             if (!lutProperties) {
@@ -650,25 +702,31 @@
             for (const auto& key : l.samplingKeys) {
                 for (ColorMode mode : testColorModes) {
                     EXPECT_TRUE(mComposerClient
-                                        ->setColorMode(display->getDisplayId(), mode,
+                                        ->setColorMode(display.getDisplayId(), mode,
                                                        RenderIntent::COLORIMETRIC)
                                         .isOk());
 
+                    auto [dataspace, readbackSupported] =
+                            GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+                    if (!readbackSupported) {
+                        continue;
+                    }
+
                     common::Rect coloredSquare(
-                            {0, 0, display->getDisplayWidth(), display->getDisplayHeight()});
+                            {0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
 
                     // expected color for each pixel
                     std::vector<Color> expectedColors(static_cast<size_t>(
-                            display->getDisplayWidth() * display->getDisplayHeight()));
-                    ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(),
+                            display.getDisplayWidth() * display.getDisplayHeight()));
+                    ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
                                                    coloredSquare, WHITE);
 
                     auto layer = std::make_shared<TestBufferLayer>(
                             mComposerClient,
-                            *mDisplayProperties.at(display->getDisplayId()).testRenderEngine,
-                            display->getDisplayId(), display->getDisplayWidth(),
-                            display->getDisplayHeight(), PixelFormat::RGBA_8888,
-                            mDisplayProperties.at(display->getDisplayId()).writer);
+                            *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
+                            display.getDisplayId(), display.getDisplayWidth(),
+                            display.getDisplayHeight(), PixelFormat::RGBA_8888,
+                            mDisplayProperties.at(display.getDisplayId()).writer);
                     layer->setDisplayFrame(coloredSquare);
                     layer->setZOrder(10);
                     layer->setDataspace(Dataspace::SRGB);
@@ -682,46 +740,45 @@
                     std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
                     ReadbackBuffer readbackBuffer(
-                            display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                            display->getDisplayHeight(),
-                            mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                            mDisplayProperties.at(display->getDisplayId()).dataspace);
+                            display.getDisplayId(), mComposerClient, display.getDisplayWidth(),
+                            display.getDisplayHeight(),
+                            mDisplayProperties.at(display.getDisplayId()).pixelFormat, dataspace);
                     ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-                    writeLayers(layers, display->getDisplayId());
-                    ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId())
+                    writeLayers(layers, display.getDisplayId());
+                    ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId())
                                         .reader.takeErrors()
                                         .empty());
-                    mDisplayProperties.at(display->getDisplayId())
-                            .writer.validateDisplay(display->getDisplayId(),
+                    mDisplayProperties.at(display.getDisplayId())
+                            .writer.validateDisplay(display.getDisplayId(),
                                                     ComposerClientWriter::kNoTimestamp,
                                                     ComposerClientWrapper::kNoFrameIntervalNs);
-                    execute(display->getDisplayId());
-                    if (!mDisplayProperties.at(display->getDisplayId())
-                                 .reader.takeChangedCompositionTypes(display->getDisplayId())
+                    execute(display.getDisplayId());
+                    if (!mDisplayProperties.at(display.getDisplayId())
+                                 .reader.takeChangedCompositionTypes(display.getDisplayId())
                                  .empty()) {
                         continue;
                     }
 
                     auto changedCompositionTypes =
-                            mDisplayProperties.at(display->getDisplayId())
-                                    .reader.takeChangedCompositionTypes(display->getDisplayId());
+                            mDisplayProperties.at(display.getDisplayId())
+                                    .reader.takeChangedCompositionTypes(display.getDisplayId());
                     ASSERT_TRUE(changedCompositionTypes.empty());
 
-                    mDisplayProperties.at(display->getDisplayId())
-                            .writer.presentDisplay(display->getDisplayId());
-                    execute(display->getDisplayId());
-                    ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId())
+                    mDisplayProperties.at(display.getDisplayId())
+                            .writer.presentDisplay(display.getDisplayId());
+                    execute(display.getDisplayId());
+                    ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId())
                                         .reader.takeErrors()
                                         .empty());
 
                     ReadbackHelper::fillColorsArea(
-                            expectedColors, display->getDisplayWidth(), coloredSquare,
+                            expectedColors, display.getDisplayWidth(), coloredSquare,
                             {188.f / 255.f, 188.f / 255.f, 188.f / 255.f, 1.0f});
 
                     ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
                     auto& testRenderEngine =
-                            mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+                            mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
                     testRenderEngine->setRenderLayers(layers);
                     ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
                     ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -744,27 +801,33 @@
         GTEST_SKIP();
     }
 
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
+    for (const DisplayWrapper display : mAllDisplays) {
         ASSERT_TRUE(
                 mComposerClient
-                        ->setClientTargetSlotCount(display->getDisplayId(), kClientTargetSlotCount)
+                        ->setClientTargetSlotCount(display.getDisplayId(), kClientTargetSlotCount)
                         .isOk());
 
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
 
             // sRGB layer
             auto srgbLayer = std::make_shared<TestBufferLayer>(
                     mComposerClient,
-                    *mDisplayProperties.at(display->getDisplayId()).testRenderEngine,
-                    display->getDisplayId(), display->getDisplayWidth(),
-                    display->getDisplayHeight() / 2, PixelFormat::RGBA_8888,
-                    mDisplayProperties.at(display->getDisplayId()).writer);
+                    *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
+                    display.getDisplayId(), display.getDisplayWidth(),
+                    display.getDisplayHeight() / 2, PixelFormat::RGBA_8888,
+                    mDisplayProperties.at(display.getDisplayId()).writer);
             std::vector<Color> sRgbDeviceColors(srgbLayer->getWidth() * srgbLayer->getHeight());
-            ReadbackHelper::fillColorsArea(sRgbDeviceColors, display->getDisplayWidth(),
+            ReadbackHelper::fillColorsArea(sRgbDeviceColors, display.getDisplayWidth(),
                                            {0, 0, static_cast<int32_t>(srgbLayer->getWidth()),
                                             static_cast<int32_t>(srgbLayer->getHeight())},
                                            GREEN);
@@ -777,86 +840,90 @@
             // display P3 layer
             auto displayP3Layer = std::make_shared<TestBufferLayer>(
                     mComposerClient,
-                    *mDisplayProperties.at(display->getDisplayId()).testRenderEngine,
-                    display->getDisplayId(), display->getDisplayWidth(),
-                    display->getDisplayHeight() / 2, PixelFormat::RGBA_8888,
-                    mDisplayProperties.at(display->getDisplayId()).writer);
+                    *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
+                    display.getDisplayId(), display.getDisplayWidth(),
+                    display.getDisplayHeight() / 2, PixelFormat::RGBA_8888,
+                    mDisplayProperties.at(display.getDisplayId()).writer);
             std::vector<Color> displayP3DeviceColors(
                     static_cast<size_t>(displayP3Layer->getWidth() * displayP3Layer->getHeight()));
-            ReadbackHelper::fillColorsArea(displayP3DeviceColors, display->getDisplayWidth(),
+            ReadbackHelper::fillColorsArea(displayP3DeviceColors, display.getDisplayWidth(),
                                            {0, 0, static_cast<int32_t>(displayP3Layer->getWidth()),
                                             static_cast<int32_t>(displayP3Layer->getHeight())},
                                            RED);
-            displayP3Layer->setDisplayFrame({0, display->getDisplayHeight() / 2,
-                                             display->getDisplayWidth(),
-                                             display->getDisplayHeight()});
+            displayP3Layer->setDisplayFrame({0, display.getDisplayHeight() / 2,
+                                             display.getDisplayWidth(),
+                                             display.getDisplayHeight()});
             displayP3Layer->setZOrder(10);
             displayP3Layer->setDataspace(Dataspace::DISPLAY_P3);
             ASSERT_NO_FATAL_FAILURE(displayP3Layer->setBuffer(displayP3DeviceColors));
 
-            writeLayers({srgbLayer, displayP3Layer}, display->getDisplayId());
+            writeLayers({srgbLayer, displayP3Layer}, display.getDisplayId());
 
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
+            execute(display.getDisplayId());
 
             auto changedCompositionTypes =
-                    mDisplayProperties.at(display->getDisplayId())
-                            .reader.takeChangedCompositionTypes(display->getDisplayId());
+                    mDisplayProperties.at(display.getDisplayId())
+                            .reader.takeChangedCompositionTypes(display.getDisplayId());
             ASSERT_TRUE(changedCompositionTypes.empty());
 
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
             changedCompositionTypes =
-                    mDisplayProperties.at(display->getDisplayId())
-                            .reader.takeChangedCompositionTypes(display->getDisplayId());
+                    mDisplayProperties.at(display.getDisplayId())
+                            .reader.takeChangedCompositionTypes(display.getDisplayId());
             ASSERT_TRUE(changedCompositionTypes.empty());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
         }
     }
 }
 
 TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
+    for (const DisplayWrapper display : mAllDisplays) {
         ASSERT_TRUE(
                 mComposerClient
-                        ->setClientTargetSlotCount(display->getDisplayId(), kClientTargetSlotCount)
+                        ->setClientTargetSlotCount(display.getDisplayId(), kClientTargetSlotCount)
                         .isOk());
 
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
             ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, 0, display->getDisplayWidth(), display->getDisplayHeight() / 2}, GREEN);
-            ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, display->getDisplayHeight() / 2, display->getDisplayWidth(),
-                     display->getDisplayHeight()},
-                    RED);
+                    expectedColors, display.getDisplayWidth(),
+                    {0, 0, display.getDisplayWidth(), display.getDisplayHeight() / 2}, GREEN);
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
+                                           {0, display.getDisplayHeight() / 2,
+                                            display.getDisplayWidth(), display.getDisplayHeight()},
+                                           RED);
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
             auto deviceLayer = std::make_shared<TestBufferLayer>(
                     mComposerClient,
-                    *mDisplayProperties.at(display->getDisplayId()).testRenderEngine,
-                    display->getDisplayId(), display->getDisplayWidth(),
-                    display->getDisplayHeight() / 2, PixelFormat::RGBA_8888,
-                    mDisplayProperties.at(display->getDisplayId()).writer);
+                    *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
+                    display.getDisplayId(), display.getDisplayWidth(),
+                    display.getDisplayHeight() / 2, PixelFormat::RGBA_8888,
+                    mDisplayProperties.at(display.getDisplayId()).writer);
             std::vector<Color> deviceColors(deviceLayer->getWidth() * deviceLayer->getHeight());
             ReadbackHelper::fillColorsArea(deviceColors,
                                            static_cast<int32_t>(deviceLayer->getWidth()),
@@ -868,7 +935,7 @@
             deviceLayer->setZOrder(10);
             deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
             ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
-            deviceLayer->write(mDisplayProperties.at(display->getDisplayId()).writer);
+            deviceLayer->write(mDisplayProperties.at(display.getDisplayId()).writer);
 
             PixelFormat clientFormat = PixelFormat::RGBA_8888;
             auto clientUsage = static_cast<uint32_t>(
@@ -876,35 +943,34 @@
                     static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
                     static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET));
             Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
-            int32_t clientWidth = display->getDisplayWidth();
-            int32_t clientHeight = display->getDisplayHeight() / 2;
+            int32_t clientWidth = display.getDisplayWidth();
+            int32_t clientHeight = display.getDisplayHeight() / 2;
 
             auto clientLayer = std::make_shared<TestBufferLayer>(
                     mComposerClient,
-                    *mDisplayProperties.at(display->getDisplayId()).testRenderEngine,
-                    display->getDisplayId(), clientWidth, clientHeight, PixelFormat::RGBA_FP16,
-                    mDisplayProperties.at(display->getDisplayId()).writer, Composition::DEVICE);
-            common::Rect clientFrame = {0, display->getDisplayHeight() / 2,
-                                        display->getDisplayWidth(), display->getDisplayHeight()};
+                    *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
+                    display.getDisplayId(), clientWidth, clientHeight, PixelFormat::RGBA_FP16,
+                    mDisplayProperties.at(display.getDisplayId()).writer, Composition::DEVICE);
+            common::Rect clientFrame = {0, display.getDisplayHeight() / 2,
+                                        display.getDisplayWidth(), display.getDisplayHeight()};
             clientLayer->setDisplayFrame(clientFrame);
             clientLayer->setZOrder(0);
-            clientLayer->write(mDisplayProperties.at(display->getDisplayId()).writer);
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            clientLayer->write(mDisplayProperties.at(display.getDisplayId()).writer);
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
+            execute(display.getDisplayId());
 
             auto changedCompositionTypes =
-                    mDisplayProperties.at(display->getDisplayId())
-                            .reader.takeChangedCompositionTypes(display->getDisplayId());
+                    mDisplayProperties.at(display.getDisplayId())
+                            .reader.takeChangedCompositionTypes(display.getDisplayId());
             if (changedCompositionTypes.size() != 1) {
                 continue;
             }
             // create client target buffer
             ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
-            const auto& [graphicBufferStatus, graphicBuffer] =
-                    allocateBuffer(*display, clientUsage);
+            const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(display, clientUsage);
             ASSERT_TRUE(graphicBufferStatus);
             const auto& buffer = graphicBuffer->handle;
 
@@ -912,131 +978,133 @@
             int bytesPerPixel = -1;
             int bytesPerStride = -1;
             graphicBuffer->lock(clientUsage,
-                                {0, 0, display->getDisplayWidth(), display->getDisplayHeight()},
+                                {0, 0, display.getDisplayWidth(), display.getDisplayHeight()},
                                 &clientBufData, &bytesPerPixel, &bytesPerStride);
 
             std::vector<Color> clientColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
-            ReadbackHelper::fillColorsArea(clientColors, display->getDisplayWidth(), clientFrame,
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
+            ReadbackHelper::fillColorsArea(clientColors, display.getDisplayWidth(), clientFrame,
                                            RED);
             ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
-                    static_cast<uint32_t>(display->getDisplayWidth()),
-                    static_cast<uint32_t>(display->getDisplayHeight()), graphicBuffer->getStride(),
+                    static_cast<uint32_t>(display.getDisplayWidth()),
+                    static_cast<uint32_t>(display.getDisplayHeight()), graphicBuffer->getStride(),
                     bytesPerPixel, clientBufData, clientFormat, clientColors));
             int32_t clientFence;
             const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
             ASSERT_EQ(::android::OK, unlockStatus);
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.setClientTarget(display->getDisplayId(), /*slot*/ 0, buffer,
-                                            clientFence, clientDataspace,
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.setClientTarget(display.getDisplayId(), /*slot*/ 0, buffer, clientFence,
+                                            clientDataspace,
                                             std::vector<common::Rect>(1, clientFrame), 1.f);
             clientLayer->setToClientComposition(
-                    mDisplayProperties.at(display->getDisplayId()).writer);
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+                    mDisplayProperties.at(display.getDisplayId()).writer);
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
+            execute(display.getDisplayId());
             changedCompositionTypes =
-                    mDisplayProperties.at(display->getDisplayId())
-                            .reader.takeChangedCompositionTypes(display->getDisplayId());
+                    mDisplayProperties.at(display.getDisplayId())
+                            .reader.takeChangedCompositionTypes(display.getDisplayId());
             ASSERT_TRUE(changedCompositionTypes.empty());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
         }
     }
 }
 
 TEST_P(GraphicsCompositionTest, SetLayerDamage) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
 
-            common::Rect redRect = {0, 0, display->getDisplayWidth() / 4,
-                                    display->getDisplayHeight() / 4};
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
+
+            common::Rect redRect = {0, 0, display.getDisplayWidth() / 4,
+                                    display.getDisplayHeight() / 4};
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(), redRect,
-                                           RED);
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), redRect, RED);
 
             auto layer = std::make_shared<TestBufferLayer>(
                     mComposerClient,
-                    *mDisplayProperties.at(display->getDisplayId()).testRenderEngine,
-                    display->getDisplayId(), display->getDisplayWidth(),
-                    display->getDisplayHeight(), PixelFormat::RGBA_8888,
-                    mDisplayProperties.at(display->getDisplayId()).writer);
-            layer->setDisplayFrame({0, 0, display->getDisplayWidth(), display->getDisplayHeight()});
+                    *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
+                    display.getDisplayId(), display.getDisplayWidth(), display.getDisplayHeight(),
+                    PixelFormat::RGBA_8888, mDisplayProperties.at(display.getDisplayId()).writer);
+            layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
             layer->setZOrder(10);
             layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
             ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
 
             std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 
             // update surface damage and recheck
-            redRect = {display->getDisplayWidth() / 4, display->getDisplayHeight() / 4,
-                       display->getDisplayWidth() / 2, display->getDisplayHeight() / 2};
-            ReadbackHelper::clearColors(expectedColors, display->getDisplayWidth(),
-                                        display->getDisplayHeight(), display->getDisplayWidth());
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(), redRect,
-                                           RED);
+            redRect = {display.getDisplayWidth() / 4, display.getDisplayHeight() / 4,
+                       display.getDisplayWidth() / 2, display.getDisplayHeight() / 2};
+            ReadbackHelper::clearColors(expectedColors, display.getDisplayWidth(),
+                                        display.getDisplayHeight(), display.getDisplayWidth());
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), redRect, RED);
 
             ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
             layer->setSurfaceDamage(std::vector<common::Rect>(
-                    1, {0, 0, display->getDisplayWidth() / 2, display->getDisplayWidth() / 2}));
+                    1, {0, 0, display.getDisplayWidth() / 2, display.getDisplayWidth() / 2}));
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId())
-                                .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId())
+                                .reader.takeChangedCompositionTypes(display.getDisplayId())
                                 .empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
         }
@@ -1044,56 +1112,60 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetLayerPlaneAlpha) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
 
             auto layer = std::make_shared<TestColorLayer>(
-                    mComposerClient, display->getDisplayId(),
-                    mDisplayProperties.at(display->getDisplayId()).writer);
+                    mComposerClient, display.getDisplayId(),
+                    mDisplayProperties.at(display.getDisplayId()).writer);
             layer->setColor(RED);
-            layer->setDisplayFrame({0, 0, display->getDisplayWidth(), display->getDisplayHeight()});
+            layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
             layer->setZOrder(10);
             layer->setAlpha(0);
             layer->setBlendMode(BlendMode::PREMULTIPLIED);
 
             std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -1102,70 +1174,72 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetLayerSourceCrop) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
             ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, 0, display->getDisplayWidth(), display->getDisplayHeight() / 4}, RED);
-            ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, display->getDisplayHeight() / 2, display->getDisplayWidth(),
-                     display->getDisplayHeight()},
-                    BLUE);
+                    expectedColors, display.getDisplayWidth(),
+                    {0, 0, display.getDisplayWidth(), display.getDisplayHeight() / 4}, RED);
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
+                                           {0, display.getDisplayHeight() / 2,
+                                            display.getDisplayWidth(), display.getDisplayHeight()},
+                                           BLUE);
 
             auto layer = std::make_shared<TestBufferLayer>(
                     mComposerClient,
-                    *mDisplayProperties.at(display->getDisplayId()).testRenderEngine,
-                    display->getDisplayId(), display->getDisplayWidth(),
-                    display->getDisplayHeight(), PixelFormat::RGBA_8888,
-                    mDisplayProperties.at(display->getDisplayId()).writer);
-            layer->setDisplayFrame({0, 0, display->getDisplayWidth(), display->getDisplayHeight()});
+                    *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
+                    display.getDisplayId(), display.getDisplayWidth(), display.getDisplayHeight(),
+                    PixelFormat::RGBA_8888, mDisplayProperties.at(display.getDisplayId()).writer);
+            layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
             layer->setZOrder(10);
             layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
-            layer->setSourceCrop({0, static_cast<float>(display->getDisplayHeight() / 2),
-                                  static_cast<float>(display->getDisplayWidth()),
-                                  static_cast<float>(display->getDisplayHeight())});
+            layer->setSourceCrop({0, static_cast<float>(display.getDisplayHeight() / 2),
+                                  static_cast<float>(display.getDisplayWidth()),
+                                  static_cast<float>(display.getDisplayHeight())});
             ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
 
             std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
             // update expected colors to match crop
             ReadbackHelper::fillColorsArea(
-                    expectedColors, display->getDisplayWidth(),
-                    {0, 0, display->getDisplayWidth(), display->getDisplayHeight()}, BLUE);
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+                    expectedColors, display.getDisplayWidth(),
+                    {0, 0, display.getDisplayWidth(), display.getDisplayHeight()}, BLUE);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -1174,98 +1248,100 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetLayerZOrder) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
 
-            common::Rect redRect = {0, 0, display->getDisplayWidth(),
-                                    display->getDisplayHeight() / 2};
-            common::Rect blueRect = {0, display->getDisplayHeight() / 4, display->getDisplayWidth(),
-                                     display->getDisplayHeight()};
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
+
+            common::Rect redRect = {0, 0, display.getDisplayWidth(),
+                                    display.getDisplayHeight() / 2};
+            common::Rect blueRect = {0, display.getDisplayHeight() / 4, display.getDisplayWidth(),
+                                     display.getDisplayHeight()};
             auto redLayer = std::make_shared<TestColorLayer>(
-                    mComposerClient, display->getDisplayId(),
-                    mDisplayProperties.at(display->getDisplayId()).writer);
+                    mComposerClient, display.getDisplayId(),
+                    mDisplayProperties.at(display.getDisplayId()).writer);
             redLayer->setColor(RED);
             redLayer->setDisplayFrame(redRect);
 
             auto blueLayer = std::make_shared<TestColorLayer>(
-                    mComposerClient, display->getDisplayId(),
-                    mDisplayProperties.at(display->getDisplayId()).writer);
+                    mComposerClient, display.getDisplayId(),
+                    mDisplayProperties.at(display.getDisplayId()).writer);
             blueLayer->setColor(BLUE);
             blueLayer->setDisplayFrame(blueRect);
             blueLayer->setZOrder(5);
 
             std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer};
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
 
             // red in front of blue
             redLayer->setZOrder(10);
 
             // fill blue first so that red will overwrite on overlap
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(), blueRect,
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), blueRect,
                                            BLUE);
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(), redRect,
-                                           RED);
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), redRect, RED);
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 
             redLayer->setZOrder(1);
-            ReadbackHelper::clearColors(expectedColors, display->getDisplayWidth(),
-                                        display->getDisplayHeight(), display->getDisplayWidth());
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(), redRect,
-                                           RED);
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(), blueRect,
+            ReadbackHelper::clearColors(expectedColors, display.getDisplayWidth(),
+                                        display.getDisplayHeight(), display.getDisplayWidth());
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), redRect, RED);
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), blueRect,
                                            BLUE);
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId())
-                                .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId())
+                                .reader.takeChangedCompositionTypes(display.getDisplayId())
                                 .empty());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -1274,32 +1350,38 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetLayerBrightnessDims) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
 
-            const common::Rect redRect = {0, 0, display->getDisplayWidth(),
-                                          display->getDisplayHeight() / 2};
-            const common::Rect dimmerRedRect = {0, display->getDisplayHeight() / 2,
-                                                display->getDisplayWidth(),
-                                                display->getDisplayHeight()};
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
+
+            const common::Rect redRect = {0, 0, display.getDisplayWidth(),
+                                          display.getDisplayHeight() / 2};
+            const common::Rect dimmerRedRect = {0, display.getDisplayHeight() / 2,
+                                                display.getDisplayWidth(),
+                                                display.getDisplayHeight()};
 
             static constexpr float kMaxBrightnessNits = 300.f;
 
             const auto redLayer = std::make_shared<TestColorLayer>(
-                    mComposerClient, display->getDisplayId(),
-                    mDisplayProperties.at(display->getDisplayId()).writer);
+                    mComposerClient, display.getDisplayId(),
+                    mDisplayProperties.at(display.getDisplayId()).writer);
             redLayer->setColor(RED);
             redLayer->setDisplayFrame(redRect);
             redLayer->setWhitePointNits(kMaxBrightnessNits);
             redLayer->setBrightness(1.f);
 
             const auto dimmerRedLayer = std::make_shared<TestColorLayer>(
-                    mComposerClient, display->getDisplayId(),
-                    mDisplayProperties.at(display->getDisplayId()).writer);
+                    mComposerClient, display.getDisplayId(),
+                    mDisplayProperties.at(display.getDisplayId()).writer);
             dimmerRedLayer->setColor(RED);
             dimmerRedLayer->setDisplayFrame(dimmerRedRect);
             // Intentionally use a small dimming ratio as some implementations may be more likely
@@ -1310,42 +1392,39 @@
 
             const std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, dimmerRedLayer};
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
 
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(), redRect,
-                                           RED);
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(),
-                                           dimmerRedRect, DIM_RED);
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), redRect, RED);
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), dimmerRedRect,
+                                           DIM_RED);
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 ALOGI(" Readback verification not supported for GPU composition for color mode %d",
                       mode);
                 continue;
             }
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -1462,49 +1541,53 @@
 };
 
 TEST_P(GraphicsBlendModeCompositionTest, None) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
 
-            setBackgroundColor(display->getDisplayId(), BLACK);
-            setTopLayerColor(display->getDisplayId(), TRANSLUCENT_RED);
-            setUpLayers(*display, BlendMode::NONE);
-            setExpectedColors(*display, expectedColors);
+            setBackgroundColor(display.getDisplayId(), BLACK);
+            setTopLayerColor(display.getDisplayId(), TRANSLUCENT_RED);
+            setUpLayers(display, BlendMode::NONE);
+            setExpectedColors(display, expectedColors);
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-            auto& layers = mDisplayGfx[display->getDisplayId()].layers;
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            auto& layers = mDisplayGfx[display.getDisplayId()].layers;
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -1513,94 +1596,103 @@
 }
 
 TEST_P(GraphicsBlendModeCompositionTest, Coverage) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
 
-            setBackgroundColor(display->getDisplayId(), BLACK);
-            setTopLayerColor(display->getDisplayId(), TRANSLUCENT_RED);
+            setBackgroundColor(display.getDisplayId(), BLACK);
+            setTopLayerColor(display.getDisplayId(), TRANSLUCENT_RED);
 
-            setUpLayers(*display, BlendMode::COVERAGE);
-            setExpectedColors(*display, expectedColors);
+            setUpLayers(display, BlendMode::COVERAGE);
+            setExpectedColors(display, expectedColors);
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-            auto& layers = mDisplayGfx[display->getDisplayId()].layers;
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            auto& layers = mDisplayGfx[display.getDisplayId()].layers;
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
         }
     }
 }
 
 TEST_P(GraphicsBlendModeCompositionTest, Premultiplied) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
 
-            setBackgroundColor(display->getDisplayId(), BLACK);
-            setTopLayerColor(display->getDisplayId(), TRANSLUCENT_RED);
-            setUpLayers(*display, BlendMode::PREMULTIPLIED);
-            setExpectedColors(*display, expectedColors);
+            setBackgroundColor(display.getDisplayId(), BLACK);
+            setTopLayerColor(display.getDisplayId(), TRANSLUCENT_RED);
+            setUpLayers(display, BlendMode::PREMULTIPLIED);
+            setExpectedColors(display, expectedColors);
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-            auto& layers = mDisplayGfx[display->getDisplayId()].layers;
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            auto& layers = mDisplayGfx[display.getDisplayId()].layers;
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -1658,58 +1750,63 @@
 };
 
 TEST_P(GraphicsTransformCompositionTest, FLIP_H) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            auto status = mComposerClient->setColorMode(display->getDisplayId(), mode,
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            auto status = mComposerClient->setColorMode(display.getDisplayId(), mode,
                                                         RenderIntent::COLORIMETRIC);
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
+
             if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
                 (status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED ||
                  status.getServiceSpecificError() == IComposerClient::EX_BAD_PARAMETER)) {
                 ALOGI("ColorMode not supported on Display %" PRId64 " for ColorMode %d",
-                      display->getDisplayId(), mode);
+                      display.getDisplayId(), mode);
                 continue;
             }
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-            auto& bufferLayer = mDisplayGfx[display->getDisplayId()].bufferLayer;
+            auto& bufferLayer = mDisplayGfx[display.getDisplayId()].bufferLayer;
             bufferLayer->setTransform(Transform::FLIP_H);
             bufferLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
-            int& sideLength = mDisplayGfx[display->getDisplayId()].sideLength;
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(),
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
+            int& sideLength = mDisplayGfx[display.getDisplayId()].sideLength;
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
                                            {sideLength / 2, 0, sideLength, sideLength / 2}, RED);
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(),
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
                                            {0, sideLength / 2, sideLength / 2, sideLength}, BLUE);
 
-            auto& layers = mDisplayGfx[display->getDisplayId()].layers;
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            auto& layers = mDisplayGfx[display.getDisplayId()].layers;
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -1718,53 +1815,57 @@
 }
 
 TEST_P(GraphicsTransformCompositionTest, FLIP_V) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
+
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            auto& bufferLayer = mDisplayGfx[display->getDisplayId()].bufferLayer;
+            auto& bufferLayer = mDisplayGfx[display.getDisplayId()].bufferLayer;
             bufferLayer->setTransform(Transform::FLIP_V);
             bufferLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
-            int& sideLength = mDisplayGfx[display->getDisplayId()].sideLength;
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(),
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
+            int& sideLength = mDisplayGfx[display.getDisplayId()].sideLength;
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
                                            {0, sideLength / 2, sideLength / 2, sideLength}, RED);
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(),
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
                                            {sideLength / 2, 0, sideLength, sideLength / 2}, BLUE);
 
-            auto& layers = mDisplayGfx[display->getDisplayId()].layers;
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            auto& layers = mDisplayGfx[display.getDisplayId()].layers;
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -1773,55 +1874,59 @@
 }
 
 TEST_P(GraphicsTransformCompositionTest, ROT_180) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
 
-            ReadbackBuffer readbackBuffer(
-                    display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                    display->getDisplayHeight(),
-                    mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                    mDisplayProperties.at(display->getDisplayId()).dataspace);
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
+
+            ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
+                                          display.getDisplayWidth(), display.getDisplayHeight(),
+                                          mDisplayProperties.at(display.getDisplayId()).pixelFormat,
+                                          dataspace);
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-            auto& bufferLayer = mDisplayGfx[display->getDisplayId()].bufferLayer;
+            auto& bufferLayer = mDisplayGfx[display.getDisplayId()].bufferLayer;
             bufferLayer->setTransform(Transform::ROT_180);
             bufferLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
 
             std::vector<Color> expectedColors(
-                    static_cast<size_t>(display->getDisplayWidth() * display->getDisplayHeight()));
-            int& sideLength = mDisplayGfx[display->getDisplayId()].sideLength;
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(),
+                    static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
+            int& sideLength = mDisplayGfx[display.getDisplayId()].sideLength;
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
                                            {sideLength / 2, sideLength / 2, sideLength, sideLength},
                                            RED);
-            ReadbackHelper::fillColorsArea(expectedColors, display->getDisplayWidth(),
+            ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
                                            {0, 0, sideLength / 2, sideLength / 2}, BLUE);
 
-            auto& layers = mDisplayGfx[display->getDisplayId()].layers;
-            writeLayers(layers, display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.validateDisplay(display->getDisplayId(),
+            auto& layers = mDisplayGfx[display.getDisplayId()].layers;
+            writeLayers(layers, display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.validateDisplay(display.getDisplayId(),
                                             ComposerClientWriter::kNoTimestamp,
                                             ComposerClientWrapper::kNoFrameIntervalNs);
-            execute(display->getDisplayId());
-            if (!mDisplayProperties.at(display->getDisplayId())
-                         .reader.takeChangedCompositionTypes(display->getDisplayId())
+            execute(display.getDisplayId());
+            if (!mDisplayProperties.at(display.getDisplayId())
+                         .reader.takeChangedCompositionTypes(display.getDisplayId())
                          .empty()) {
                 continue;
             }
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-            mDisplayProperties.at(display->getDisplayId())
-                    .writer.presentDisplay(display->getDisplayId());
-            execute(display->getDisplayId());
-            ASSERT_TRUE(mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+            mDisplayProperties.at(display.getDisplayId())
+                    .writer.presentDisplay(display.getDisplayId());
+            execute(display.getDisplayId());
+            ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
             ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-            auto& testRenderEngine =
-                    mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+            auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
             testRenderEngine->setRenderLayers(layers);
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
             ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
@@ -1888,59 +1993,63 @@
 
 // @VsrTest = 4.4-015
 TEST_P(GraphicsColorManagementCompositionTest, ColorConversion) {
-    for (const DisplayWrapper* display : mDisplaysWithReadbackBuffers) {
-        for (ColorMode mode : mDisplayProperties.at(display->getDisplayId()).testColorModes) {
-            EXPECT_TRUE(mComposerClient
-                                ->setColorMode(display->getDisplayId(), mode,
-                                               RenderIntent::COLORIMETRIC)
-                                .isOk());
+    for (const DisplayWrapper display : mAllDisplays) {
+        for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
+            EXPECT_TRUE(
+                    mComposerClient
+                            ->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+            auto [dataspace, readbackSupported] =
+                    GetDataspaceAndIfReadBackSupported(display.getDisplayId());
+            if (!readbackSupported) {
+                continue;
+            }
 
             auto& clientCompositionDisplaySettings =
-                    mDisplayProperties.at(display->getDisplayId()).clientCompositionDisplaySettings;
+                    mDisplayProperties.at(display.getDisplayId()).clientCompositionDisplaySettings;
             clientCompositionDisplaySettings.outputDataspace =
-                    static_cast<::android::ui::Dataspace>(
-                            mDisplayProperties.at(display->getDisplayId()).dataspace);
-            mDisplayProperties.at(display->getDisplayId())
+                    static_cast<::android::ui::Dataspace>(dataspace);
+            mDisplayProperties.at(display.getDisplayId())
                     .testRenderEngine->setDisplaySettings(clientCompositionDisplaySettings);
 
-            makeLayer(*display);
+            makeLayer(display);
             for (auto color : {LIGHT_RED, LIGHT_GREEN, LIGHT_BLUE}) {
                 ALOGD("Testing color: %f, %f, %f, %f with color mode: %d", color.r, color.g,
                       color.b, color.a, mode);
                 ReadbackBuffer readbackBuffer(
-                        display->getDisplayId(), mComposerClient, display->getDisplayWidth(),
-                        display->getDisplayHeight(),
-                        mDisplayProperties.at(display->getDisplayId()).pixelFormat,
-                        mDisplayProperties.at(display->getDisplayId()).dataspace);
+                        display.getDisplayId(), mComposerClient, display.getDisplayWidth(),
+                        display.getDisplayHeight(),
+                        mDisplayProperties.at(display.getDisplayId()).pixelFormat, dataspace);
                 ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-                fillColor(*display, color);
-                auto& layer = mDisplayGfx[display->getDisplayId()].layer;
-                writeLayers({layer}, display->getDisplayId());
-                EXPECT_TRUE(mComposerClient->setPowerMode(display->getDisplayId(), PowerMode::ON)
+                fillColor(display, color);
+                auto& layer = mDisplayGfx[display.getDisplayId()].layer;
+                writeLayers({layer}, display.getDisplayId());
+                EXPECT_TRUE(mComposerClient->setPowerMode(display.getDisplayId(), PowerMode::ON)
                                     .isOk());
 
                 ASSERT_TRUE(
-                        mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-                mDisplayProperties.at(display->getDisplayId())
-                        .writer.validateDisplay(display->getDisplayId(),
+                        mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+                mDisplayProperties.at(display.getDisplayId())
+                        .writer.validateDisplay(display.getDisplayId(),
                                                 ComposerClientWriter::kNoTimestamp,
                                                 ComposerClientWrapper::kNoFrameIntervalNs);
-                execute(display->getDisplayId());
-                if (!mDisplayProperties.at(display->getDisplayId())
-                             .reader.takeChangedCompositionTypes(display->getDisplayId())
+                execute(display.getDisplayId());
+                if (!mDisplayProperties.at(display.getDisplayId())
+                             .reader.takeChangedCompositionTypes(display.getDisplayId())
                              .empty()) {
                     continue;
                 }
                 ASSERT_TRUE(
-                        mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
-                mDisplayProperties.at(display->getDisplayId())
-                        .writer.presentDisplay(display->getDisplayId());
-                execute(display->getDisplayId());
+                        mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
+                mDisplayProperties.at(display.getDisplayId())
+                        .writer.presentDisplay(display.getDisplayId());
+                execute(display.getDisplayId());
                 ASSERT_TRUE(
-                        mDisplayProperties.at(display->getDisplayId()).reader.takeErrors().empty());
+                        mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
 
                 auto& testRenderEngine =
-                        mDisplayProperties.at(display->getDisplayId()).testRenderEngine;
+                        mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
                 testRenderEngine->setRenderLayers({layer});
                 ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
                 ASSERT_NO_FATAL_FAILURE(
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.h b/radio/aidl/vts/radio_aidl_hal_utils.h
index d9c7311..3e2e633 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.h
+++ b/radio/aidl/vts/radio_aidl_hal_utils.h
@@ -65,8 +65,6 @@
 
 static constexpr const char* FEATURE_TELEPHONY = "android.hardware.telephony";
 
-static constexpr const char* FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
-
 static constexpr const char* FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
 
 static constexpr const char* FEATURE_TELEPHONY_CALLING = "android.hardware.telephony.calling";
diff --git a/radio/aidl/vts/radio_messaging_test.cpp b/radio/aidl/vts/radio_messaging_test.cpp
index 089895f..7e4ef96 100644
--- a/radio/aidl/vts/radio_messaging_test.cpp
+++ b/radio/aidl/vts/radio_messaging_test.cpp
@@ -113,104 +113,6 @@
 }
 
 /*
- * Test IRadioMessaging.sendCdmaSms() for the response returned.
- */
-TEST_P(RadioMessagingTest, sendCdmaSms) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping sendCdmaSms "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    // Create a CdmaSmsAddress
-    CdmaSmsAddress cdmaSmsAddress;
-    cdmaSmsAddress.digitMode = CdmaSmsAddress::DIGIT_MODE_FOUR_BIT;
-    cdmaSmsAddress.isNumberModeDataNetwork = false;
-    cdmaSmsAddress.numberType = CdmaSmsAddress::NUMBER_TYPE_UNKNOWN;
-    cdmaSmsAddress.numberPlan = CdmaSmsAddress::NUMBER_PLAN_UNKNOWN;
-    cdmaSmsAddress.digits = (std::vector<uint8_t>){11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
-
-    // Create a CdmaSmsSubAddress
-    CdmaSmsSubaddress cdmaSmsSubaddress;
-    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddress::SUBADDRESS_TYPE_NSAP;
-    cdmaSmsSubaddress.odd = false;
-    cdmaSmsSubaddress.digits = (std::vector<uint8_t>){};
-
-    // Create a CdmaSmsMessage
-    CdmaSmsMessage cdmaSmsMessage;
-    cdmaSmsMessage.teleserviceId = 4098;
-    cdmaSmsMessage.isServicePresent = false;
-    cdmaSmsMessage.serviceCategory = 0;
-    cdmaSmsMessage.address = cdmaSmsAddress;
-    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
-    cdmaSmsMessage.bearerData =
-            (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
-
-    radio_messaging->sendCdmaSms(serial, cdmaSmsMessage);
-
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_messaging->rspInfo.error,
-                {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
-                CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
- * Test IRadioMessaging.sendCdmaSmsExpectMore() for the response returned.
- */
-TEST_P(RadioMessagingTest, sendCdmaSmsExpectMore) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping sendCdmaSmsExpectMore "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    // Create a CdmaSmsAddress
-    CdmaSmsAddress cdmaSmsAddress;
-    cdmaSmsAddress.digitMode = CdmaSmsAddress::DIGIT_MODE_FOUR_BIT;
-    cdmaSmsAddress.isNumberModeDataNetwork = false;
-    cdmaSmsAddress.numberType = CdmaSmsAddress::NUMBER_TYPE_UNKNOWN;
-    cdmaSmsAddress.numberPlan = CdmaSmsAddress::NUMBER_PLAN_UNKNOWN;
-    cdmaSmsAddress.digits = (std::vector<uint8_t>){11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
-
-    // Create a CdmaSmsSubAddress
-    CdmaSmsSubaddress cdmaSmsSubaddress;
-    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddress::SUBADDRESS_TYPE_NSAP;
-    cdmaSmsSubaddress.odd = false;
-    cdmaSmsSubaddress.digits = (std::vector<uint8_t>){};
-
-    // Create a CdmaSmsMessage
-    CdmaSmsMessage cdmaSmsMessage;
-    cdmaSmsMessage.teleserviceId = 4098;
-    cdmaSmsMessage.isServicePresent = false;
-    cdmaSmsMessage.serviceCategory = 0;
-    cdmaSmsMessage.address = cdmaSmsAddress;
-    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
-    cdmaSmsMessage.bearerData =
-            (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
-
-    radio_messaging->sendCdmaSmsExpectMore(serial, cdmaSmsMessage);
-
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_messaging->rspInfo.error,
-                {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
-                CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
  * Test IRadioMessaging.setGsmBroadcastConfig() for the response returned.
  */
 TEST_P(RadioMessagingTest, setGsmBroadcastConfig) {
@@ -304,85 +206,6 @@
 }
 
 /*
- * Test IRadioMessaging.setCdmaBroadcastConfig() for the response returned.
- */
-TEST_P(RadioMessagingTest, setCdmaBroadcastConfig) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping setCdmaBroadcastConfig "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    CdmaBroadcastSmsConfigInfo cbSmsConfig;
-    cbSmsConfig.serviceCategory = 4096;
-    cbSmsConfig.language = 1;
-    cbSmsConfig.selected = true;
-
-    std::vector<CdmaBroadcastSmsConfigInfo> cdmaBroadcastSmsConfigInfoList = {cbSmsConfig};
-
-    radio_messaging->setCdmaBroadcastConfig(serial, cdmaBroadcastSmsConfigInfoList);
-
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_messaging->rspInfo.error,
-                                     {RadioError::NONE, RadioError::INVALID_MODEM_STATE},
-                                     CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
- * Test IRadioMessaging.getCdmaBroadcastConfig() for the response returned.
- */
-TEST_P(RadioMessagingTest, getCdmaBroadcastConfig) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping getCdmaBroadcastConfig "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    radio_messaging->getCdmaBroadcastConfig(serial);
-
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_messaging->rspInfo.error, {RadioError::NONE},
-                                     CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
- * Test IRadioMessaging.setCdmaBroadcastActivation() for the response returned.
- */
-TEST_P(RadioMessagingTest, setCdmaBroadcastActivation) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping setCdmaBroadcastActivation "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-    bool activate = false;
-
-    radio_messaging->setCdmaBroadcastActivation(serial, activate);
-
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_messaging->rspInfo.error,
-                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS},
-                                     CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
  * Test IRadioMessaging.setGsmBroadcastActivation() for the response returned.
  */
 TEST_P(RadioMessagingTest, setGsmBroadcastActivation) {
@@ -462,35 +285,6 @@
 }
 
 /*
- * Test IRadioMessaging.acknowledgeLastIncomingCdmaSms() for the response returned.
- */
-TEST_P(RadioMessagingTest, acknowledgeLastIncomingCdmaSms) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping acknowledgeIncomingGsmSmsWithPdu "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    // Create a CdmaSmsAck
-    CdmaSmsAck cdmaSmsAck;
-    cdmaSmsAck.errorClass = false;
-    cdmaSmsAck.smsCauseCode = 1;
-
-    radio_messaging->acknowledgeLastIncomingCdmaSms(serial, cdmaSmsAck);
-
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_messaging->rspInfo.error,
-                                     {RadioError::INVALID_ARGUMENTS, RadioError::NO_SMS_TO_ACK},
-                                     CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
  * Test IRadioMessaging.sendImsSms() for the response returned.
  */
 TEST_P(RadioMessagingTest, sendImsSms) {
@@ -656,118 +450,6 @@
 }
 
 /*
- * Test IRadioMessaging.writeSmsToRuim() for the response returned.
- */
-TEST_P(RadioMessagingTest, writeSmsToRuim) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping writeSmsToRuim "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    // Create a CdmaSmsAddress
-    CdmaSmsAddress cdmaSmsAddress;
-    cdmaSmsAddress.digitMode = CdmaSmsAddress::DIGIT_MODE_FOUR_BIT;
-    cdmaSmsAddress.isNumberModeDataNetwork = false;
-    cdmaSmsAddress.numberType = CdmaSmsAddress::NUMBER_TYPE_UNKNOWN;
-    cdmaSmsAddress.numberPlan = CdmaSmsAddress::NUMBER_PLAN_UNKNOWN;
-    cdmaSmsAddress.digits = (std::vector<uint8_t>){11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
-
-    // Create a CdmaSmsSubAddress
-    CdmaSmsSubaddress cdmaSmsSubaddress;
-    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddress::SUBADDRESS_TYPE_NSAP;
-    cdmaSmsSubaddress.odd = false;
-    cdmaSmsSubaddress.digits = (std::vector<uint8_t>){};
-
-    // Create a CdmaSmsMessage
-    CdmaSmsMessage cdmaSmsMessage;
-    cdmaSmsMessage.teleserviceId = 4098;
-    cdmaSmsMessage.isServicePresent = false;
-    cdmaSmsMessage.serviceCategory = 0;
-    cdmaSmsMessage.address = cdmaSmsAddress;
-    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
-    cdmaSmsMessage.bearerData =
-            (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
-
-    // Create a CdmaSmsWriteArgs
-    CdmaSmsWriteArgs cdmaSmsWriteArgs;
-    cdmaSmsWriteArgs.status = CdmaSmsWriteArgs::STATUS_REC_UNREAD;
-    cdmaSmsWriteArgs.message = cdmaSmsMessage;
-
-    radio_messaging->writeSmsToRuim(serial, cdmaSmsWriteArgs);
-
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_messaging->rspInfo.error,
-                {RadioError::NONE, RadioError::INVALID_ARGUMENTS, RadioError::INVALID_SMS_FORMAT,
-                 RadioError::INVALID_SMSC_ADDRESS, RadioError::INVALID_STATE, RadioError::MODEM_ERR,
-                 RadioError::NO_SUCH_ENTRY, RadioError::SIM_ABSENT},
-                CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
- * Test IRadioMessaging.deleteSmsOnRuim() for the response returned.
- */
-TEST_P(RadioMessagingTest, deleteSmsOnRuim) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping deleteSmsOnRuim "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-    int index = 1;
-
-    // Create a CdmaSmsAddress
-    CdmaSmsAddress cdmaSmsAddress;
-    cdmaSmsAddress.digitMode = CdmaSmsAddress::DIGIT_MODE_FOUR_BIT;
-    cdmaSmsAddress.isNumberModeDataNetwork = false;
-    cdmaSmsAddress.numberType = CdmaSmsAddress::NUMBER_TYPE_UNKNOWN;
-    cdmaSmsAddress.numberPlan = CdmaSmsAddress::NUMBER_PLAN_UNKNOWN;
-    cdmaSmsAddress.digits = (std::vector<uint8_t>){11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
-
-    // Create a CdmaSmsSubAddress
-    CdmaSmsSubaddress cdmaSmsSubaddress;
-    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddress::SUBADDRESS_TYPE_NSAP;
-    cdmaSmsSubaddress.odd = false;
-    cdmaSmsSubaddress.digits = (std::vector<uint8_t>){};
-
-    // Create a CdmaSmsMessage
-    CdmaSmsMessage cdmaSmsMessage;
-    cdmaSmsMessage.teleserviceId = 4098;
-    cdmaSmsMessage.isServicePresent = false;
-    cdmaSmsMessage.serviceCategory = 0;
-    cdmaSmsMessage.address = cdmaSmsAddress;
-    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
-    cdmaSmsMessage.bearerData =
-            (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
-
-    // Create a CdmaSmsWriteArgs
-    CdmaSmsWriteArgs cdmaSmsWriteArgs;
-    cdmaSmsWriteArgs.status = CdmaSmsWriteArgs::STATUS_REC_UNREAD;
-    cdmaSmsWriteArgs.message = cdmaSmsMessage;
-
-    radio_messaging->deleteSmsOnRuim(serial, index);
-
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_messaging->rspInfo.error,
-                {RadioError::NONE, RadioError::INVALID_ARGUMENTS, RadioError::INVALID_MODEM_STATE,
-                 RadioError::MODEM_ERR, RadioError::NO_SUCH_ENTRY, RadioError::SIM_ABSENT},
-                CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
  * Test IRadioMessaging.reportSmsMemoryStatus() for the response returned.
  */
 TEST_P(RadioMessagingTest, reportSmsMemoryStatus) {
diff --git a/radio/aidl/vts/radio_modem_test.cpp b/radio/aidl/vts/radio_modem_test.cpp
index 9fb7db8..1c8a6f8 100644
--- a/radio/aidl/vts/radio_modem_test.cpp
+++ b/radio/aidl/vts/radio_modem_test.cpp
@@ -201,6 +201,13 @@
         GTEST_SKIP() << "Skipping getDeviceIdentity "
                         "due to undefined FEATURE_TELEPHONY";
     }
+    int32_t aidl_version;
+    ndk::ScopedAStatus aidl_status = radio_modem->getInterfaceVersion(&aidl_version);
+    ASSERT_OK(aidl_status);
+    if (aidl_version >= 4) {
+        ALOGI("Skipped the test since getDeviceIdentity is deprecated");
+        GTEST_SKIP();
+    }
 
     serial = GetRandomSerialNumber();
 
@@ -285,29 +292,6 @@
 }
 
 /*
- * Test IRadioModem.nvWriteCdmaPrl() for the response returned.
- */
-TEST_P(RadioModemTest, nvWriteCdmaPrl) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping nvWriteCdmaPrl "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-    std::vector<uint8_t> prl = {1, 2, 3, 4, 5};
-
-    radio_modem->nvWriteCdmaPrl(serial, std::vector<uint8_t>(prl));
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_modem->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_modem->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_modem->rspInfo.error, {RadioError::NONE},
-                                     CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
  * Test IRadioModem.nvResetConfig() for the response returned.
  */
 TEST_P(RadioModemTest, nvResetConfig) {
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index ff231db..bdd4148 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -590,42 +590,6 @@
 }
 
 /*
- * Test IRadioNetwork.setSignalStrengthReportingCriteria() for CDMA2000
- */
-TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Cdma2000) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
-        GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Cdma2000 "
-                        "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
-    }
-
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Cdma2000 "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    SignalThresholdInfo signalThresholdInfo;
-    signalThresholdInfo.signalMeasurement = SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSSI;
-    signalThresholdInfo.hysteresisMs = 5000;
-    signalThresholdInfo.hysteresisDb = 2;
-    signalThresholdInfo.thresholds = {-105, -90, -75, -65};
-    signalThresholdInfo.isEnabled = true;
-    signalThresholdInfo.ran = AccessNetwork::CDMA2000;
-
-    ndk::ScopedAStatus res =
-            radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo});
-    ASSERT_OK(res);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
-
-    ALOGI("setSignalStrengthReportingCriteria_Cdma2000, rspInfo.error = %s\n",
-          toString(radioRsp_network->rspInfo.error).c_str());
-    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE}));
-}
-
-/*
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for NGRAN_SSRSRP
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_NGRAN_SSRSRP) {
@@ -790,15 +754,6 @@
     signalThresholdInfoEutran.isEnabled = true;
     signalThresholdInfoEutran.ran = AccessNetwork::EUTRAN;
 
-    SignalThresholdInfo signalThresholdInfoCdma2000;
-    signalThresholdInfoCdma2000.signalMeasurement =
-            SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSSI;
-    signalThresholdInfoCdma2000.hysteresisMs = 5000;
-    signalThresholdInfoCdma2000.hysteresisDb = 2;
-    signalThresholdInfoCdma2000.thresholds = {-105, -90, -75, -65};
-    signalThresholdInfoCdma2000.isEnabled = true;
-    signalThresholdInfoCdma2000.ran = AccessNetwork::CDMA2000;
-
     SignalThresholdInfo signalThresholdInfoNgran;
     signalThresholdInfoNgran.signalMeasurement =
             SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_SSRSRP;
@@ -811,9 +766,6 @@
     std::vector<SignalThresholdInfo> candidateSignalThresholdInfos = {
             signalThresholdInfoGeran, signalThresholdInfoUtran, signalThresholdInfoEutran,
             signalThresholdInfoNgran};
-    if (deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        candidateSignalThresholdInfos.push_back(signalThresholdInfoCdma2000);
-    }
 
     std::vector<SignalThresholdInfo> supportedSignalThresholdInfos;
     for (size_t i = 0; i < candidateSignalThresholdInfos.size(); i++) {
@@ -2015,53 +1967,6 @@
 }
 
 /*
- * Test IRadioNetwork.setCdmaRoamingPreference() for the response returned.
- */
-TEST_P(RadioNetworkTest, setCdmaRoamingPreference) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping setCdmaRoamingPreference "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    radio_network->setCdmaRoamingPreference(serial, CdmaRoamingType::HOME_NETWORK);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_network->rspInfo.error,
-                {RadioError::NONE, RadioError::SIM_ABSENT, RadioError::REQUEST_NOT_SUPPORTED}));
-    }
-}
-
-/*
- * Test IRadioNetwork.getCdmaRoamingPreference() for the response returned.
- */
-TEST_P(RadioNetworkTest, getCdmaRoamingPreference) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping getCdmaRoamingPreference "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    radio_network->getCdmaRoamingPreference(serial);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                 {RadioError::NONE, RadioError::SIM_ABSENT, RadioError::MODEM_ERR},
-                                 CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
  * Test IRadioNetwork.getVoiceRadioTechnology() for the response returned.
  */
 TEST_P(RadioNetworkTest, getVoiceRadioTechnology) {
diff --git a/radio/aidl/vts/radio_sim_test.cpp b/radio/aidl/vts/radio_sim_test.cpp
index e7c7c65..73beb57 100644
--- a/radio/aidl/vts/radio_sim_test.cpp
+++ b/radio/aidl/vts/radio_sim_test.cpp
@@ -1066,106 +1066,6 @@
 }
 
 /*
- * Test IRadioSim.getCdmaSubscription() for the response returned.
- */
-TEST_P(RadioSimTest, getCdmaSubscription) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping getCdmaSubscription "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    radio_sim->getCdmaSubscription(serial);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_sim->rspInfo.error,
-                {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::SIM_ABSENT}));
-    }
-}
-
-/*
- * Test IRadioSim.getCdmaSubscriptionSource() for the response returned.
- */
-TEST_P(RadioSimTest, getCdmaSubscriptionSource) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping getCdmaSubscriptionSource "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    radio_sim->getCdmaSubscriptionSource(serial);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_sim->rspInfo.error,
-                {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::SIM_ABSENT}));
-    }
-}
-
-/*
- * Test IRadioSim.setCdmaSubscriptionSource() for the response returned.
- */
-TEST_P(RadioSimTest, setCdmaSubscriptionSource) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping setCdmaSubscriptionSource "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    radio_sim->setCdmaSubscriptionSource(serial, CdmaSubscriptionSource::RUIM_SIM);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_sim->rspInfo.error,
-                {RadioError::NONE, RadioError::SIM_ABSENT, RadioError::SUBSCRIPTION_NOT_AVAILABLE},
-                CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
- * Test IRadioSim.setUiccSubscription() for the response returned.
- */
-TEST_P(RadioSimTest, setUiccSubscription) {
-    if (!shouldTestCdma()) {
-        GTEST_SKIP() << "Skipping CDMA testing (deprecated)";
-    }
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
-        GTEST_SKIP() << "Skipping setUiccSubscription "
-                        "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
-    }
-
-    serial = GetRandomSerialNumber();
-    SelectUiccSub item;
-    memset(&item, 0, sizeof(item));
-
-    radio_sim->setUiccSubscription(serial, item);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
-                                 {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
-                                  RadioError::MODEM_ERR, RadioError::SUBSCRIPTION_NOT_SUPPORTED},
-                                 CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
  * Test IRadioSim.sendEnvelope() for the response returned.
  */
 TEST_P(RadioSimTest, sendEnvelope) {
diff --git a/radio/aidl/vts/radio_voice_test.cpp b/radio/aidl/vts/radio_voice_test.cpp
index 9eb5bac..3df6bfb 100644
--- a/radio/aidl/vts/radio_voice_test.cpp
+++ b/radio/aidl/vts/radio_voice_test.cpp
@@ -821,31 +821,6 @@
 }
 
 /*
- * Test IRadioVoice.sendCdmaFeatureCode() for the response returned.
- */
-TEST_P(RadioVoiceTest, sendCdmaFeatureCode) {
-    if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        GTEST_SKIP() << "Skipping sendCdmaFeatureCode "
-                        "due to undefined FEATURE_TELEPHONY_CDMA";
-    }
-
-    serial = GetRandomSerialNumber();
-
-    radio_voice->sendCdmaFeatureCode(serial, std::string());
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_voice->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_voice->rspInfo.serial);
-
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_voice->rspInfo.error,
-                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
-                                      RadioError::INVALID_CALL_ID, RadioError::INVALID_MODEM_STATE,
-                                      RadioError::MODEM_ERR, RadioError::OPERATION_NOT_ALLOWED},
-                                     CHECK_GENERAL_ERROR));
-    }
-}
-
-/*
  * Test IRadioVoice.sendDtmf() for the response returned.
  */
 TEST_P(RadioVoiceTest, sendDtmf) {
diff --git a/security/see/hwcrypto/aidl/vts/functional/Android.bp b/security/see/hwcrypto/aidl/vts/functional/Android.bp
index c2514d1..fc63878 100644
--- a/security/see/hwcrypto/aidl/vts/functional/Android.bp
+++ b/security/see/hwcrypto/aidl/vts/functional/Android.bp
@@ -30,6 +30,7 @@
         "libvsock",
         "librpcbinder_rs",
         "librustutils",
+        "libhwcryptohal_common",
     ],
     arch: {
         arm64: {
@@ -50,13 +51,37 @@
 }
 
 rust_test {
-    name: "VtsAidlHwCryptoConnTest",
-    srcs: ["connection_test.rs"],
+    name: "VtsAidlHwCryptoTests",
+    srcs: ["hwcryptokey_tests.rs"],
+    test_config: "AndroidKeyOperations.xml",
     require_root: true,
     defaults: [
         "hw_crypto_hal_aidl_rust_defaults",
+        "rdroidtest.defaults",
     ],
     rustlibs: [
         "libhwcryptohal_vts_test",
     ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+rust_test {
+    name: "VtsAidlHwCryptoOperationsTests",
+    srcs: ["hwcrypto_operations_tests.rs"],
+    test_config: "AndroidTestOperations.xml",
+    require_root: true,
+    defaults: [
+        "hw_crypto_hal_aidl_rust_defaults",
+        "rdroidtest.defaults",
+    ],
+    rustlibs: [
+        "libhwcryptohal_vts_test",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/security/see/hwcrypto/aidl/vts/functional/AndroidKeyOperations.xml b/security/see/hwcrypto/aidl/vts/functional/AndroidKeyOperations.xml
new file mode 100644
index 0000000..57229d7
--- /dev/null
+++ b/security/see/hwcrypto/aidl/vts/functional/AndroidKeyOperations.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2025 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 HwCrypto HAL operations VTS tests.">
+  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="push-file" key="VtsAidlHwCryptoTests" value="/data/local/tmp/VtsAidlHwCryptoTests" />
+  </target_preparer>
+
+  <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+    <option name="test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="VtsAidlHwCryptoTests" />
+    <!-- Rust tests are run in parallel by default. Run these ones
+         single-threaded. -->
+    <option name="native-test-flag" value="--test-threads=1" />
+  </test>
+</configuration>
\ No newline at end of file
diff --git a/security/see/hwcrypto/aidl/vts/functional/AndroidTestOperations.xml b/security/see/hwcrypto/aidl/vts/functional/AndroidTestOperations.xml
new file mode 100644
index 0000000..f069b3b
--- /dev/null
+++ b/security/see/hwcrypto/aidl/vts/functional/AndroidTestOperations.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2025 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 HwCrypto HAL device key VTS tests.">
+  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="push-file" key="VtsAidlHwCryptoOperationsTests" value="/data/local/tmp/VtsAidlHwCryptoOperationsTests" />
+  </target_preparer>
+
+  <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+    <option name="test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="VtsAidlHwCryptoOperationsTests" />
+    <!-- Rust tests are run in parallel by default. Run these ones
+         single-threaded. -->
+    <option name="native-test-flag" value="--test-threads=1" />
+  </test>
+</configuration>
\ No newline at end of file
diff --git a/security/see/hwcrypto/aidl/vts/functional/AndroidTestSystem.xml b/security/see/hwcrypto/aidl/vts/functional/AndroidTestSystem.xml
deleted file mode 100644
index 649be23..0000000
--- a/security/see/hwcrypto/aidl/vts/functional/AndroidTestSystem.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright 2025 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="Runs {MODULE}">
-    <!-- object type="module_controller" class="com.android.tradefed.testtype.suite.module.CommandSuccessModuleController" -->
-        <!--Skip the test when trusty VM is not enabled. -->
-        <!--option name="run-command" value="getprop trusty.test_vm.nonsecure_vm_ready | grep 1" /-->
-    <!--/object-->
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
-    <!-- Target Preparers - Run Shell Commands -->
-    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
-        <option name="cleanup" value="true" />
-        <option name="push-file" key="trusty-vm-launcher.sh" value="/data/local/tmp/trusty_test_vm/trusty-vm-launcher.sh" />
-        <option name="push-file" key="trusty-wait-ready.sh" value="/data/local/tmp/trusty_test_vm/trusty-wait-ready.sh" />
-        <option name="push-file" key="wait_hw_crypto" value="/data/local/tmp/trusty_test_vm/wait_hw_crypto" />
-        <option name="push-file" key="trusty-test_vm-config.json" value="/data/local/tmp/trusty_test_vm/trusty-test_vm-config.json" />
-        <option name="push-file" key="trusty_test_vm.elf" value="/data/local/tmp/trusty_test_vm/trusty_test_vm.elf" />
-        <option name="push-file" key="VtsAidlHwCryptoConnTestSystem" value="/data/local/tmp/VtsAidlHwCryptoConnTestSystem" />
-    </target_preparer>
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="throw-if-cmd-fail" value="true" />
-        <!--Note: the first run-command shall not expect the background command to have started -->
-        <option name="run-bg-command" value="sh /data/local/tmp/trusty_test_vm/trusty-vm-launcher.sh" />
-        <option name="run-command" value="sh /data/local/tmp/trusty_test_vm/trusty-wait-ready.sh" />
-        <option name="run-bg-command" value="start trusty-hwcryptohal" />
-        <option name="run-command" value="/data/local/tmp/trusty_test_vm/wait_hw_crypto" />
-        <option name="run-command" value="start storageproxyd_test_system" />
-        <option name="teardown-command" value="stop storageproxyd_test_system" />
-        <option name="teardown-command" value="stop trusty-hwcryptohal" />
-        <option name="teardown-command" value="killall storageproxyd_test_system || true" />
-        <option name="teardown-command" value="stop trusty-hwcryptohal" />
-        <option name="teardown-command" value="killall trusty || true" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
-        <option name="test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="VtsAidlHwCryptoConnTestSystem" />
-        <!-- 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/see/hwcrypto/aidl/vts/functional/connection_test.rs b/security/see/hwcrypto/aidl/vts/functional/connection_test.rs
deleted file mode 100644
index 338923d..0000000
--- a/security/see/hwcrypto/aidl/vts/functional/connection_test.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//! HwCrypto Connection tests.
-
-#[test]
-fn test_hwcrypto_key_connection() {
-    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey();
-    assert!(hw_crypto_key.is_ok(), "Couldn't get back a hwcryptokey binder object");
-}
diff --git a/security/see/hwcrypto/aidl/vts/functional/hwcrypto_operations_tests.rs b/security/see/hwcrypto/aidl/vts/functional/hwcrypto_operations_tests.rs
new file mode 100644
index 0000000..69a34e3
--- /dev/null
+++ b/security/see/hwcrypto/aidl/vts/functional/hwcrypto_operations_tests.rs
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+
+//! HwCryptoOperations tests.
+
+use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::types::{
+    AesKey::AesKey, ExplicitKeyMaterial::ExplicitKeyMaterial, KeyType::KeyType, KeyLifetime::KeyLifetime,
+    KeyUse::KeyUse, OperationData::OperationData, HmacOperationParameters::HmacOperationParameters,
+    SymmetricOperationParameters::SymmetricOperationParameters, SymmetricOperation::SymmetricOperation,
+    HmacKey::HmacKey, CipherModeParameters::CipherModeParameters, AesCipherMode::AesCipherMode,
+    SymmetricCryptoParameters::SymmetricCryptoParameters,
+};
+use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::{
+    KeyPolicy::KeyPolicy,CryptoOperation::CryptoOperation,CryptoOperationSet::CryptoOperationSet,
+    OperationParameters::OperationParameters, PatternParameters::PatternParameters,
+};
+use rdroidtest::{ignore_if, rdroidtest};
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_key_operations_connection() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key.getHwCryptoOperations();
+    assert!(hw_crypto_operations.is_ok(), "Couldn't get back a hwcrypto operations binder object");
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_key_operations_simple_aes_test() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let policy = KeyPolicy {
+        usage: KeyUse::ENCRYPT_DECRYPT,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyManagementKey: false,
+        keyType: KeyType::AES_128_CBC_PKCS7_PADDING,
+    };
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let nonce = [0u8; 16];
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    let input_data = OperationData::DataBuffer("string to be encrypted".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    let mut op_result = hw_crypto_operations
+        .processCommandList(&mut crypto_sets)
+        .expect("couldn't process commands");
+    // Extracting the vector from the command list because of ownership
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let context = op_result.remove(0).context;
+    // Separating the finish call on a different command set to test the returned context
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(encrypted_data);
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+
+    // Decrypting
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::DECRYPT;
+    let sym_op_params = SymmetricOperationParameters { key: Some(key), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::DataInput(OperationData::DataBuffer(encrypted_data)));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    // Extracting the vector from the command list because of ownership
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let decrypted_msg =
+        String::from_utf8(decrypted_data).expect("couldn't decode received message");
+    assert_eq!(decrypted_msg, "string to be encrypted", "couldn't retrieve original message");
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_key_operations_simple_hmac_test() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+    let clear_key = ExplicitKeyMaterial::Hmac(HmacKey::Sha256([0; 32]));
+    let policy = KeyPolicy {
+        usage: KeyUse::SIGN,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyManagementKey: false,
+        keyType: KeyType::HMAC_SHA256,
+    };
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let hmac_parameters = HmacOperationParameters { key: Some(key.clone()) };
+    let op_parameters = OperationParameters::Hmac(hmac_parameters);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_parameters));
+    let input_data = OperationData::DataBuffer("text to be mac'ed".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    // Extracting the vector from the command list because of ownership
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(mac)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+
+    //Getting a second mac to compare
+    let hmac_parameters = HmacOperationParameters { key: Some(key) };
+    let op_parameters = OperationParameters::Hmac(hmac_parameters);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_parameters));
+    let input_data = OperationData::DataBuffer("text to be mac'ed".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    // Extracting the vector from the command list because of ownership
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(mac2)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    assert_eq!(mac, mac2, "got a different mac");
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_key_operations_aes_simple_cbcs_test_non_block_multiple() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+
+    let usage = KeyUse::ENCRYPT_DECRYPT;
+    let key_type = KeyType::AES_128_CBC_NO_PADDING;
+    let policy = KeyPolicy {
+        usage,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyType: key_type,
+        keyManagementKey: false,
+    };
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let nonce = [0u8; 16];
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 0,
+    }));
+    let input_data =
+        OperationData::DataBuffer("encryption data.0123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data = OperationData::DataBuffer("unencrypted".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+
+    let clear_encrypted_msg =
+        String::from_utf8(encrypted_data[encrypted_data.len() - "unencrypted".len()..].to_vec())
+            .expect("couldn't decode message");
+    assert_eq!(clear_encrypted_msg, "unencrypted");
+
+    // Decrypting
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::DECRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 0,
+    }));
+    cmd_list.push(CryptoOperation::DataInput(OperationData::DataBuffer(encrypted_data)));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let decrypted_msg =
+        String::from_utf8(decrypted_data).expect("couldn't decode received message");
+    assert_eq!(
+        decrypted_msg,
+        "encryption data.0123456789abcdeffedcba9876543210\
+        0123456789abcdefunencrypted",
+        "couldn't retrieve original message"
+    );
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_key_operations_aes_simple_all_encrypted_cbcs_test() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+
+    let usage = KeyUse::ENCRYPT_DECRYPT;
+    let key_type = KeyType::AES_128_CBC_NO_PADDING;
+    let policy = KeyPolicy {
+        usage,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyType: key_type,
+        keyManagementKey: false,
+    };
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let nonce = [0u8; 16];
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 0,
+    }));
+    let input_data =
+        OperationData::DataBuffer("encryption data.0123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+
+    // Checking that encrypting with patter 0,0 is equivalent to pattern 1,0
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 0,
+        numberBlocksCopy: 0,
+    }));
+    let input_data =
+        OperationData::DataBuffer("encryption data.0123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data1)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    assert_eq!(encrypted_data, encrypted_data1, "encrypted data should match");
+
+    // Decrypting
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::DECRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::DataInput(OperationData::DataBuffer(encrypted_data)));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let decrypted_msg =
+        String::from_utf8(decrypted_data).expect("couldn't decode received message");
+    assert_eq!(
+        decrypted_msg,
+        "encryption data.0123456789abcdeffedcba9876543210\
+        0123456789abcdef",
+        "couldn't retrieve original message"
+    );
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn check_cbcs_wrong_key_types() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+
+    let usage = KeyUse::ENCRYPT_DECRYPT;
+    let key_type = KeyType::AES_128_CBC_PKCS7_PADDING;
+    let policy = KeyPolicy {
+        usage,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyType: key_type,
+        keyManagementKey: false,
+    };
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let nonce = [0u8; 16];
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params = SymmetricOperationParameters { key: Some(key), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 9,
+    }));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    let process_result = hw_crypto_operations.processCommandList(&mut crypto_sets);
+    assert!(process_result.is_err(), "Should not be able to use cbcs mode with this key type");
+
+    let policy = KeyPolicy {
+        usage,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyType: KeyType::AES_256_CBC_NO_PADDING,
+        keyManagementKey: false,
+    };
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes256([0; 32]));
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let sym_op_params = SymmetricOperationParameters { key: Some(key), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 9,
+    }));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    let process_result = hw_crypto_operations.processCommandList(&mut crypto_sets);
+
+    assert!(process_result.is_err(), "Should not be able to use cbcs mode with this key type");
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn aes_simple_cbcs_test() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+
+    let usage = KeyUse::ENCRYPT_DECRYPT;
+    let key_type = KeyType::AES_128_CBC_NO_PADDING;
+    let policy = KeyPolicy {
+        usage,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyType: key_type,
+        keyManagementKey: false,
+    };
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let nonce = [0u8; 16];
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 9,
+    }));
+    let input_data =
+        OperationData::DataBuffer("encryption data.0123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data = OperationData::DataBuffer(
+        "fedcba98765432100123456789abcdefProtectedSection".as_bytes().to_vec(),
+    );
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let clear_encrypted_msg =
+        String::from_utf8(encrypted_data[16..encrypted_data.len() - 16].to_vec())
+            .expect("couldn't decode received message");
+    assert_eq!(
+        clear_encrypted_msg,
+        "0123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210\
+        0123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdef",
+        "couldn't retrieve clear portion"
+    );
+
+    // Decrypting
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::DECRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 9,
+    }));
+    cmd_list.push(CryptoOperation::DataInput(OperationData::DataBuffer(encrypted_data)));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let decrypted_msg =
+        String::from_utf8(decrypted_data).expect("couldn't decode received message");
+    assert_eq!(
+        decrypted_msg,
+        "encryption data.0123456789abcdeffedcba9876543210\
+        0123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210\
+        0123456789abcdeffedcba98765432100123456789abcdefProtectedSection",
+        "couldn't retrieve original message"
+    );
+}
+
+rdroidtest::test_main!();
diff --git a/security/see/hwcrypto/aidl/vts/functional/hwcryptokey_tests.rs b/security/see/hwcrypto/aidl/vts/functional/hwcryptokey_tests.rs
new file mode 100644
index 0000000..8b4d924
--- /dev/null
+++ b/security/see/hwcrypto/aidl/vts/functional/hwcryptokey_tests.rs
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! HwCryptoKey tests.
+
+use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::IHwCryptoKey::{
+    DerivedKeyParameters::DerivedKeyParameters, DerivedKeyPolicy::DerivedKeyPolicy,
+    DiceBoundDerivationKey::DiceBoundDerivationKey, KeySlot::KeySlot,
+};
+use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::types::{
+    HalErrorCode, AesKey::AesKey, ExplicitKeyMaterial::ExplicitKeyMaterial, KeyType::KeyType, KeyLifetime::KeyLifetime, KeyUse::KeyUse,
+    HmacKey::HmacKey, ProtectionId::ProtectionId,
+};
+use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::KeyPolicy::KeyPolicy;
+use hwcryptohal_common;
+use rdroidtest::{ignore_if, rdroidtest};
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_key_connection() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey();
+    assert!(hw_crypto_key.is_ok(), "Couldn't get back a hwcryptokey binder object");
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_key_get_current_dice_policy() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let dice_policy = hw_crypto_key.getCurrentDicePolicy().expect("Couldn't get dice policy back");
+    assert!(!dice_policy.is_empty(), "received empty dice policy");
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_get_keyslot_data() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let key = hw_crypto_key.getKeyslotData(KeySlot::KEYMINT_SHARED_HMAC_KEY);
+    assert_eq!(
+        key.err()
+            .expect("should not be able to access this keylost from the host")
+            .service_specific_error(),
+        HalErrorCode::UNAUTHORIZED,
+        "wrong error type received"
+    );
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_import_clear_key() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let mut policy = KeyPolicy {
+        usage: KeyUse::ENCRYPT_DECRYPT,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyManagementKey: false,
+        keyType: KeyType::AES_128_GCM,
+    };
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import key");
+    assert!(key.getPublicKey().is_err(), "symmetric keys don't have a public key");
+    let imported_policy = key.getKeyPolicy().expect("couldn't get key policy");
+    let serialized_policy =
+        hwcryptohal_common::key_policy_to_cbor(&policy).expect("couldn't serialize policy");
+    let serialized_impoorted_policy = hwcryptohal_common::key_policy_to_cbor(&imported_policy)
+        .expect("couldn't serialize policy");
+    assert_eq!(serialized_policy, serialized_impoorted_policy, "policies should match");
+    policy.keyLifetime = KeyLifetime::EPHEMERAL;
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy);
+    assert!(key.is_err(), "imported keys should be of type PORTABLE");
+    policy.keyLifetime = KeyLifetime::HARDWARE;
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy);
+    assert!(key.is_err(), "imported keys should be of type PORTABLE");
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_token_export_import() {
+    // This test is not representative of the complete flow because here the exporter and importer
+    // are the same client, which is not something we would usually do
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let clear_key = ExplicitKeyMaterial::Hmac(HmacKey::Sha256([0; 32]));
+    let policy = KeyPolicy {
+        usage: KeyUse::DERIVE,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyManagementKey: false,
+        keyType: KeyType::HMAC_SHA256,
+    };
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+    let dice_policy = hw_crypto_key.getCurrentDicePolicy().expect("Couldn't get dice policy back");
+    let token =
+        key.getShareableToken(dice_policy.as_slice()).expect("Couldn't get shareable token");
+    let imported_key = hw_crypto_key
+        .keyTokenImport(&token, dice_policy.as_slice());
+    assert!(imported_key.is_ok(), "Couldn't import shareable token");
+    // TODO: Use operations to verify that the keys match
+}
+
+#[rdroidtest]
+#[ignore_if(hwcryptohal_vts_test::ignore_test())]
+fn test_hwcrypto_android_invalid_calls() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let clear_key = ExplicitKeyMaterial::Hmac(HmacKey::Sha256([0; 32]));
+    let policy = KeyPolicy {
+        usage: KeyUse::DERIVE,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyManagementKey: false,
+        keyType: KeyType::HMAC_SHA256,
+    };
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+    let protections = Vec::new();
+    let res = key.setProtectionId(ProtectionId::WIDEVINE_OUTPUT_BUFFER, &protections);
+    assert_eq!(
+        res.err()
+            .expect("should not be call this function from the host")
+            .service_specific_error(),
+        HalErrorCode::UNAUTHORIZED,
+        "wrong error type received"
+    );
+    let derivation_key = DiceBoundDerivationKey::OpaqueKey(Some(key));
+    let res = hw_crypto_key.deriveCurrentDicePolicyBoundKey(&derivation_key);
+    assert_eq!(
+        res.err()
+            .expect("should not be call this function from the host")
+            .service_specific_error(),
+        HalErrorCode::UNAUTHORIZED,
+        "wrong error type received"
+    );
+    let fake_policy = Vec::new();
+    let res = hw_crypto_key.deriveDicePolicyBoundKey(&derivation_key, &fake_policy);
+    assert_eq!(
+        res.err()
+            .expect("should not be call this function from the host")
+            .service_specific_error(),
+        HalErrorCode::UNAUTHORIZED,
+        "wrong error type received"
+    );
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+    let derived_policy = DerivedKeyPolicy::OpaqueKey(Vec::new());
+    let derived_parameters = DerivedKeyParameters {
+        derivationKey: Some(key),
+        keyPolicy: derived_policy,
+        context: Vec::new(),
+    };
+    let res = hw_crypto_key.deriveKey(&derived_parameters);
+    assert_eq!(
+        res.err()
+            .expect("should not be call this function from the host")
+            .service_specific_error(),
+        HalErrorCode::UNAUTHORIZED,
+        "wrong error type received"
+    );
+}
+
+rdroidtest::test_main!();
diff --git a/security/see/hwcrypto/aidl/vts/functional/lib.rs b/security/see/hwcrypto/aidl/vts/functional/lib.rs
index 81ae3fa..43676f6 100644
--- a/security/see/hwcrypto/aidl/vts/functional/lib.rs
+++ b/security/see/hwcrypto/aidl/vts/functional/lib.rs
@@ -17,62 +17,27 @@
 //! VTS test library for HwCrypto functionality.
 //! It provides the base clases necessaries to write HwCrypto VTS tests
 
-#[cfg(target_arch = "x86_64")]
-use anyhow::Context;
 use anyhow::Result;
-#[cfg(target_arch = "x86_64")]
-use binder::{ExceptionCode, FromIBinder, IntoBinderResult, ParcelFileDescriptor};
-#[cfg(target_arch = "x86_64")]
-use rpcbinder::RpcSession;
-#[cfg(target_arch = "x86_64")]
-use vsock::VsockStream;
-#[cfg(target_arch = "x86_64")]
-use std::os::fd::{FromRawFd, IntoRawFd};
-#[cfg(target_arch = "x86_64")]
-use std::fs::File;
-#[cfg(target_arch = "x86_64")]
-use std::io::Read;
-#[cfg(target_arch = "x86_64")]
-use rustutils::system_properties;
-#[cfg(target_arch = "aarch64")]
-use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::IHwCryptoKey::BpHwCryptoKey;
 use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::IHwCryptoKey::IHwCryptoKey;
 
-#[cfg(target_arch = "x86_64")]
-const HWCRYPTO_SERVICE_PORT: u32 = 4;
-
-/// Local function to connect to service
-#[cfg(target_arch = "x86_64")]
-pub fn connect_service<T: FromIBinder + ?Sized>(
-    cid: u32,
-    port: u32,
-) -> Result<binder::Strong<T>, binder::StatusCode> {
-    RpcSession::new().setup_preconnected_client(|| {
-        let mut stream = VsockStream::connect_with_cid_port(cid, port).ok()?;
-        let mut buffer = [0];
-        let _ = stream.read(&mut buffer);
-        // SAFETY: ownership is transferred from stream to f
-        let f = unsafe { File::from_raw_fd(stream.into_raw_fd()) };
-        Some(ParcelFileDescriptor::new(f).into_raw_fd())
-    })
-}
-
-/// Get a HwCryptoKey binder service object using a direct vsock connection
-#[cfg(target_arch = "x86_64")]
-pub fn get_hwcryptokey() -> Result<binder::Strong<dyn IHwCryptoKey>, binder::Status> {
-    let cid = system_properties::read("trusty.test_vm.vm_cid")
-        .context("couldn't get vm cid")
-        .or_binder_exception(ExceptionCode::ILLEGAL_STATE)?
-        .ok_or(ExceptionCode::ILLEGAL_STATE)?
-        .parse::<u32>()
-        .context("couldn't parse vm cid")
-        .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT)?;
-    Ok(connect_service(cid, HWCRYPTO_SERVICE_PORT)?)
-}
+pub const HWCRYPTO_SERVICE: &str = "android.hardware.security.see.hwcrypto.IHwCryptoKey";
 
 /// Get a HwCryptoKey binder service object using the service manager
-#[cfg(target_arch = "aarch64")]
 pub fn get_hwcryptokey() -> Result<binder::Strong<dyn IHwCryptoKey>, binder::Status> {
-    let interface_name = <BpHwCryptoKey as IHwCryptoKey>::get_descriptor().to_owned() + "/default";
+    let interface_name = HWCRYPTO_SERVICE.to_owned() + "/default";
     Ok(binder::get_interface(&interface_name)?)
 }
+
+pub fn get_supported_instances() -> Vec<(String, String)> {
+    // Determine which instances are available.
+    binder::get_declared_instances(HWCRYPTO_SERVICE)
+        .unwrap_or_default()
+        .into_iter()
+        .map(|v| (v.clone(), v))
+        .collect()
+}
+
+pub fn ignore_test() -> bool {
+    let instances = get_supported_instances();
+    instances.len() == 0
+}
diff --git a/security/see/hwcrypto/default/Android.bp b/security/see/hwcrypto/default/Android.bp
index ab23cfd..7a4a7b6 100644
--- a/security/see/hwcrypto/default/Android.bp
+++ b/security/see/hwcrypto/default/Android.bp
@@ -112,6 +112,7 @@
 cc_test {
     name: "HwCryptoHalDelegatorTests",
     enabled: false,
+    require_root: true,
     srcs: [
         "delegatorTest.cpp",
     ],
@@ -124,12 +125,14 @@
     shared_libs: [
         "libbase",
         "liblog",
+        "libutils",
         "libbinder",
         "libbinder_ndk",
     ],
     static_libs: [
         "android.hardware.security.see.hwcrypto-V1-ndk",
         "android.hardware.security.see.hwcrypto-V1-cpp",
+        "hwcryptohallib",
     ],
 
     arch: {
diff --git a/security/see/hwcrypto/default/delegatorTest.cpp b/security/see/hwcrypto/default/delegatorTest.cpp
index a80d6fd..28b177d 100644
--- a/security/see/hwcrypto/default/delegatorTest.cpp
+++ b/security/see/hwcrypto/default/delegatorTest.cpp
@@ -1,11 +1,84 @@
+#include <android/binder_manager.h>
 #include <gtest/gtest.h>
+#include <linux/dma-heap.h>
+#include <sys/auxv.h>
+#include <sys/mman.h>
 #include "hwcryptokeyimpl.h"
 
+static inline bool align_overflow(size_t size, size_t alignment, size_t* aligned) {
+    if (size % alignment == 0) {
+        *aligned = size;
+        return false;
+    }
+    size_t temp = 0;
+    bool overflow = __builtin_add_overflow(size / alignment, 1, &temp);
+    overflow |= __builtin_mul_overflow(temp, alignment, aligned);
+    return overflow;
+}
+
+static int allocate_buffers(size_t size) {
+    const char* device_name = "/dev/dma_heap/system";
+    int dma_heap_fd = open(device_name, O_RDONLY | O_CLOEXEC);
+    if (dma_heap_fd < 0) {
+        LOG(ERROR) << "Cannot open " << device_name;
+        return -1;
+    }
+    size_t aligned = 0;
+    if (align_overflow(size, getauxval(AT_PAGESZ), &aligned)) {
+        LOG(ERROR) << "Rounding up buffer size oveflowed";
+        return -1;
+    }
+    struct dma_heap_allocation_data allocation_request = {
+            .len = aligned,
+            .fd_flags = O_RDWR | O_CLOEXEC,
+    };
+    int rc = ioctl(dma_heap_fd, DMA_HEAP_IOCTL_ALLOC, &allocation_request);
+    if (rc < 0) {
+        LOG(ERROR) << "Buffer allocation request failed  " << rc;
+        return -1;
+    }
+    int fd = allocation_request.fd;
+    if (fd < 0) {
+        LOG(ERROR) << "Allocation request returned bad fd" << fd;
+        return -1;
+    }
+    return fd;
+}
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     return RUN_ALL_TESTS();
 }
 
+TEST(HwCryptoHalDelegator, FdTest) {
+    const std::string instance =
+            std::string() + ndk_hwcrypto::IHwCryptoKey::descriptor + "/default";
+    ndk::SpAIBinder binder(AServiceManager_waitForService(instance.c_str()));
+    ASSERT_NE(binder, nullptr);
+    auto hwCryptoKey = ndk_hwcrypto::IHwCryptoKey::fromBinder(binder);
+    ASSERT_NE(hwCryptoKey, nullptr);
+    auto fd = allocate_buffers(4096);
+    EXPECT_GE(fd, 0);
+    ndk::ScopedFileDescriptor ndkFd(fd);
+    ndk_hwcrypto::MemoryBufferParameter memBuffParam = ndk_hwcrypto::MemoryBufferParameter();
+    memBuffParam.bufferHandle.set<ndk_hwcrypto::MemoryBufferParameter::MemoryBuffer::input>(
+            std::move(ndkFd));
+    memBuffParam.sizeBytes = 4096;
+    auto operation = ndk_hwcrypto::CryptoOperation();
+    operation.set<ndk_hwcrypto::CryptoOperation::setMemoryBuffer>(std::move(memBuffParam));
+    ndk_hwcrypto::CryptoOperationSet operationSet = ndk_hwcrypto::CryptoOperationSet();
+    operationSet.context = nullptr;
+    operationSet.operations.push_back(std::move(operation));
+    std::vector<ndk_hwcrypto::CryptoOperationSet> operationSets;
+    operationSets.push_back(std::move(operationSet));
+    std::vector<ndk_hwcrypto::CryptoOperationResult> aidl_return;
+    std::shared_ptr<ndk_hwcrypto::IHwCryptoOperations> hwCryptoOperations;
+    auto res = hwCryptoKey->getHwCryptoOperations(&hwCryptoOperations);
+    EXPECT_TRUE(res.isOk());
+    res = hwCryptoOperations->processCommandList(&operationSets, &aidl_return);
+    EXPECT_TRUE(res.isOk());
+}
+
 TEST(HwCryptoHalDelegator, keyPolicyCppToNdk) {
     cpp_hwcrypto::KeyPolicy cppPolicy = cpp_hwcrypto::KeyPolicy();
     cppPolicy.keyType = cpp_hwcrypto::types::KeyType::AES_128_CBC_PKCS7_PADDING;
@@ -46,4 +119,4 @@
               cpp_hwcrypto::types::KeyPermissions::ALLOW_EPHEMERAL_KEY_WRAPPING);
     EXPECT_EQ(cppPolicy.keyPermissions[1],
               cpp_hwcrypto::types::KeyPermissions::ALLOW_HARDWARE_KEY_WRAPPING);
-}
\ No newline at end of file
+}
diff --git a/security/see/hwcrypto/default/hwcryptokeyimpl.h b/security/see/hwcrypto/default/hwcryptokeyimpl.h
index 19be8b4..7d3ade7 100644
--- a/security/see/hwcrypto/default/hwcryptokeyimpl.h
+++ b/security/see/hwcrypto/default/hwcryptokeyimpl.h
@@ -46,30 +46,33 @@
 
     ndk::ScopedAStatus deriveCurrentDicePolicyBoundKey(
             const ndk_hwcrypto::IHwCryptoKey::DiceBoundDerivationKey& derivationKey,
-            ndk_hwcrypto::IHwCryptoKey::DiceCurrentBoundKeyResult* aidl_return);
+            ndk_hwcrypto::IHwCryptoKey::DiceCurrentBoundKeyResult* aidl_return) override;
 
     ndk::ScopedAStatus deriveDicePolicyBoundKey(
             const ndk_hwcrypto::IHwCryptoKey::DiceBoundDerivationKey& derivationKey,
             const ::std::vector<uint8_t>& dicePolicyForKeyVersion,
-            ndk_hwcrypto::IHwCryptoKey::DiceBoundKeyResult* aidl_return);
+            ndk_hwcrypto::IHwCryptoKey::DiceBoundKeyResult* aidl_return) override;
     ndk::ScopedAStatus deriveKey(const ndk_hwcrypto::IHwCryptoKey::DerivedKeyParameters& parameters,
-                                 ndk_hwcrypto::IHwCryptoKey::DerivedKey* aidl_return);
+                                 ndk_hwcrypto::IHwCryptoKey::DerivedKey* aidl_return) override;
 
     ndk::ScopedAStatus getHwCryptoOperations(
-            std::shared_ptr<ndk_hwcrypto::IHwCryptoOperations>* aidl_return);
+            std::shared_ptr<ndk_hwcrypto::IHwCryptoOperations>* aidl_return) override;
 
-    ndk::ScopedAStatus importClearKey(const ndk_hwcrypto::types::ExplicitKeyMaterial& keyMaterial,
-                                      const ndk_hwcrypto::KeyPolicy& newKeyPolicy,
-                                      std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return);
+    ndk::ScopedAStatus importClearKey(
+            const ndk_hwcrypto::types::ExplicitKeyMaterial& keyMaterial,
+            const ndk_hwcrypto::KeyPolicy& newKeyPolicy,
+            std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return) override;
 
-    ndk::ScopedAStatus getCurrentDicePolicy(std::vector<uint8_t>* aidl_return);
+    ndk::ScopedAStatus getCurrentDicePolicy(std::vector<uint8_t>* aidl_return) override;
 
-    ndk::ScopedAStatus keyTokenImport(const ndk_hwcrypto::types::OpaqueKeyToken& requestedKey,
-                                      const ::std::vector<uint8_t>& sealingDicePolicy,
-                                      std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return);
+    ndk::ScopedAStatus keyTokenImport(
+            const ndk_hwcrypto::types::OpaqueKeyToken& requestedKey,
+            const ::std::vector<uint8_t>& sealingDicePolicy,
+            std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return) override;
 
-    ndk::ScopedAStatus getKeyslotData(ndk_hwcrypto::IHwCryptoKey::KeySlot slotId,
-                                      std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return);
+    ndk::ScopedAStatus getKeyslotData(
+            ndk_hwcrypto::IHwCryptoKey::KeySlot slotId,
+            std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return) override;
 };
 
 template <typename LHP, typename RHP>
@@ -79,9 +82,10 @@
     policy.keyLifetime = static_cast<decltype(policy.keyLifetime)>(policyToConvert.keyLifetime);
     policy.keyType = static_cast<decltype(policy.keyType)>(policyToConvert.keyType);
     policy.keyManagementKey = policyToConvert.keyManagementKey;
+    policy.keyPermissions.reserve(policyToConvert.keyPermissions.size());
     for (auto permission : policyToConvert.keyPermissions) {
         policy.keyPermissions.push_back(
-                std::move(reinterpret_cast<decltype(policy.keyPermissions[0])>(permission)));
+                std::move(static_cast<decltype(policy.keyPermissions)::value_type>(permission)));
     }
     return policy;
 }
diff --git a/security/see/hwcrypto/default/hwcryptolib.cpp b/security/see/hwcrypto/default/hwcryptolib.cpp
index 0e15883..a7ecca1 100644
--- a/security/see/hwcrypto/default/hwcryptolib.cpp
+++ b/security/see/hwcrypto/default/hwcryptolib.cpp
@@ -115,11 +115,14 @@
 class HwCryptoOperationContextNdk : public ndk_hwcrypto::BnCryptoOperationContext {
   private:
     sp<cpp_hwcrypto::ICryptoOperationContext> mContext;
+    std::weak_ptr<ndk_hwcrypto::ICryptoOperationContext> self;
 
   public:
     HwCryptoOperationContextNdk(sp<cpp_hwcrypto::ICryptoOperationContext> operations)
         : mContext(std::move(operations)) {}
 
+    ~HwCryptoOperationContextNdk() { contextMapping.erase(self); }
+
     static std::shared_ptr<HwCryptoOperationContextNdk> Create(
             sp<cpp_hwcrypto::ICryptoOperationContext> operations) {
         if (operations == nullptr) {
@@ -132,18 +135,18 @@
             LOG(ERROR) << "failed to allocate HwCryptoOperationContext";
             return nullptr;
         }
+        contextNdk->self = contextNdk;
         return contextNdk;
     }
 };
 
-// TODO: Check refactoring opportunities like returning a Result<cpp_hwcrypto::types::OperationData>
-//       once we add the code that uses this function.
-Result<void> setOperationData(const ndk_hwcrypto::types::OperationData& ndkOperationData,
-                              cpp_hwcrypto::types::OperationData* cppOperationData) {
+std::optional<cpp_hwcrypto::types::OperationData> convertOperationData(
+        const ndk_hwcrypto::types::OperationData& ndkOperationData) {
+    cpp_hwcrypto::types::OperationData cppOperationData = cpp_hwcrypto::types::OperationData();
     cpp_hwcrypto::types::MemoryBufferReference cppMemBuffRef;
     switch (ndkOperationData.getTag()) {
         case ndk_hwcrypto::types::OperationData::dataBuffer:
-            cppOperationData->set<cpp_hwcrypto::types::OperationData::dataBuffer>(
+            cppOperationData.set<cpp_hwcrypto::types::OperationData::dataBuffer>(
                     ndkOperationData.get<ndk_hwcrypto::types::OperationData::dataBuffer>());
             break;
         case ndk_hwcrypto::types::OperationData::memoryBufferReference:
@@ -155,14 +158,253 @@
                     ndkOperationData
                             .get<ndk_hwcrypto::types::OperationData::memoryBufferReference>()
                             .sizeBytes;
-            cppOperationData->set<cpp_hwcrypto::types::OperationData::memoryBufferReference>(
+            cppOperationData.set<cpp_hwcrypto::types::OperationData::memoryBufferReference>(
                     std::move(cppMemBuffRef));
             break;
         default:
-            // This shouldn't happen with the current definitions
-            return ErrnoError() << "received unknown operation data type";
+            LOG(ERROR) << "received unknown operation data type";
+            return std::nullopt;
     }
-    return {};
+    return cppOperationData;
+}
+
+std::optional<cpp_hwcrypto::PatternParameters> convertPatternParameters(
+        const ndk_hwcrypto::PatternParameters& ndkpatternParameters) {
+    int64_t numberBlocksProcess = ndkpatternParameters.numberBlocksProcess;
+    int64_t numberBlocksCopy = ndkpatternParameters.numberBlocksCopy;
+    if ((numberBlocksProcess < 0) || (numberBlocksCopy < 0)) {
+        LOG(ERROR) << "received invalid pattern parameters";
+        return std::nullopt;
+    }
+    cpp_hwcrypto::PatternParameters patternParameters = cpp_hwcrypto::PatternParameters();
+    patternParameters.numberBlocksProcess = numberBlocksProcess;
+    patternParameters.numberBlocksCopy = numberBlocksCopy;
+    return patternParameters;
+}
+
+std::optional<cpp_hwcrypto::types::SymmetricOperation> convertSymmetricOperation(
+        const ndk_hwcrypto::types::SymmetricOperation& ndkSymmetricOperation) {
+    cpp_hwcrypto::types::SymmetricOperation symmetricOperation =
+            cpp_hwcrypto::types::SymmetricOperation();
+    switch (ndkSymmetricOperation) {
+        case ndk_hwcrypto::types::SymmetricOperation::ENCRYPT:
+            symmetricOperation = cpp_hwcrypto::types::SymmetricOperation::ENCRYPT;
+            break;
+        case ndk_hwcrypto::types::SymmetricOperation::DECRYPT:
+            symmetricOperation = cpp_hwcrypto::types::SymmetricOperation::DECRYPT;
+            break;
+        default:
+            LOG(ERROR) << "invalid symmetric operation type";
+            return std::nullopt;
+    }
+    return symmetricOperation;
+}
+
+cpp_hwcrypto::types::CipherModeParameters convertSymmetricModeParameters(
+        const ndk_hwcrypto::types::CipherModeParameters& ndkcipherModeParameters) {
+    cpp_hwcrypto::types::CipherModeParameters cipherModeParameters =
+            cpp_hwcrypto::types::CipherModeParameters();
+    cipherModeParameters.nonce = ndkcipherModeParameters.nonce;
+    return cipherModeParameters;
+}
+
+cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters convertSymmetricModeParameters(
+        const ndk_hwcrypto::types::AesGcmMode::AesGcmModeParameters& ndkgcmModeParameters) {
+    cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters gcmModeParameters =
+            cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters();
+    gcmModeParameters.nonce = ndkgcmModeParameters.nonce;
+    return gcmModeParameters;
+}
+
+std::optional<cpp_hwcrypto::MemoryBufferParameter> convertMemoryBufferParameters(
+        const ndk_hwcrypto::MemoryBufferParameter& ndkMemBuffParams) {
+    cpp_hwcrypto::MemoryBufferParameter memBuffParams = cpp_hwcrypto::MemoryBufferParameter();
+    memBuffParams.sizeBytes = ndkMemBuffParams.sizeBytes;
+    android::os::ParcelFileDescriptor pfd;
+    ndk::ScopedFileDescriptor ndkFd;
+    switch (ndkMemBuffParams.bufferHandle.getTag()) {
+        case ndk_hwcrypto::MemoryBufferParameter::MemoryBuffer::input:
+            ndkFd = ndkMemBuffParams.bufferHandle
+                            .get<ndk_hwcrypto::MemoryBufferParameter::MemoryBuffer::input>()
+                            .dup();
+            pfd.reset(binder::unique_fd(ndkFd.release()));
+            memBuffParams.bufferHandle
+                    .set<cpp_hwcrypto::MemoryBufferParameter::MemoryBuffer::input>(std::move(pfd));
+            break;
+        case ndk_hwcrypto::MemoryBufferParameter::MemoryBuffer::output:
+            ndkFd = ndkMemBuffParams.bufferHandle
+                            .get<ndk_hwcrypto::MemoryBufferParameter::MemoryBuffer::output>()
+                            .dup();
+            pfd.reset(binder::unique_fd(ndkFd.release()));
+            memBuffParams.bufferHandle
+                    .set<cpp_hwcrypto::MemoryBufferParameter::MemoryBuffer::output>(std::move(pfd));
+            break;
+        default:
+            LOG(ERROR) << "unknown bufferHandle type";
+            return std::nullopt;
+    }
+    return memBuffParams;
+}
+
+std::optional<cpp_hwcrypto::OperationParameters> convertOperationParameters(
+        const ndk_hwcrypto::OperationParameters& ndkOperationParameters) {
+    cpp_hwcrypto::OperationParameters operationParameters = cpp_hwcrypto::OperationParameters();
+    sp<cpp_hwcrypto::IOpaqueKey> opaqueKey;
+    cpp_hwcrypto::types::HmacOperationParameters hmacParameters =
+            cpp_hwcrypto::types::HmacOperationParameters();
+    std::optional<cpp_hwcrypto::types::SymmetricOperation> cppSymmetricOperation;
+    cpp_hwcrypto::types::CipherModeParameters cipherModeParameters;
+    cpp_hwcrypto::types::AesCipherMode cppAesCipherMode = cpp_hwcrypto::types::AesCipherMode();
+    cpp_hwcrypto::types::SymmetricOperationParameters cppSymmetricOperationParameters =
+            cpp_hwcrypto::types::SymmetricOperationParameters();
+    cpp_hwcrypto::types::SymmetricAuthOperationParameters cppSymmetricAuthOperationParameters =
+            cpp_hwcrypto::types::SymmetricAuthOperationParameters();
+    cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters cppAesGcmModeParameters =
+            cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters();
+    cpp_hwcrypto::types::AesGcmMode cppAesGcmMode = cpp_hwcrypto::types::AesGcmMode();
+    switch (ndkOperationParameters.getTag()) {
+        case ndk_hwcrypto::OperationParameters::symmetricAuthCrypto:
+            opaqueKey = retrieveCppBinder<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey,
+                                          keyMapping>(
+                    ndkOperationParameters
+                            .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>()
+                            .key);
+            if (!opaqueKey) {
+                LOG(ERROR) << "couldn't get aes key";
+                return std::nullopt;
+            }
+            cppSymmetricAuthOperationParameters.key = std::move(opaqueKey);
+            cppSymmetricOperation = convertSymmetricOperation(
+                    ndkOperationParameters
+                            .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>()
+                            .direction);
+            if (!cppSymmetricOperation.has_value()) {
+                LOG(ERROR) << "couldn't get aes direction";
+                return std::nullopt;
+            }
+            cppSymmetricAuthOperationParameters.direction =
+                    std::move(cppSymmetricOperation.value());
+            switch (ndkOperationParameters
+                            .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>()
+                            .parameters.getTag()) {
+                case ndk_hwcrypto::types::SymmetricAuthCryptoParameters::aes:
+                    switch (ndkOperationParameters
+                                    .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>()
+                                    .parameters
+                                    .get<ndk_hwcrypto::types::SymmetricAuthCryptoParameters::aes>()
+                                    .getTag()) {
+                        case ndk_hwcrypto::types::AesGcmMode::gcmTag16:
+                            cppAesGcmModeParameters = convertSymmetricModeParameters(
+                                    ndkOperationParameters
+                                            .get<ndk_hwcrypto::OperationParameters::
+                                                         symmetricAuthCrypto>()
+                                            .parameters
+                                            .get<ndk_hwcrypto::types::
+                                                         SymmetricAuthCryptoParameters::aes>()
+                                            .get<ndk_hwcrypto::types::AesGcmMode::gcmTag16>());
+                            cppAesGcmMode.set<cpp_hwcrypto::types::AesGcmMode::gcmTag16>(
+                                    std::move(cppAesGcmModeParameters));
+                            cppSymmetricAuthOperationParameters.parameters
+                                    .set<cpp_hwcrypto::types::SymmetricAuthCryptoParameters::aes>(
+                                            std::move(cppAesGcmMode));
+                            break;
+                        default:
+                            LOG(ERROR) << "received invalid aes gcm parameters";
+                            return std::nullopt;
+                    }
+                    break;
+                default:
+                    LOG(ERROR) << "received invalid symmetric auth crypto parameters";
+                    return std::nullopt;
+            }
+            operationParameters.set<cpp_hwcrypto::OperationParameters::symmetricAuthCrypto>(
+                    std::move(cppSymmetricAuthOperationParameters));
+            break;
+        case ndk_hwcrypto::OperationParameters::symmetricCrypto:
+            opaqueKey = retrieveCppBinder<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey,
+                                          keyMapping>(
+                    ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::symmetricCrypto>()
+                            .key);
+            if (!opaqueKey) {
+                LOG(ERROR) << "couldn't get aes key";
+                return std::nullopt;
+            }
+            cppSymmetricOperationParameters.key = std::move(opaqueKey);
+            cppSymmetricOperation = convertSymmetricOperation(
+                    ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::symmetricCrypto>()
+                            .direction);
+            if (!cppSymmetricOperation.has_value()) {
+                LOG(ERROR) << "couldn't get aes direction";
+                return std::nullopt;
+            }
+            cppSymmetricOperationParameters.direction = std::move(cppSymmetricOperation.value());
+            switch (ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::symmetricCrypto>()
+                            .parameters.getTag()) {
+                case ndk_hwcrypto::types::SymmetricCryptoParameters::aes:
+                    switch (ndkOperationParameters
+                                    .get<ndk_hwcrypto::OperationParameters::symmetricCrypto>()
+                                    .parameters
+                                    .get<ndk_hwcrypto::types::SymmetricCryptoParameters::aes>()
+                                    .getTag()) {
+                        case ndk_hwcrypto::types::AesCipherMode::cbc:
+                            cipherModeParameters = convertSymmetricModeParameters(
+                                    ndkOperationParameters
+                                            .get<ndk_hwcrypto::OperationParameters::
+                                                         symmetricCrypto>()
+                                            .parameters
+                                            .get<ndk_hwcrypto::types::SymmetricCryptoParameters::
+                                                         aes>()
+                                            .get<ndk_hwcrypto::types::AesCipherMode::cbc>());
+                            cppAesCipherMode.set<cpp_hwcrypto::types::AesCipherMode::cbc>(
+                                    std::move(cipherModeParameters));
+                            cppSymmetricOperationParameters.parameters
+                                    .set<cpp_hwcrypto::types::SymmetricCryptoParameters::aes>(
+                                            std::move(cppAesCipherMode));
+                            break;
+                        case ndk_hwcrypto::types::AesCipherMode::ctr:
+                            cipherModeParameters = convertSymmetricModeParameters(
+                                    ndkOperationParameters
+                                            .get<ndk_hwcrypto::OperationParameters::
+                                                         symmetricCrypto>()
+                                            .parameters
+                                            .get<ndk_hwcrypto::types::SymmetricCryptoParameters::
+                                                         aes>()
+                                            .get<ndk_hwcrypto::types::AesCipherMode::ctr>());
+                            cppAesCipherMode.set<cpp_hwcrypto::types::AesCipherMode::ctr>(
+                                    std::move(cipherModeParameters));
+                            cppSymmetricOperationParameters.parameters
+                                    .set<cpp_hwcrypto::types::SymmetricCryptoParameters::aes>(
+                                            std::move(cppAesCipherMode));
+                            break;
+                        default:
+                            LOG(ERROR) << "received invalid aes parameters";
+                            return std::nullopt;
+                    }
+                    break;
+                default:
+                    LOG(ERROR) << "received invalid symmetric crypto parameters";
+                    return std::nullopt;
+            }
+            operationParameters.set<cpp_hwcrypto::OperationParameters::symmetricCrypto>(
+                    std::move(cppSymmetricOperationParameters));
+            break;
+        case ndk_hwcrypto::OperationParameters::hmac:
+            opaqueKey = retrieveCppBinder<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey,
+                                          keyMapping>(
+                    ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::hmac>().key);
+            if (!opaqueKey) {
+                LOG(ERROR) << "couldn't get hmac key";
+                return std::nullopt;
+            }
+            hmacParameters.key = opaqueKey;
+            operationParameters.set<cpp_hwcrypto::OperationParameters::hmac>(
+                    std::move(hmacParameters));
+            break;
+        default:
+            LOG(ERROR) << "received invalid operation parameters";
+            return std::nullopt;
+    }
+    return operationParameters;
 }
 
 class HwCryptoOperationsNdk : public ndk_hwcrypto::BnHwCryptoOperations {
@@ -189,19 +431,215 @@
     }
 
     ndk::ScopedAStatus processCommandList(
-            std::vector<ndk_hwcrypto::CryptoOperationSet>* /*operationSets*/,
-            std::vector<ndk_hwcrypto::CryptoOperationResult>* /*aidl_return*/) {
-        return ndk::ScopedAStatus::ok();
+            std::vector<ndk_hwcrypto::CryptoOperationSet>* operationSets,
+            std::vector<ndk_hwcrypto::CryptoOperationResult>* aidl_return) {
+        Status status = Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+        if (operationSets == nullptr) {
+            LOG(ERROR) << "received a null operation set";
+            return convertStatus(status);
+        }
+        if (aidl_return == nullptr) {
+            LOG(ERROR) << "received a null CryptoOperationResult set";
+            return convertStatus(status);
+        }
+        std::vector<cpp_hwcrypto::CryptoOperationResult> binderResult;
+        std::vector<cpp_hwcrypto::CryptoOperationSet> cppOperationSets;
+        for (ndk_hwcrypto::CryptoOperationSet& operationSet : *operationSets) {
+            cpp_hwcrypto::CryptoOperationSet cppSingleOperation =
+                    cpp_hwcrypto::CryptoOperationSet();
+            cppSingleOperation.context =
+                    retrieveCppBinder<cpp_hwcrypto::ICryptoOperationContext,
+                                      ndk_hwcrypto::ICryptoOperationContext, contextMapping>(
+                            operationSet.context);
+            for (ndk_hwcrypto::CryptoOperation& operation : operationSet.operations) {
+                cpp_hwcrypto::CryptoOperation cppOperation;
+                cpp_hwcrypto::types::Void voidObj;
+                std::optional<cpp_hwcrypto::types::OperationData> cppOperationData;
+                std::optional<cpp_hwcrypto::PatternParameters> cppPatternParameters;
+                std::optional<cpp_hwcrypto::OperationParameters> cppOperationParameters;
+                std::optional<cpp_hwcrypto::MemoryBufferParameter> cppMemBuffParams;
+                switch (operation.getTag()) {
+                    case ndk_hwcrypto::CryptoOperation::setMemoryBuffer:
+                        cppMemBuffParams = convertMemoryBufferParameters(
+                                operation.get<ndk_hwcrypto::CryptoOperation::setMemoryBuffer>());
+                        if (cppMemBuffParams.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::setMemoryBuffer>(
+                                    std::move(cppMemBuffParams.value()));
+                        } else {
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::setOperationParameters:
+                        cppOperationParameters = convertOperationParameters(
+                                operation.get<
+                                        ndk_hwcrypto::CryptoOperation::setOperationParameters>());
+                        if (cppOperationParameters.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::setOperationParameters>(
+                                    std::move(cppOperationParameters.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert operation parameters";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::setPattern:
+                        cppPatternParameters = convertPatternParameters(
+                                operation.get<ndk_hwcrypto::CryptoOperation::setPattern>());
+                        if (cppPatternParameters.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::setPattern>(
+                                    std::move(cppPatternParameters.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert pattern parameters";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::copyData:
+                        cppOperationData = convertOperationData(
+                                operation.get<ndk_hwcrypto::CryptoOperation::copyData>());
+                        if (cppOperationData.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::copyData>(
+                                    std::move(cppOperationData.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert CryptoOperation::copyData";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::aadInput:
+                        cppOperationData = convertOperationData(
+                                operation.get<ndk_hwcrypto::CryptoOperation::aadInput>());
+                        if (cppOperationData.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::aadInput>(
+                                    std::move(cppOperationData.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert CryptoOperation::aadInput";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::dataInput:
+                        cppOperationData = convertOperationData(
+                                operation.get<ndk_hwcrypto::CryptoOperation::dataInput>());
+                        if (cppOperationData.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::dataInput>(
+                                    std::move(cppOperationData.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert CryptoOperation::dataInput";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::dataOutput:
+                        cppOperationData = convertOperationData(
+                                operation.get<ndk_hwcrypto::CryptoOperation::dataOutput>());
+                        if (cppOperationData.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::dataOutput>(
+                                    std::move(cppOperationData.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert CryptoOperation::dataOutput";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::destroyContext:
+                        cppOperation.set<cpp_hwcrypto::CryptoOperation::destroyContext>(
+                                std::move(voidObj));
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::finish:
+                        cppOperation.set<cpp_hwcrypto::CryptoOperation::finish>(std::move(voidObj));
+                        break;
+                    default:
+                        // This shouldn't happen
+                        LOG(ERROR) << "received unknown crypto operation";
+                        return convertStatus(status);
+                }
+                cppSingleOperation.operations.push_back(std::move(cppOperation));
+            }
+            cppOperationSets.push_back(std::move(cppSingleOperation));
+        }
+        status = mHwCryptoOperations->processCommandList(&cppOperationSets, &binderResult);
+        if (status.isOk()) {
+            *aidl_return = std::vector<ndk_hwcrypto::CryptoOperationResult>();
+            for (cpp_hwcrypto::CryptoOperationResult& result : binderResult) {
+                ndk_hwcrypto::CryptoOperationResult ndkResult =
+                        ndk_hwcrypto::CryptoOperationResult();
+                if (result.context != nullptr) {
+                    insertBinderMapping<cpp_hwcrypto::ICryptoOperationContext,
+                                        ndk_hwcrypto::ICryptoOperationContext,
+                                        HwCryptoOperationContextNdk, contextMapping>(
+                            result.context, &ndkResult.context);
+                } else {
+                    ndkResult.context = nullptr;
+                }
+                aidl_return->push_back(std::move(ndkResult));
+            }
+        } else {
+            // No reason to copy back the data output vectors if this failed
+            LOG(ERROR) << "couldn't process command list";
+            return convertStatus(status);
+        }
+        // We need to copy the vectors from the cpp operations back to the ndk one
+        if (cppOperationSets.size() != operationSets->size()) {
+            LOG(ERROR) << "ndk and cpp operation sets had a different number of elements";
+            return convertStatus(Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT));
+        }
+        for (unsigned setIdx = 0; setIdx < cppOperationSets.size(); ++setIdx) {
+            if (cppOperationSets[setIdx].operations.size() !=
+                (*operationSets)[setIdx].operations.size()) {
+                LOG(ERROR) << "ndk and cpp operations on set " << setIdx
+                           << " had a different number of elements";
+                return convertStatus(Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT));
+            }
+            for (unsigned operationIdx = 0;
+                 operationIdx < cppOperationSets[setIdx].operations.size(); ++operationIdx) {
+                if (cppOperationSets[setIdx].operations[operationIdx].getTag() ==
+                    cpp_hwcrypto::CryptoOperation::dataOutput) {
+                    if ((*operationSets)[setIdx].operations[operationIdx].getTag() !=
+                        ndk_hwcrypto::CryptoOperation::dataOutput) {
+                        LOG(ERROR)
+                                << "ndk and cpp operations on set " << setIdx << " and operation "
+                                << operationIdx << " had a different operation type";
+                        return convertStatus(
+                                Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT));
+                    }
+                    if (cppOperationSets[setIdx]
+                                .operations[operationIdx]
+                                .get<cpp_hwcrypto::CryptoOperation::dataOutput>()
+                                .getTag() == cpp_hwcrypto::types::OperationData::dataBuffer) {
+                        // This is the only case on which we need to move the data backto the
+                        // original array
+                        if ((*operationSets)[setIdx]
+                                    .operations[operationIdx]
+                                    .get<ndk_hwcrypto::CryptoOperation::dataOutput>()
+                                    .getTag() != ndk_hwcrypto::types::OperationData::dataBuffer) {
+                            LOG(ERROR) << "ndk and cpp operations on set " << setIdx
+                                       << " and operation " << operationIdx
+                                       << " had a different operation data output type";
+                            return convertStatus(
+                                    Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT));
+                        }
+                        (*operationSets)[setIdx]
+                                .operations[operationIdx]
+                                .get<ndk_hwcrypto::CryptoOperation::dataOutput>()
+                                .set<ndk_hwcrypto::types::OperationData::dataBuffer>(
+                                        cppOperationSets[setIdx]
+                                                .operations[operationIdx]
+                                                .get<cpp_hwcrypto::CryptoOperation::dataOutput>()
+                                                .get<cpp_hwcrypto::types::OperationData::
+                                                             dataBuffer>());
+                    }
+                }
+            }
+        }
+        return convertStatus(status);
     }
 };
 
 class OpaqueKeyNdk : public ndk_hwcrypto::BnOpaqueKey {
   private:
     sp<cpp_hwcrypto::IOpaqueKey> mOpaqueKey;
+    std::weak_ptr<ndk_hwcrypto::IOpaqueKey> self;
 
   public:
     OpaqueKeyNdk(sp<cpp_hwcrypto::IOpaqueKey> opaqueKey) : mOpaqueKey(std::move(opaqueKey)) {}
 
+    ~OpaqueKeyNdk() { keyMapping.erase(self); }
+
     static std::shared_ptr<OpaqueKeyNdk> Create(sp<cpp_hwcrypto::IOpaqueKey> opaqueKey) {
         if (opaqueKey == nullptr) {
             return nullptr;
@@ -213,6 +651,7 @@
             LOG(ERROR) << "failed to allocate HwCryptoKey";
             return nullptr;
         }
+        opaqueKeyNdk->self = opaqueKeyNdk;
         return opaqueKeyNdk;
     }
 
@@ -271,13 +710,19 @@
     ndk::ScopedAStatus setProtectionId(
             const ndk_hwcrypto::types::ProtectionId /*protectionId*/,
             const ::std::vector<ndk_hwcrypto::types::OperationType>& /*allowedOperations*/) {
-        return ndk::ScopedAStatus::ok();
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                ndk_hwcrypto::types::HalErrorCode::UNAUTHORIZED,
+                "android is not authorized to call setProtectionId");
     }
 };
 
 Result<void> HwCryptoKey::connectToTrusty(const char* tipcDev) {
     assert(!mSession);
-    mSession = RpcTrustyConnectWithSessionInitializer(tipcDev, HWCRYPTO_KEY_PORT, [](auto) {});
+    auto session_initializer = [](sp<RpcSession>& session) {
+        session->setFileDescriptorTransportMode(RpcSession::FileDescriptorTransportMode::TRUSTY);
+    };
+    mSession =
+            RpcTrustyConnectWithSessionInitializer(tipcDev, HWCRYPTO_KEY_PORT, session_initializer);
     if (!mSession) {
         return ErrnoError() << "failed to connect to hwcrypto";
     }
@@ -308,24 +753,26 @@
 ndk::ScopedAStatus HwCryptoKey::deriveCurrentDicePolicyBoundKey(
         const ndk_hwcrypto::IHwCryptoKey::DiceBoundDerivationKey& /*derivationKey*/,
         ndk_hwcrypto::IHwCryptoKey::DiceCurrentBoundKeyResult* /*aidl_return*/) {
-    // return mHwCryptoServer->deriveCurrentDicePolicyBoundKey(derivationKey, aidl_return);
-    return ndk::ScopedAStatus::ok();
+    return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            ndk_hwcrypto::types::HalErrorCode::UNAUTHORIZED,
+            "android is not authorized to call deriveCurrentDicePolicyBoundKey");
 }
 
 ndk::ScopedAStatus HwCryptoKey::deriveDicePolicyBoundKey(
         const ndk_hwcrypto::IHwCryptoKey::DiceBoundDerivationKey& /*derivationKey*/,
         const ::std::vector<uint8_t>& /*dicePolicyForKeyVersion*/,
         ndk_hwcrypto::IHwCryptoKey::DiceBoundKeyResult* /*aidl_return*/) {
-    // return mHwCryptoServer->deriveDicePolicyBoundKey(derivationKey, dicePolicyForKeyVersion,
-    // aidl_return);
-    return ndk::ScopedAStatus::ok();
+    return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            ndk_hwcrypto::types::HalErrorCode::UNAUTHORIZED,
+            "android is not authorized to call deriveDicePolicyBoundKey");
 }
 
 ndk::ScopedAStatus HwCryptoKey::deriveKey(
         const ndk_hwcrypto::IHwCryptoKey::DerivedKeyParameters& /*parameters*/,
         ndk_hwcrypto::IHwCryptoKey::DerivedKey* /*aidl_return*/) {
-    // return mHwCryptoServer->deriveKey(parameters, aidl_return);
-    return ndk::ScopedAStatus::ok();
+    return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            ndk_hwcrypto::types::HalErrorCode::UNAUTHORIZED,
+            "android is not authorized to call deriveKey");
 }
 
 ndk::ScopedAStatus HwCryptoKey::getHwCryptoOperations(
diff --git a/security/see/storage/default/Android.bp b/security/see/storage/default/Android.bp
new file mode 100644
index 0000000..7ea7739
--- /dev/null
+++ b/security/see/storage/default/Android.bp
@@ -0,0 +1,21 @@
+//
+// Copyright (C) 2025 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.
+
+prebuilt_etc {
+    name: "android.hardware.security.see.storage-service.trusty.xml",
+    sub_dir: "vintf",
+    vendor: true,
+    src: "android.hardware.security.see.storage-service.trusty.xml",
+}
diff --git a/security/see/storage/default/android.hardware.security.see.storage-service.trusty.xml b/security/see/storage/default/android.hardware.security.see.storage-service.trusty.xml
new file mode 100644
index 0000000..89f3839
--- /dev/null
+++ b/security/see/storage/default/android.hardware.security.see.storage-service.trusty.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl" exclusive-to="virtual-machine">
+        <name>android.hardware.security.see.storage</name>
+        <version>1</version>
+        <interface>
+            <name>ISecureStorage</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/sensors/aidl/multihal/android.hardware.sensors-service-multihal.rc b/sensors/aidl/multihal/android.hardware.sensors-service-multihal.rc
index 5aecc54..d1acd6f 100644
--- a/sensors/aidl/multihal/android.hardware.sensors-service-multihal.rc
+++ b/sensors/aidl/multihal/android.hardware.sensors-service-multihal.rc
@@ -1,3 +1,6 @@
+on boot
+    setprop vendor.sensors.dynamic_sensor_op_timeout_ms 1600
+
 service vendor.sensors-hal-multihal /vendor/bin/hw/android.hardware.sensors-service.multihal
     class hal
     user system