Merge "Add SubHal header for Sensors HAL 2.1" into rvc-dev
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 150d641..1519c48 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -455,20 +455,22 @@
     sp<IStreamOutCallback> callback = self->mCallback;
     if (callback.get() == nullptr) return 0;
     ALOGV("asyncCallback() event %d", event);
+    Return<void> result;
     switch (event) {
         case STREAM_CBK_EVENT_WRITE_READY:
-            callback->onWriteReady();
+            result = callback->onWriteReady();
             break;
         case STREAM_CBK_EVENT_DRAIN_READY:
-            callback->onDrainReady();
+            result = callback->onDrainReady();
             break;
         case STREAM_CBK_EVENT_ERROR:
-            callback->onError();
+            result = callback->onError();
             break;
         default:
             ALOGW("asyncCallback() unknown event %d", event);
             break;
     }
+    ALOGW_IF(!result.isOk(), "Client callback failed: %s", result.description().c_str());
     return 0;
 }
 
@@ -629,16 +631,18 @@
     sp<IStreamOutEventCallback> eventCallback = self->mEventCallback;
     if (eventCallback.get() == nullptr) return 0;
     ALOGV("%s event %d", __func__, event);
+    Return<void> result;
     switch (event) {
         case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED: {
             hidl_vec<uint8_t> audioMetadata;
             audioMetadata.setToExternal((uint8_t*)param, strlen((char*)param));
-            eventCallback->onCodecFormatChanged(audioMetadata);
+            result = eventCallback->onCodecFormatChanged(audioMetadata);
         } break;
         default:
             ALOGW("%s unknown event %d", __func__, event);
             break;
     }
+    ALOGW_IF(!result.isOk(), "Client callback failed: %s", result.description().c_str());
     return 0;
 }
 #endif
diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h
index a2f4116..8ef2b43 100644
--- a/audio/core/all-versions/vts/functional/ConfigHelper.h
+++ b/audio/core/all-versions/vts/functional/ConfigHelper.h
@@ -40,7 +40,7 @@
             return devs.getDevice(AUDIO_DEVICE_IN_BUILTIN_MIC, {}, AUDIO_FORMAT_DEFAULT);
         };
         auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices());
-        auto availableMic = getMic(policyConfig.getAvailableInputDevices());
+        auto availableMic = getMic(policyConfig.getInputDevices());
 
         return primaryMic != nullptr && primaryMic->equals(availableMic);
     }
diff --git a/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp
index f9e4aa3..9c0135b 100644
--- a/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp
+++ b/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp
@@ -18,6 +18,12 @@
 #include <iterator>
 
 #include <media/EffectsConfig.h>
+// clang-format off
+#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h)
+// clang-format on
+
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
 
 #include "utility/ValidateXml.h"
 
@@ -29,6 +35,11 @@
     RecordProperty("description",
                    "Verify that the effects configuration file is valid according to the schema");
     using namespace android::effectsConfig;
+    if (android::hardware::getAllHalInstanceNames(
+                ::android::hardware::audio::effect::CPP_VERSION::IEffectsFactory::descriptor)
+                .size() == 0) {
+        GTEST_SKIP() << "No Effects HAL version " STRINGIFY(CPP_VERSION) " on this device";
+    }
 
     std::vector<const char*> locations(std::begin(DEFAULT_LOCATIONS), std::end(DEFAULT_LOCATIONS));
     const char* xsd = "/data/local/tmp/audio_effects_conf_" STRINGIFY(CPP_VERSION) ".xsd";
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index 390d4ee..070242f 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -155,11 +155,20 @@
     0xfe3199be, 0xaed0, 0x413f, 0x87bb,
     std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}};
 
+enum { PARAM_FACTORY_NAME, PARAM_EFFECT_UUID };
+using EffectParameter = std::tuple<std::string, Uuid>;
+
+static inline std::string EffectParameterToString(
+        const ::testing::TestParamInfo<EffectParameter>& info) {
+    return ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo<std::string>{
+            std::get<PARAM_FACTORY_NAME>(info.param), info.index});
+}
+
 // The main test class for Audio Effect HIDL HAL.
-class AudioEffectHidlTest : public ::testing::TestWithParam<std::string> {
+class AudioEffectHidlTest : public ::testing::TestWithParam<EffectParameter> {
   public:
     void SetUp() override {
-        effectsFactory = IEffectsFactory::getService(GetParam());
+        effectsFactory = IEffectsFactory::getService(std::get<PARAM_FACTORY_NAME>(GetParam()));
         ASSERT_NE(nullptr, effectsFactory.get());
 
         findAndCreateEffect(getEffectType());
@@ -180,7 +189,7 @@
         RecordProperty("description", description);
     }
 
-    virtual Uuid getEffectType() { return EQUALIZER_EFFECT_TYPE; }
+    Uuid getEffectType() const { return std::get<PARAM_EFFECT_UUID>(GetParam()); }
 
     void findAndCreateEffect(const Uuid& type);
     void findEffectInstance(const Uuid& type, Uuid* uuid);
@@ -369,7 +378,9 @@
     description("Verify Disable -> Enable -> Disable sequence for an effect");
     Return<Result> ret = effect->disable();
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::INVALID_ARGUMENTS, ret);
+    // Note: some legacy effects may return -EINVAL (INVALID_ARGUMENTS),
+    //       more canonical is to return -ENOSYS (NOT_SUPPORTED)
+    EXPECT_TRUE(ret == Result::NOT_SUPPORTED || ret == Result::INVALID_ARGUMENTS);
     ret = effect->enable();
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
@@ -519,15 +530,19 @@
 
 // The main test class for Equalizer Audio Effect HIDL HAL.
 class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest {
-   public:
+  public:
     void SetUp() override {
         AudioEffectHidlTest::SetUp();
         equalizer = IEqualizerEffect::castFrom(effect);
         ASSERT_NE(nullptr, equalizer.get());
     }
 
-   protected:
-    Uuid getEffectType() override { return EQUALIZER_EFFECT_TYPE; }
+    void TearDown() override {
+        equalizer.clear();
+        AudioEffectHidlTest::TearDown();
+    }
+
+  protected:
     void getNumBands(uint16_t* numBands);
     void getLevelRange(int16_t* minLevel, int16_t* maxLevel);
     void getBandFrequencyRange(uint16_t band, uint32_t* minFreq, uint32_t* centerFreq,
@@ -765,16 +780,19 @@
 
 // The main test class for Equalizer Audio Effect HIDL HAL.
 class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest {
-   public:
+  public:
     void SetUp() override {
         AudioEffectHidlTest::SetUp();
         enhancer = ILoudnessEnhancerEffect::castFrom(effect);
         ASSERT_NE(nullptr, enhancer.get());
     }
 
-   protected:
-    Uuid getEffectType() override { return LOUDNESS_ENHANCER_EFFECT_TYPE; }
+    void TearDown() override {
+        enhancer.clear();
+        AudioEffectHidlTest::TearDown();
+    }
 
+  protected:
     sp<ILoudnessEnhancerEffect> enhancer;
 };
 
@@ -799,19 +817,31 @@
     EXPECT_EQ(gain, actualGain);
 }
 
+INSTANTIATE_TEST_SUITE_P(EffectsFactory, AudioEffectsFactoryHidlTest,
+                         ::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
+                                 IEffectsFactory::descriptor)),
+                         ::android::hardware::PrintInstanceNameToString);
 INSTANTIATE_TEST_SUITE_P(
-        EffectsFactory, AudioEffectsFactoryHidlTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
-        android::hardware::PrintInstanceNameToString);
+        Equalizer_IEffect, AudioEffectHidlTest,
+        ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
+                                   IEffectsFactory::descriptor)),
+                           ::testing::Values(EQUALIZER_EFFECT_TYPE)),
+        EffectParameterToString);
 INSTANTIATE_TEST_SUITE_P(
-        Equalizer, AudioEffectHidlTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
-        android::hardware::PrintInstanceNameToString);
+        LoudnessEnhancer_IEffect, AudioEffectHidlTest,
+        ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
+                                   IEffectsFactory::descriptor)),
+                           ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE)),
+        EffectParameterToString);
 INSTANTIATE_TEST_SUITE_P(
         Equalizer, EqualizerAudioEffectHidlTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
-        android::hardware::PrintInstanceNameToString);
+        ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
+                                   IEffectsFactory::descriptor)),
+                           ::testing::Values(EQUALIZER_EFFECT_TYPE)),
+        EffectParameterToString);
 INSTANTIATE_TEST_SUITE_P(
         LoudnessEnhancer, LoudnessEnhancerAudioEffectHidlTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
-        android::hardware::PrintInstanceNameToString);
+        ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
+                                   IEffectsFactory::descriptor)),
+                           ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE)),
+        EffectParameterToString);
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index cde8048..368a6d4 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -38,16 +38,15 @@
 
 #include <hidl/HidlTransportSupport.h>
 #include <hwbinder/ProcessState.h>
-#include <log/log.h>
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 
-#include <android/log.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
 #include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
 #include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android-base/logging.h>
 #include <system/camera_metadata.h>
 #include <ui/DisplayConfig.h>
 #include <ui/DisplayState.h>
@@ -98,18 +97,19 @@
         std::string service_name = GetParam();
         pEnumerator = IEvsEnumerator::getService(service_name);
         ASSERT_NE(pEnumerator.get(), nullptr);
+        LOG(INFO) << "Test target service: " << service_name;
 
         mIsHwModule = pEnumerator->isHardware();
     }
 
     virtual void TearDown() override {
         // Attempt to close any active camera
-        for (auto &&c : activeCameras) {
-            sp<IEvsCamera_1_1> cam = c.promote();
+        for (auto &&cam : activeCameras) {
             if (cam != nullptr) {
                 pEnumerator->closeCamera(cam);
             }
         }
+        activeCameras.clear();
     }
 
 protected:
@@ -120,11 +120,12 @@
         // Get the camera list
         pEnumerator->getCameraList_1_1(
             [this](hidl_vec <CameraDesc> cameraList) {
-                ALOGI("Camera list callback received %zu cameras",
-                      cameraList.size());
+                LOG(INFO) << "Camera list callback received "
+                          << cameraList.size()
+                          << " cameras";
                 cameraInfo.reserve(cameraList.size());
                 for (auto&& cam: cameraList) {
-                    ALOGI("Found camera %s", cam.v1.cameraId.c_str());
+                    LOG(INFO) << "Found camera " << cam.v1.cameraId;
                     cameraInfo.push_back(cam);
                 }
             }
@@ -137,10 +138,12 @@
 
         // Get the ultrasonics array list
         pEnumerator->getUltrasonicsArrayList([this](hidl_vec<UltrasonicsArrayDesc> ultraList) {
-            ALOGI("Ultrasonics array list callback received %zu arrays", ultraList.size());
+            LOG(INFO) << "Ultrasonics array list callback received "
+                      << ultraList.size()
+                      << " arrays";
             ultrasonicsArraysInfo.reserve(ultraList.size());
             for (auto&& ultraArray : ultraList) {
-                ALOGI("Found ultrasonics array %s", ultraArray.ultrasonicsArrayId.c_str());
+                LOG(INFO) << "Found ultrasonics array " << ultraArray.ultrasonicsArrayId;
                 ultrasonicsArraysInfo.push_back(ultraArray);
             }
         });
@@ -195,7 +198,7 @@
         if (!flag) {
             // EVS assumes that the device w/o a valid metadata is a physical
             // device.
-            ALOGI("%s is not a logical camera device.", id.c_str());
+            LOG(INFO) << id << " is not a logical camera device.";
             physicalCameras.emplace(id);
             return physicalCameras;
         }
@@ -205,7 +208,9 @@
         int rc = find_camera_metadata_ro_entry(metadata,
                                                ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
                                                &entry);
-        ALOGE_IF(rc, "No physical camera ID is found for a logical camera device");
+        if (rc != 0) {
+            LOG(ERROR) << "No physical camera ID is found for a logical camera device";
+        }
 
         const uint8_t *ids = entry.data.u8;
         size_t start = 0;
@@ -219,7 +224,10 @@
             }
         }
 
-        ALOGI("%s consists of %d physical camera devices.", id.c_str(), (int)physicalCameras.size());
+        LOG(INFO) << id
+                  << " consists of "
+                  << physicalCameras.size()
+                  << " physical camera devices";
         return physicalCameras;
     }
 
@@ -228,7 +236,7 @@
     std::vector<CameraDesc>         cameraInfo;    // Empty unless/until loadCameraList() is called
     bool                            mIsHwModule;   // boolean to tell current module under testing
                                                    // is HW module implementation.
-    std::deque<wp<IEvsCamera_1_1>>  activeCameras; // A list of active camera handles that are
+    std::deque<sp<IEvsCamera_1_1>>  activeCameras; // A list of active camera handles that are
                                                    // needed to be cleaned up.
     std::vector<UltrasonicsArrayDesc>
             ultrasonicsArraysInfo;                           // Empty unless/until
@@ -247,7 +255,7 @@
  * call to closeCamera.  Then repeats the test to ensure all cameras can be reopened.
  */
 TEST_P(EvsHidlTest, CameraOpenClean) {
-    ALOGI("Starting CameraOpenClean test");
+    LOG(INFO) << "Starting CameraOpenClean test";
 
     // Get the camera list
     loadCameraList();
@@ -261,15 +269,12 @@
         bool isLogicalCam = false;
         auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
         if (mIsHwModule && isLogicalCam) {
-            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            LOG(INFO) << "Skip a logical device, " << cam.v1.cameraId << " for HW target.";
             continue;
         }
 
         for (int pass = 0; pass < 2; pass++) {
-            activeCameras.clear();
-            sp<IEvsCamera_1_1> pCam =
-                IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-                .withDefault(nullptr);
+            sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg);
             ASSERT_NE(pCam, nullptr);
 
             for (auto&& devName : devices) {
@@ -286,7 +291,7 @@
 
             // Verify that this camera self-identifies correctly
             pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
-                                        ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+                                        LOG(DEBUG) << "Found camera " << desc.v1.cameraId;
                                         EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
                                     }
             );
@@ -295,15 +300,16 @@
             const auto id = 0xFFFFFFFF; // meaningless id
             hidl_vec<uint8_t> values;
             auto err = pCam->setExtendedInfo_1_1(id, values);
-            ASSERT_EQ(EvsResult::INVALID_ARG, err);
+            ASSERT_NE(EvsResult::INVALID_ARG, err);
 
             pCam->getExtendedInfo_1_1(id, [](const auto& result, const auto& data) {
-                ASSERT_EQ(EvsResult::INVALID_ARG, result);
+                ASSERT_NE(EvsResult::INVALID_ARG, result);
                 ASSERT_EQ(0, data.size());
             });
 
             // Explicitly close the camera so resources are released right away
             pEnumerator->closeCamera(pCam);
+            activeCameras.clear();
         }
     }
 }
@@ -316,7 +322,7 @@
  * the system to be tolerant of shutdown/restart race conditions.
  */
 TEST_P(EvsHidlTest, CameraOpenAggressive) {
-    ALOGI("Starting CameraOpenAggressive test");
+    LOG(INFO) << "Starting CameraOpenAggressive test";
 
     // Get the camera list
     loadCameraList();
@@ -330,7 +336,7 @@
         bool isLogicalCam = false;
         getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
         if (mIsHwModule && isLogicalCam) {
-            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            LOG(INFO) << "Skip a logical device, " << cam.v1.cameraId << " for HW target.";
             continue;
         }
 
@@ -345,7 +351,7 @@
 
         // Verify that this camera self-identifies correctly
         pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
-                                    ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+                                    LOG(DEBUG) << "Found camera " << desc.v1.cameraId;
                                     EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
                                 }
         );
@@ -371,16 +377,18 @@
 
         // Close the superceded camera
         pEnumerator->closeCamera(pCam);
+        activeCameras.pop_front();
 
         // Verify that the second camera instance self-identifies correctly
         pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) {
-                                     ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+                                     LOG(DEBUG) << "Found camera " << desc.v1.cameraId;
                                      EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
                                  }
         );
 
         // Close the second camera instance
         pEnumerator->closeCamera(pCam2);
+        activeCameras.pop_front();
     }
 
     // Sleep here to ensure the destructor cleanup has time to run so we don't break follow on tests
@@ -393,7 +401,7 @@
  * Measure and qualify the stream start up time and streaming frame rate of each reported camera
  */
 TEST_P(EvsHidlTest, CameraStreamPerformance) {
-    ALOGI("Starting CameraStreamPerformance test");
+    LOG(INFO) << "Starting CameraStreamPerformance test";
 
     // Get the camera list
     loadCameraList();
@@ -407,11 +415,10 @@
         bool isLogicalCam = false;
         auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
         if (mIsHwModule && isLogicalCam) {
-            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
             continue;
         }
 
-        activeCameras.clear();
         sp<IEvsCamera_1_1> pCam =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
@@ -444,8 +451,10 @@
                   kMaxStreamStartMilliseconds * devices.size());
         printf("%s: Measured time to first frame %0.2f ms\n",
                cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
-        ALOGI("%s: Measured time to first frame %0.2f ms",
-              cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
+        LOG(INFO) << cam.v1.cameraId
+                  << ": Measured time to first frame "
+                  << std::scientific << timeToFirstFrame * kNanoToMilliseconds
+                  << " ms.";
 
         // Check aspect ratio
         unsigned width = 0, height = 0;
@@ -468,11 +477,14 @@
         nsecs_t runTime = end - firstFrame;
         float framesPerSecond = framesReceived / (runTime * kNanoToSeconds);
         printf("Measured camera rate %3.2f fps\n", framesPerSecond);
-        ALOGI("Measured camera rate %3.2f fps", framesPerSecond);
+        LOG(INFO) << "Measured camera rate "
+                  << std::scientific << framesPerSecond
+                  << " fps.";
         EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond);
 
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
     }
 }
 
@@ -483,7 +495,7 @@
  * than one frame time.  The camera must cleanly skip frames until the client is ready again.
  */
 TEST_P(EvsHidlTest, CameraStreamBuffering) {
-    ALOGI("Starting CameraStreamBuffering test");
+    LOG(INFO) << "Starting CameraStreamBuffering test";
 
     // Arbitrary constant (should be > 1 and less than crazy)
     static const unsigned int kBuffersToHold = 6;
@@ -500,11 +512,10 @@
         bool isLogicalCam = false;
         getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
         if (mIsHwModule && isLogicalCam) {
-            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId << " for HW target.";
             continue;
         }
 
-        activeCameras.clear();
         sp<IEvsCamera_1_1> pCam =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
@@ -557,6 +568,7 @@
 
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
     }
 }
 
@@ -568,7 +580,7 @@
  * which a human could observe to see the operation of the system on the physical display.
  */
 TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) {
-    ALOGI("Starting CameraToDisplayRoundTrip test");
+    LOG(INFO) << "Starting CameraToDisplayRoundTrip test";
 
     // Get the camera list
     loadCameraList();
@@ -587,14 +599,14 @@
     // Request exclusive access to the first EVS display
     sp<IEvsDisplay_1_1> pDisplay = pEnumerator->openDisplay_1_1(targetDisplayId);
     ASSERT_NE(pDisplay, nullptr);
-    ALOGI("Display %d is in use.", targetDisplayId);
+    LOG(INFO) << "Display " << targetDisplayId << " is alreay in use.";
 
     // Get the display descriptor
     pDisplay->getDisplayInfo_1_1([](const auto& config, const auto& state) {
         android::DisplayConfig* pConfig = (android::DisplayConfig*)config.data();
         const auto width = pConfig->resolution.getWidth();
         const auto height = pConfig->resolution.getHeight();
-        ALOGI("    Resolution: %dx%d", width, height);
+        LOG(INFO) << "    Resolution: " << width << "x" << height;
         ASSERT_GT(width, 0);
         ASSERT_GT(height, 0);
 
@@ -607,11 +619,10 @@
         bool isLogicalCam = false;
         getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
         if (mIsHwModule && isLogicalCam) {
-            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId << " for HW target.";
             continue;
         }
 
-        activeCameras.clear();
         sp<IEvsCamera_1_1> pCam =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
@@ -654,6 +665,7 @@
 
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
     }
 
     // Explicitly release the display
@@ -667,7 +679,7 @@
  * underlying camera.
  */
 TEST_P(EvsHidlTest, MultiCameraStream) {
-    ALOGI("Starting MultiCameraStream test");
+    LOG(INFO) << "Starting MultiCameraStream test";
 
     if (mIsHwModule) {
         // This test is not for HW module implementation.
@@ -683,7 +695,6 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
-        activeCameras.clear();
         // Create two camera clients.
         sp<IEvsCamera_1_1> pCam0 =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
@@ -735,7 +746,9 @@
         nsecs_t runTime = end - firstFrame;
         float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
         float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
-        ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+        LOG(INFO) << "Measured camera rate "
+                  << std::scientific << framesPerSecond0 << " fps and "
+                  << framesPerSecond1 << " fps";
         EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
         EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
 
@@ -760,6 +773,7 @@
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam0);
         pEnumerator->closeCamera(pCam1);
+        activeCameras.clear();
 
         // TODO(b/145459970, b/145457727): below sleep() is added to ensure the
         // destruction of active camera objects; this may be related with two
@@ -774,7 +788,7 @@
  * Verify that a client can adjust a camera parameter.
  */
 TEST_P(EvsHidlTest, CameraParameter) {
-    ALOGI("Starting CameraParameter test");
+    LOG(INFO) << "Starting CameraParameter test";
 
     // Get the camera list
     loadCameraList();
@@ -791,11 +805,10 @@
         if (isLogicalCam) {
             // TODO(b/145465724): Support camera parameter programming on
             // logical devices.
-            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
             continue;
         }
 
-        activeCameras.clear();
         // Create a camera client
         sp<IEvsCamera_1_1> pCam =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
@@ -908,6 +921,7 @@
 
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
     }
 }
 
@@ -918,7 +932,7 @@
  * terminates or releases a role.
  */
 TEST_P(EvsHidlTest, CameraMasterRelease) {
-    ALOGI("Starting CameraMasterRelease test");
+    LOG(INFO) << "Starting CameraMasterRelease test";
 
     if (mIsHwModule) {
         // This test is not for HW module implementation.
@@ -939,11 +953,10 @@
         if (isLogicalCam) {
             // TODO(b/145465724): Support camera parameter programming on
             // logical devices.
-            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
             continue;
         }
 
-        activeCameras.clear();
         // Create two camera clients.
         sp<IEvsCamera_1_1> pCamMaster =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
@@ -1012,7 +1025,7 @@
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
                 if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) {
-                    ALOGW("A timer is expired before a target event is fired.");
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
 
             }
@@ -1057,7 +1070,7 @@
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
                 if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) {
-                    ALOGW("A timer is expired before a target event is fired.");
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
 
             }
@@ -1089,6 +1102,7 @@
         // Explicitly release the camera
         pEnumerator->closeCamera(pCamMaster);
         pEnumerator->closeCamera(pCamNonMaster);
+        activeCameras.clear();
     }
 }
 
@@ -1099,7 +1113,7 @@
  * camera parameters.
  */
 TEST_P(EvsHidlTest, MultiCameraParameter) {
-    ALOGI("Starting MultiCameraParameter test");
+    LOG(INFO) << "Starting MultiCameraParameter test";
 
     if (mIsHwModule) {
         // This test is not for HW module implementation.
@@ -1120,11 +1134,10 @@
         if (isLogicalCam) {
             // TODO(b/145465724): Support camera parameter programming on
             // logical devices.
-            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
             continue;
         }
 
-        activeCameras.clear();
         // Create two camera clients.
         sp<IEvsCamera_1_1> pCamMaster =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
@@ -1256,7 +1269,7 @@
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
                     if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
-                        ALOGW("A timer is expired before a target event is fired.");
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
             );
@@ -1273,7 +1286,7 @@
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
                     if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
-                        ALOGW("A timer is expired before a target event is fired.");
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
             );
@@ -1374,7 +1387,7 @@
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
                 if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) {
-                    ALOGW("A timer is expired before a target event is fired.");
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
             }
         );
@@ -1466,7 +1479,7 @@
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
                     if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
-                        ALOGW("A timer is expired before a target event is fired.");
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
             );
@@ -1482,7 +1495,7 @@
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
                     if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
-                        ALOGW("A timer is expired before a target event is fired.");
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
             );
@@ -1562,6 +1575,7 @@
         // Explicitly release the camera
         pEnumerator->closeCamera(pCamMaster);
         pEnumerator->closeCamera(pCamNonMaster);
+        activeCameras.clear();
     }
 }
 
@@ -1572,7 +1586,7 @@
  * a master role from other EVS clients without the display.
  */
 TEST_P(EvsHidlTest, HighPriorityCameraClient) {
-    ALOGI("Starting HighPriorityCameraClient test");
+    LOG(INFO) << "Starting HighPriorityCameraClient test";
 
     if (mIsHwModule) {
         // This test is not for HW module implementation.
@@ -1592,8 +1606,6 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
-        activeCameras.clear();
-
         // Create two clients
         sp<IEvsCamera_1_1> pCam0 =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
@@ -1687,7 +1699,7 @@
                     aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
                     aTargetEvent.payload[1] = 0;
                     if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
-                        ALOGW("A timer is expired before a target event is fired.");
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
             );
@@ -1740,7 +1752,7 @@
                 aTargetEvent.payload[0] = static_cast<uint32_t>(cam1Cmds[0]);
                 aTargetEvent.payload[1] = val0;
                 if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
-                    ALOGW("A timer is expired before a target event is fired.");
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
             }
         );
@@ -1791,7 +1803,7 @@
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
                 if (!frameHandler1->waitForEvent(aTargetEvent, aNotification, true)) {
-                    ALOGW("A timer is expired before a target event is fired.");
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
             }
         );
@@ -1833,7 +1845,7 @@
                     aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
                     aTargetEvent.payload[1] = 0;
                     if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
-                        ALOGW("A timer is expired before a target event is fired.");
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
             );
@@ -1882,7 +1894,7 @@
                 aTargetEvent.payload[0] = static_cast<uint32_t>(cam0Cmds[0]);
                 aTargetEvent.payload[1] = val0;
                 if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
-                    ALOGW("A timer is expired before a target event is fired.");
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
             }
         );
@@ -1931,6 +1943,8 @@
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam0);
         pEnumerator->closeCamera(pCam1);
+        activeCameras.clear();
+
     }
 
     // Explicitly release the display
@@ -1945,7 +1959,7 @@
  * configurations from EVS and uses one of them to start a video stream.
  */
 TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) {
-    ALOGI("Starting CameraUseStreamConfigToDisplay test");
+    LOG(INFO) << "Starting CameraUseStreamConfigToDisplay test";
 
     // Get the camera list
     loadCameraList();
@@ -1956,7 +1970,6 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
-        activeCameras.clear();
         // choose a configuration that has a frame rate faster than minReqFps.
         Stream targetCfg = {};
         const int32_t minReqFps = 15;
@@ -2036,6 +2049,7 @@
 
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
     }
 
     // Explicitly release the display
@@ -2049,7 +2063,7 @@
  * underlying camera with same configuration.
  */
 TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) {
-    ALOGI("Starting MultiCameraStream test");
+    LOG(INFO) << "Starting MultiCameraStream test";
 
     if (mIsHwModule) {
         // This test is not for HW module implementation.
@@ -2061,7 +2075,6 @@
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
-        activeCameras.clear();
         // choose a configuration that has a frame rate faster than minReqFps.
         Stream targetCfg = {};
         const int32_t minReqFps = 15;
@@ -2094,9 +2107,8 @@
             static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
 
         if (!foundCfg) {
-            ALOGI("Device %s does not provide a list of supported stream configurations, skipped",
-                  cam.v1.cameraId.c_str());
-
+            LOG(INFO) << "Device " << cam.v1.cameraId
+                      << " does not provide a list of supported stream configurations, skipped";
             continue;
         }
 
@@ -2162,7 +2174,9 @@
         nsecs_t runTime = end - firstFrame;
         float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
         float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
-        ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+        LOG(INFO) << "Measured camera rate "
+                  << std::scientific << framesPerSecond0 << " fps and "
+                  << framesPerSecond1 << " fps";
         EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
         EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
 
@@ -2187,6 +2201,7 @@
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam0);
         pEnumerator->closeCamera(pCam1);
+        activeCameras.clear();
     }
 }
 
@@ -2198,7 +2213,7 @@
  * identifiers.
  */
 TEST_P(EvsHidlTest, LogicalCameraMetadata) {
-    ALOGI("Starting LogicalCameraMetadata test");
+    LOG(INFO) << "Starting LogicalCameraMetadata test";
 
     // Get the camera list
     loadCameraList();
@@ -2222,7 +2237,7 @@
  * can be reopened.
  */
 TEST_P(EvsHidlTest, UltrasonicsArrayOpenClean) {
-    ALOGI("Starting UltrasonicsArrayOpenClean test");
+    LOG(INFO) << "Starting UltrasonicsArrayOpenClean test";
 
     // Get the ultrasonics array list
     loadUltrasonicsArrayList();
@@ -2236,7 +2251,7 @@
 
             // Verify that this ultrasonics array self-identifies correctly
             pUltrasonicsArray->getUltrasonicArrayInfo([&ultraInfo](UltrasonicsArrayDesc desc) {
-                ALOGD("Found ultrasonics array %s", ultraInfo.ultrasonicsArrayId.c_str());
+                LOG(DEBUG) << "Found ultrasonics array " << ultraInfo.ultrasonicsArrayId;
                 EXPECT_EQ(ultraInfo.ultrasonicsArrayId, desc.ultrasonicsArrayId);
             });
 
@@ -2249,14 +2264,14 @@
 
 // Starts a stream and verifies all data received is valid.
 TEST_P(EvsHidlTest, UltrasonicsVerifyStreamData) {
-    ALOGI("Starting UltrasonicsVerifyStreamData");
+    LOG(INFO) << "Starting UltrasonicsVerifyStreamData";
 
     // Get the ultrasonics array list
     loadUltrasonicsArrayList();
 
     // For each ultrasonics array.
     for (auto&& ultraInfo : ultrasonicsArraysInfo) {
-        ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str());
+        LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId;
 
         sp<IEvsUltrasonicsArray> pUltrasonicsArray =
                 pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
@@ -2285,14 +2300,14 @@
 
 // Sets frames in flight before and after start of stream and verfies success.
 TEST_P(EvsHidlTest, UltrasonicsSetFramesInFlight) {
-    ALOGI("Starting UltrasonicsSetFramesInFlight");
+    LOG(INFO) << "Starting UltrasonicsSetFramesInFlight";
 
     // Get the ultrasonics array list
     loadUltrasonicsArrayList();
 
     // For each ultrasonics array.
     for (auto&& ultraInfo : ultrasonicsArraysInfo) {
-        ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str());
+        LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId;
 
         sp<IEvsUltrasonicsArray> pUltrasonicsArray =
                 pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
index e3cbf2e..f2d3c13 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
@@ -206,7 +206,7 @@
         InternalPool(VehiclePropertyType type, size_t vectorSize)
             : mPropType(type), mVectorSize(vectorSize) {}
 
-        RecyclableType obtain() {
+        RecyclableType obtain() override {
             return ObjectPool<VehiclePropValue>::obtain();
         }
     protected:
diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
index 24b777c..6087bfa 100644
--- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -58,6 +58,8 @@
         return false;
     }
     // update the propertyValue.
+    // The timestamp in propertyStore should only be updated by the server side. It indicates
+    // the time when the event is generated by the server.
     valueToUpdate->timestamp = propValue.timestamp;
     valueToUpdate->value = propValue.value;
     if (updateStatus) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 6d5f23f..84354c1 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -15,8 +15,9 @@
  */
 #define LOG_TAG "DefaultVehicleHal_v2_0"
 
-#include <android/log.h>
 #include <android-base/macros.h>
+#include <android/log.h>
+#include <sys/system_properties.h>
 
 #include "EmulatedVehicleHal.h"
 #include "JsonFakeValueGenerator.h"
@@ -126,7 +127,9 @@
             *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
             break;
     }
-
+    if (v.get()) {
+        v->timestamp = elapsedRealtimeNano();
+    }
     return v;
 }
 
@@ -186,6 +189,14 @@
         return StatusCode::NOT_AVAILABLE;
     }
 
+    if (mInEmulator && propValue.prop == toInt(VehicleProperty::DISPLAY_BRIGHTNESS)) {
+        // Emulator does not support remote brightness control, b/139959479
+        // do not send it down so that it does not bring unnecessary property change event
+        // return other error code, such NOT_AVAILABLE, causes Emulator to be freezing
+        // TODO: return StatusCode::NOT_AVAILABLE once the above issue is fixed
+        return StatusCode::OK;
+    }
+
     /**
      * After checking all conditions, such as the property is available, a real vhal will
      * sent the events to Car ECU to take actions.
@@ -211,6 +222,17 @@
     return false;
 }
 
+// determine if it's running inside Android Emulator
+static bool isInEmulator() {
+    char propValue[PROP_VALUE_MAX];
+    bool isEmulator = (__system_property_get("ro.kernel.qemu", propValue) != 0);
+    if (!isEmulator) {
+        isEmulator = (__system_property_get("ro.hardware", propValue) != 0) &&
+                     (!strcmp(propValue, "ranchu") || !strcmp(propValue, "goldfish"));
+    }
+    return isEmulator;
+}
+
 // Parse supported properties list and generate vector of property values to hold current values.
 void EmulatedVehicleHal::onCreate() {
     static constexpr bool shouldUpdateStatus = true;
@@ -261,6 +283,8 @@
     }
     initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
     initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
+    mInEmulator = isInEmulator();
+    ALOGD("mInEmulator=%s", mInEmulator ? "true" : "false");
 }
 
 std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties()  {
@@ -283,6 +307,7 @@
         }
 
         if (v.get()) {
+            v->timestamp = elapsedRealtimeNano();
             doHalEvent(std::move(v));
         }
     }
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index ebf1995..dc05145 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -86,6 +86,7 @@
     std::unordered_set<int32_t> mHvacPowerProps;
     RecurrentTimer mRecurrentTimer;
     VehicleHalClient* mVehicleClient;
+    bool mInEmulator;
 };
 
 }  // impl
diff --git a/bluetooth/1.1/IBluetoothHci.hal b/bluetooth/1.1/IBluetoothHci.hal
index 0f69c6e..2a520c1 100644
--- a/bluetooth/1.1/IBluetoothHci.hal
+++ b/bluetooth/1.1/IBluetoothHci.hal
@@ -35,8 +35,8 @@
     initialize_1_1(@1.1::IBluetoothHciCallbacks callback);
 
     /**
-     * Send an ISO data packet (as specified in the Bluetooth Specification
-     * V6.0) to the Bluetooth controller.
+     * Send an ISO data packet (as specified in the Bluetooth Core
+     * Specification v5.2) to the Bluetooth controller.
      * Packets must be processed in order.
      * @param data HCI data packet to be sent
      */
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index f518a15..677b496 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -20,6 +20,7 @@
 
 #include <algorithm>
 #include <array>
+#include <regex>
 #include <linux/videodev2.h>
 #include "android-base/macros.h"
 #include "CameraMetadata.h"
@@ -46,10 +47,20 @@
 
 } // anonymous namespace
 
+const std::regex kDevicePathRE("/dev/video([0-9]+)");
+
 ExternalCameraDevice::ExternalCameraDevice(
-        const std::string& cameraId, const ExternalCameraConfig& cfg) :
-        mCameraId(cameraId),
-        mCfg(cfg) {}
+        const std::string& devicePath, const ExternalCameraConfig& cfg) :
+        mCameraId("-1"),
+        mDevicePath(devicePath),
+        mCfg(cfg) {
+    std::smatch sm;
+    if (std::regex_match(mDevicePath, sm, kDevicePathRE)) {
+        mCameraId = std::to_string(mCfg.cameraIdOffset + std::stoi(sm[1]));
+    } else {
+        ALOGE("%s: device path match failed for %s", __FUNCTION__, mDevicePath.c_str());
+    }
+}
 
 ExternalCameraDevice::~ExternalCameraDevice() {}
 
@@ -129,20 +140,20 @@
         return Void();
     }
 
-    unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
+    unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
     if (fd.get() < 0) {
         int numAttempt = 0;
         do {
             ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again",
-                    __FUNCTION__, mCameraId.c_str());
+                    __FUNCTION__, mDevicePath.c_str());
             usleep(OPEN_RETRY_SLEEP_US); // sleep and try again
-            fd.reset(::open(mCameraId.c_str(), O_RDWR));
+            fd.reset(::open(mDevicePath.c_str(), O_RDWR));
             numAttempt++;
         } while (fd.get() < 0 && numAttempt <= MAX_RETRY);
 
         if (fd.get() < 0) {
             ALOGE("%s: v4l2 device open %s failed: %s",
-                    __FUNCTION__, mCameraId.c_str(), strerror(errno));
+                    __FUNCTION__, mDevicePath.c_str(), strerror(errno));
             mLock.unlock();
             _hidl_cb(Status::INTERNAL_ERROR, nullptr);
             return Void();
@@ -203,9 +214,9 @@
 status_t ExternalCameraDevice::initCameraCharacteristics() {
     if (mCameraCharacteristics.isEmpty()) {
         // init camera characteristics
-        unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
+        unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
         if (fd.get() < 0) {
-            ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mCameraId.c_str());
+            ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mDevicePath.c_str());
             return DEAD_OBJECT;
         }
 
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index 62a4c87..8f4626c 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -703,6 +703,7 @@
 namespace common {
 
 namespace {
+    const int kDefaultCameraIdOffset = 100;
     const int kDefaultJpegBufSize = 5 << 20; // 5MB
     const int kDefaultNumVideoBuffer = 4;
     const int kDefaultNumStillBuffer = 2;
@@ -738,6 +739,11 @@
         return ret;
     }
 
+    XMLElement *cameraIdOffset = providerCfg->FirstChildElement("CameraIdOffset");
+    if (cameraIdOffset != nullptr) {
+        ret.cameraIdOffset = std::atoi(cameraIdOffset->GetText());
+    }
+
     XMLElement *ignore = providerCfg->FirstChildElement("ignore");
     if (ignore == nullptr) {
         ALOGI("%s: no internal ignored device specified", __FUNCTION__);
@@ -874,6 +880,7 @@
 }
 
 ExternalCameraConfig::ExternalCameraConfig() :
+        cameraIdOffset(kDefaultCameraIdOffset),
         maxJpegBufSize(kDefaultJpegBufSize),
         numVideoBuffers(kDefaultNumVideoBuffer),
         numStillBuffers(kDefaultNumStillBuffer),
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index 1958fcb..88726f4 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -149,6 +149,7 @@
     bool mInitialized = false;
     bool mInitFailed = false;
     std::string mCameraId;
+    std::string mDevicePath;
     const ExternalCameraConfig& mCfg;
     std::vector<SupportedV4L2Format> mSupportedFormats;
     CroppingType mCroppingType;
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 74f75eb..b354406 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -68,6 +68,9 @@
     static const char* kDefaultCfgPath;
     static ExternalCameraConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
 
+    // CameraId base offset for numerical representation
+    uint32_t cameraIdOffset;
+
     // List of internal V4L2 video nodes external camera HAL must ignore.
     std::unordered_set<std::string> mInternalDevices;
 
diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
index 60a1a10..8fd8e58 100644
--- a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
@@ -272,16 +272,17 @@
 
     // convert hal requests to offline request
     std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+    size_t i = 0;
     for (auto& v4lReq : halReqs) {
-        std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
-        halReq->frameNumber = v4lReq->frameNumber;
-        halReq->setting = v4lReq->setting;
-        halReq->shutterTs = v4lReq->shutterTs;
-        halReq->buffers = v4lReq->buffers;
+        offlineReqs[i] = std::make_shared<HalRequest>();
+        offlineReqs[i]->frameNumber = v4lReq->frameNumber;
+        offlineReqs[i]->setting = v4lReq->setting;
+        offlineReqs[i]->shutterTs = v4lReq->shutterTs;
+        offlineReqs[i]->buffers = v4lReq->buffers;
         sp<V3_4::implementation::V4L2Frame> v4l2Frame =
                 static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
-        halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame);
-        offlineReqs.push_back(halReq);
+        offlineReqs[i]->frameIn = new AllocatedV4L2Frame(v4l2Frame);
+        i++;
         // enqueue V4L2 frame
         enqueueV4l2Frame(v4l2Frame);
     }
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
index 4e2252c..d32bc91 100644
--- a/camera/metadata/3.5/types.hal
+++ b/camera/metadata/3.5/types.hal
@@ -35,28 +35,29 @@
  * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
  */
 enum CameraMetadataTag : @3.4::CameraMetadataTag {
-    /** android.control.availableBokehMaxSizes [static, int32[], ndk_public]
+    /** android.control.availableExtendedSceneModeMaxSizes [static, int32[], ndk_public]
      *
-     * <p>The list of bokeh modes for ANDROID_CONTROL_BOKEH_MODE that are supported by this camera
-     * device, and each bokeh mode's maximum streaming (non-stall) size with bokeh effect.</p>
+     * <p>The list of extended scene modes for ANDROID_CONTROL_EXTENDED_SCENE_MODE that are supported
+     * by this camera device, and each extended scene mode's maximum streaming (non-stall) size
+     * with  effect.</p>
      *
-     * @see ANDROID_CONTROL_BOKEH_MODE
+     * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE
      */
-    ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+    ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
 
-    /** android.control.availableBokehZoomRatioRanges [static, float[], ndk_public]
+    /** android.control.availableExtendedSceneModeZoomRatioRanges [static, float[], ndk_public]
      *
-     * <p>The ranges of supported zoom ratio for non-OFF ANDROID_CONTROL_BOKEH_MODE.</p>
+     * <p>The ranges of supported zoom ratio for non-DISABLED ANDROID_CONTROL_EXTENDED_SCENE_MODE.</p>
      *
-     * @see ANDROID_CONTROL_BOKEH_MODE
+     * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE
      */
-    ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES,
+    ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES,
 
-    /** android.control.bokehMode [dynamic, enum, public]
+    /** android.control.extendedSceneMode [dynamic, enum, public]
      *
-     * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+     * <p>Whether extended scene mode is enabled for a particular capture request.</p>
      */
-    ANDROID_CONTROL_BOKEH_MODE,
+    ANDROID_CONTROL_EXTENDED_SCENE_MODE,
 
     /** android.control.zoomRatioRange [static, float[], public]
      *
@@ -95,13 +96,22 @@
  * Enumeration definitions for the various entries that need them
  */
 
-/** android.control.bokehMode enumeration values
- * @see ANDROID_CONTROL_BOKEH_MODE
+/** android.control.mode enumeration values added since v3.2
+ * @see ANDROID_CONTROL_MODE
  */
-enum CameraMetadataEnumAndroidControlBokehMode : uint32_t {
-    ANDROID_CONTROL_BOKEH_MODE_OFF,
-    ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE,
-    ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS,
+enum CameraMetadataEnumAndroidControlMode :
+        @3.2::CameraMetadataEnumAndroidControlMode {
+    ANDROID_CONTROL_MODE_USE_EXTENDED_SCENE_MODE,
+};
+
+/** android.control.extendedSceneMode enumeration values
+ * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE
+ */
+enum CameraMetadataEnumAndroidControlExtendedSceneMode : uint32_t {
+    ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED                = 0,
+    ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE,
+    ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS,
+    ANDROID_CONTROL_EXTENDED_SCENE_MODE_VENDOR_START            = 0x40,
 };
 
 /** android.lens.poseReference enumeration values added since v3.3
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index 2bfced2..64a51f6 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -44,17 +44,19 @@
 const char* kDevicePath = "/dev/";
 constexpr char kPrefix[] = "video";
 constexpr int kPrefixLen = sizeof(kPrefix) - 1;
+constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
 
-bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
-                     std::string* cameraId) {
+bool matchDeviceName(int cameraIdOffset,
+                     const hidl_string& deviceName, std::string* deviceVersion,
+                     std::string* cameraDevicePath) {
     std::string deviceNameStd(deviceName.c_str());
     std::smatch sm;
     if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) {
         if (deviceVersion != nullptr) {
             *deviceVersion = sm[1];
         }
-        if (cameraId != nullptr) {
-            *cameraId = sm[2];
+        if (cameraDevicePath != nullptr) {
+            *cameraDevicePath = "/dev/video" + std::to_string(std::stoi(sm[2]) - cameraIdOffset);
         }
         return true;
     }
@@ -146,8 +148,9 @@
         const hidl_string& cameraDeviceName,
         ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb) {
 
-    std::string cameraId, deviceVersion;
-    bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId);
+    std::string cameraDevicePath, deviceVersion;
+    bool match = matchDeviceName(mCfg.cameraIdOffset, cameraDeviceName,
+                                 &deviceVersion, &cameraDevicePath);
     if (!match) {
         _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
         return Void();
@@ -164,19 +167,19 @@
         case 4: {
             ALOGV("Constructing v3.4 external camera device");
             deviceImpl = new device::V3_4::implementation::ExternalCameraDevice(
-                    cameraId, mCfg);
+                    cameraDevicePath, mCfg);
             break;
         }
         case 5: {
             ALOGV("Constructing v3.5 external camera device");
             deviceImpl = new device::V3_5::implementation::ExternalCameraDevice(
-                    cameraId, mCfg);
+                    cameraDevicePath, mCfg);
             break;
         }
         case 6: {
             ALOGV("Constructing v3.6 external camera device");
             deviceImpl = new device::V3_6::implementation::ExternalCameraDevice(
-                    cameraId, mCfg);
+                    cameraDevicePath, mCfg);
             break;
         }
         default:
@@ -186,7 +189,7 @@
     }
 
     if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
-        ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+        ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraDevicePath.c_str());
         _hidl_cb(Status::INTERNAL_ERROR, nullptr);
         return Void();
     }
@@ -210,12 +213,14 @@
     ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
     Mutex::Autolock _l(mLock);
     std::string deviceName;
+    std::string cameraId = std::to_string(mCfg.cameraIdOffset +
+                                          std::atoi(devName + kDevicePrefixLen));
     if (mPreferredHal3MinorVersion == 6) {
-        deviceName = std::string("device@3.6/external/") + devName;
+        deviceName = std::string("device@3.6/external/") + cameraId;
     } else if (mPreferredHal3MinorVersion == 5) {
-        deviceName = std::string("device@3.5/external/") + devName;
+        deviceName = std::string("device@3.5/external/") + cameraId;
     } else {
-        deviceName = std::string("device@3.4/external/") + devName;
+        deviceName = std::string("device@3.4/external/") + cameraId;
     }
     mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
     if (mCallbacks != nullptr) {
@@ -259,12 +264,14 @@
 void ExternalCameraProviderImpl_2_4::deviceRemoved(const char* devName) {
     Mutex::Autolock _l(mLock);
     std::string deviceName;
+    std::string cameraId = std::to_string(mCfg.cameraIdOffset +
+                                          std::atoi(devName + kDevicePrefixLen));
     if (mPreferredHal3MinorVersion == 6) {
-        deviceName = std::string("device@3.6/external/") + devName;
+        deviceName = std::string("device@3.6/external/") + cameraId;
     } else if (mPreferredHal3MinorVersion == 5) {
-        deviceName = std::string("device@3.5/external/") + devName;
+        deviceName = std::string("device@3.5/external/") + cameraId;
     } else {
-        deviceName = std::string("device@3.4/external/") + devName;
+        deviceName = std::string("device@3.4/external/") + cameraId;
     }
     if (mCameraStatusMap.find(deviceName) != mCameraStatusMap.end()) {
         mCameraStatusMap.erase(deviceName);
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index c9d76da..05b8b47 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -784,7 +784,7 @@
             const CameraMetadata& chars, int deviceVersion,
             const hidl_vec<hidl_string>& deviceNames);
     void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
-    void verifyBokehCharacteristics(const camera_metadata_t* metadata);
+    void verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata);
     void verifyZoomCharacteristics(const camera_metadata_t* metadata);
     void verifyRecommendedConfigs(const CameraMetadata& metadata);
     void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
@@ -6588,77 +6588,98 @@
                 poseReference >= ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA);
     }
 
-    verifyBokehCharacteristics(metadata);
+    verifyExtendedSceneModeCharacteristics(metadata);
     verifyZoomCharacteristics(metadata);
 }
 
-void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadata) {
+void CameraHidlTest::verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata) {
     camera_metadata_ro_entry entry;
     int retcode = 0;
 
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_AVAILABLE_MODES, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        for (auto i = 0; i < entry.count; i++) {
+            ASSERT_TRUE(entry.data.u8[i] >= ANDROID_CONTROL_MODE_OFF &&
+                        entry.data.u8[i] <= ANDROID_CONTROL_MODE_USE_EXTENDED_SCENE_MODE);
+        }
+    } else {
+        ADD_FAILURE() << "Get camera controlAvailableModes failed!";
+    }
+
     // Check key availability in capabilities, request and result.
 
     retcode = find_camera_metadata_ro_entry(metadata,
             ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
-    bool hasBokehRequestKey = false;
+    bool hasExtendedSceneModeRequestKey = false;
     if ((0 == retcode) && (entry.count > 0)) {
-        hasBokehRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count,
-                ANDROID_CONTROL_BOKEH_MODE) != entry.data.i32+entry.count;
+        hasExtendedSceneModeRequestKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_EXTENDED_SCENE_MODE) != entry.data.i32 + entry.count;
     } else {
         ADD_FAILURE() << "Get camera availableRequestKeys failed!";
     }
 
     retcode = find_camera_metadata_ro_entry(metadata,
             ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
-    bool hasBokehResultKey = false;
+    bool hasExtendedSceneModeResultKey = false;
     if ((0 == retcode) && (entry.count > 0)) {
-        hasBokehResultKey = std::find(entry.data.i32, entry.data.i32+entry.count,
-                ANDROID_CONTROL_BOKEH_MODE) != entry.data.i32+entry.count;
+        hasExtendedSceneModeResultKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_EXTENDED_SCENE_MODE) != entry.data.i32 + entry.count;
     } else {
         ADD_FAILURE() << "Get camera availableResultKeys failed!";
     }
 
     retcode = find_camera_metadata_ro_entry(metadata,
             ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
-    bool hasBokehMaxSizesKey = false;
-    bool hasBokehZoomRatioRangesKey = false;
+    bool hasExtendedSceneModeMaxSizesKey = false;
+    bool hasExtendedSceneModeZoomRatioRangesKey = false;
     if ((0 == retcode) && (entry.count > 0)) {
-        hasBokehMaxSizesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
-                ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES) != entry.data.i32+entry.count;
-        hasBokehZoomRatioRangesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
-                ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES) != entry.data.i32+entry.count;
+        hasExtendedSceneModeMaxSizesKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES) !=
+                entry.data.i32 + entry.count;
+        hasExtendedSceneModeZoomRatioRangesKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES) !=
+                entry.data.i32 + entry.count;
     } else {
         ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
     }
 
     camera_metadata_ro_entry maxSizesEntry;
-    retcode = find_camera_metadata_ro_entry(metadata,
-            ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES, &maxSizesEntry);
-    bool hasBokehMaxSizes = (0 == retcode && maxSizesEntry.count > 0);
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES, &maxSizesEntry);
+    bool hasExtendedSceneModeMaxSizes = (0 == retcode && maxSizesEntry.count > 0);
 
     camera_metadata_ro_entry zoomRatioRangesEntry;
-    retcode = find_camera_metadata_ro_entry(metadata,
-            ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES, &zoomRatioRangesEntry);
-    bool hasBokehZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0);
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES,
+            &zoomRatioRangesEntry);
+    bool hasExtendedSceneModeZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0);
 
-    // Bokeh keys must all be available, or all be unavailable.
-    bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehMaxSizesKey &&
-            !hasBokehZoomRatioRangesKey && !hasBokehMaxSizes && !hasBokehZoomRatioRanges;
-    if (noBokeh) {
+    // Extended scene mode keys must all be available, or all be unavailable.
+    bool noExtendedSceneMode =
+            !hasExtendedSceneModeRequestKey && !hasExtendedSceneModeResultKey &&
+            !hasExtendedSceneModeMaxSizesKey && !hasExtendedSceneModeZoomRatioRangesKey &&
+            !hasExtendedSceneModeMaxSizes && !hasExtendedSceneModeZoomRatioRanges;
+    if (noExtendedSceneMode) {
         return;
     }
-    bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehMaxSizesKey &&
-            hasBokehZoomRatioRangesKey && hasBokehMaxSizes && hasBokehZoomRatioRanges;
-    ASSERT_TRUE(hasBokeh);
+    bool hasExtendedSceneMode = hasExtendedSceneModeRequestKey && hasExtendedSceneModeResultKey &&
+                                hasExtendedSceneModeMaxSizesKey &&
+                                hasExtendedSceneModeZoomRatioRangesKey &&
+                                hasExtendedSceneModeMaxSizes && hasExtendedSceneModeZoomRatioRanges;
+    ASSERT_TRUE(hasExtendedSceneMode);
 
-    // Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS.
-    // Only valid combinations: {OFF, CONTINUOUS}, {OFF, STILL_CAPTURE}, and
-    // {OFF, CONTINUOUS, STILL_CAPTURE}.
+    // Must have DISABLED, and must have one of BOKEH_STILL_CAPTURE, BOKEH_CONTINUOUS, or a VENDOR
+    // mode.
     ASSERT_TRUE((maxSizesEntry.count == 6 && zoomRatioRangesEntry.count == 2) ||
             (maxSizesEntry.count == 9 && zoomRatioRangesEntry.count == 4));
-    bool hasOffMode = false;
-    bool hasStillCaptureMode = false;
-    bool hasContinuousMode = false;
+    bool hasDisabledMode = false;
+    bool hasBokehStillCaptureMode = false;
+    bool hasBokehContinuousMode = false;
+    bool hasVendorMode = false;
     std::vector<AvailableStream> outputStreams;
     ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams));
     for (int i = 0, j = 0; i < maxSizesEntry.count && j < zoomRatioRangesEntry.count; i += 3) {
@@ -6666,24 +6687,29 @@
         int32_t maxWidth = maxSizesEntry.data.i32[i+1];
         int32_t maxHeight = maxSizesEntry.data.i32[i+2];
         switch (mode) {
-            case ANDROID_CONTROL_BOKEH_MODE_OFF:
-                hasOffMode = true;
+            case ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED:
+                hasDisabledMode = true;
                 ASSERT_TRUE(maxWidth == 0 && maxHeight == 0);
                 break;
-            case ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE:
-                hasStillCaptureMode = true;
+            case ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE:
+                hasBokehStillCaptureMode = true;
                 j += 2;
                 break;
-            case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS:
-                hasContinuousMode = true;
+            case ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS:
+                hasBokehContinuousMode = true;
                 j += 2;
                 break;
             default:
-                ADD_FAILURE() << "Invalid bokehMode advertised: " << mode;
+                if (mode < ANDROID_CONTROL_EXTENDED_SCENE_MODE_VENDOR_START) {
+                    ADD_FAILURE() << "Invalid extended scene mode advertised: " << mode;
+                } else {
+                    hasVendorMode = true;
+                    j += 2;
+                }
                 break;
         }
 
-        if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) {
+        if (mode != ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED) {
             // Make sure size is supported.
             bool sizeSupported = false;
             for (const auto& stream : outputStreams) {
@@ -6703,8 +6729,8 @@
             ASSERT_LE(minZoomRatio, maxZoomRatio);
         }
     }
-    ASSERT_TRUE(hasOffMode);
-    ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode);
+    ASSERT_TRUE(hasDisabledMode);
+    ASSERT_TRUE(hasBokehStillCaptureMode || hasBokehContinuousMode || hasVendorMode);
 }
 
 void CameraHidlTest::verifyZoomCharacteristics(const camera_metadata_t* metadata) {
diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal
index 5651550..ed1d31d 100644
--- a/camera/provider/2.6/ICameraProvider.hal
+++ b/camera/provider/2.6/ICameraProvider.hal
@@ -76,6 +76,13 @@
      * configuration settings exposed through camera metadata), should the sum
      * of resource costs for the combination be <= 100.
      *
+     * The lists of camera id combinations returned by this method may contain
+     * hidden physical camera ids. If a combination does contain hidden physical
+     * camera ids, the camera framework must be able to open any logical cameras
+     * that contain these hidden physical camera ids in their
+     * ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS list, in addition to the other
+     * camera ids advertised in the combination, for concurrent operation.
+     *
      * @return status Status code for the operation
      * @return cameraIds a list of camera id combinations that support
      *         concurrent stream configurations with the minimum guarantees
diff --git a/cas/1.2/vts/functional/Android.bp b/cas/1.2/vts/functional/Android.bp
index 9bc372c..2d6517f 100644
--- a/cas/1.2/vts/functional/Android.bp
+++ b/cas/1.2/vts/functional/Android.bp
@@ -31,6 +31,8 @@
     shared_libs: [
         "libbinder",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
-
diff --git a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
index 8439ceb..58e0f2e 100644
--- a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
+++ b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
@@ -16,8 +16,6 @@
 
 #define LOG_TAG "mediacas_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/cas/1.0/IDescramblerBase.h>
 #include <android/hardware/cas/1.0/types.h>
@@ -28,8 +26,11 @@
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <android/hardware/cas/native/1.0/types.h>
 #include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
 #include <hidl/Status.h>
 #include <hidlmemory/FrameworkUtils.h>
 #include <utils/Condition.h>
@@ -293,27 +294,14 @@
     EXPECT_EQ(mEventArg, static_cast<int32_t>(mode));
 }
 
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-  public:
-    // get the test environment singleton
-    static CasHidlEnvironment* Instance() {
-        static CasHidlEnvironment* instance = new CasHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
-        mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
-                CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+        mService = IMediaCasService::getService(GetParam());
         ASSERT_NE(mService, nullptr);
     }
 
-    sp<IMediaCasService> mService;
+    sp<IMediaCasService> mService = nullptr;
 
   protected:
     static void description(const std::string& description) {
@@ -497,7 +485,7 @@
     return ::testing::AssertionResult(returnVoid.isOk());
 }
 
-TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) {
+TEST_P(MediaCasHidlTest, TestClearKeyApisWithSession) {
     description("Test that valid call sequences with SessionEvent send and receive");
 
     ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -609,11 +597,7 @@
 
 }  // anonymous namespace
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    CasHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, MediaCasHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 7883dd9..33157a6 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -83,8 +83,8 @@
         "compatibility_matrix.current.xml",
     ],
     kernel_configs: [
-        "kernel_config_current_4.14",
-        "kernel_config_current_4.19",
-        "kernel_config_current_5.4",
+        "kernel_config_r_4.14",
+        "kernel_config_r_4.19",
+        "kernel_config_r_5.4",
     ]
 }
diff --git a/compatibility_matrices/compatibility_matrix.1.xml b/compatibility_matrices/compatibility_matrix.1.xml
index d82829d..cccf24f 100644
--- a/compatibility_matrices/compatibility_matrix.1.xml
+++ b/compatibility_matrices/compatibility_matrix.1.xml
@@ -71,7 +71,7 @@
             <instance>legacy/0</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <hal format="hidl" optional="true">
         <name>android.hardware.configstore</name>
         <version>1.0</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.2.xml b/compatibility_matrices/compatibility_matrix.2.xml
index 98e6cfa..d4f9809 100644
--- a/compatibility_matrices/compatibility_matrix.2.xml
+++ b/compatibility_matrices/compatibility_matrix.2.xml
@@ -79,7 +79,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <hal format="hidl" optional="true">
         <name>android.hardware.configstore</name>
         <version>1.0</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.3.xml b/compatibility_matrices/compatibility_matrix.3.xml
index 9933b33..5888ab9 100644
--- a/compatibility_matrices/compatibility_matrix.3.xml
+++ b/compatibility_matrices/compatibility_matrix.3.xml
@@ -111,7 +111,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <hal format="hidl" optional="true">
         <name>android.hardware.configstore</name>
         <version>1.0-1</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml
index 01ec172..e5e012c 100644
--- a/compatibility_matrices/compatibility_matrix.4.xml
+++ b/compatibility_matrices/compatibility_matrix.4.xml
@@ -181,12 +181,6 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.gnss</name>
-        <!--
-         - Both versions are listed here as a workaround for libvintf since 2.0 extends 1.1.
-         - Devices launched with Q must support gnss@2.0, see VtsTrebleVendorVintfTest
-         - test DeviceManifestTest#GnssHalVersionCompatibility.
-        -->
-        <version>1.1</version>
         <version>2.0</version>
         <interface>
             <name>IGnss</name>
@@ -429,7 +423,6 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.thermal</name>
-        <version>1.0-1</version>
         <version>2.0</version>
         <interface>
             <name>IThermal</name>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index de1ee84..f28a8b2 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -40,9 +40,21 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
-        <name>android.hardware.automotive.evs</name>
+        <name>android.hardware.automotive.can</name>
         <version>1.0</version>
         <interface>
+            <name>ICanBus</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+        <interface>
+            <name>ICanController</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.evs</name>
+        <version>1.0-1</version>
+        <interface>
             <name>IEvsEnumerator</name>
             <instance>default</instance>
             <regex-instance>[a-z]+/[0-9]+</regex-instance>
@@ -197,12 +209,6 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.gnss</name>
-        <!--
-         - Both versions are listed here as a workaround for libvintf since 2.0 extends 1.1.
-         - Devices launched with Q must support gnss@2.0, see VtsTrebleVendorVintfTest
-         - test DeviceManifestTest#GnssHalVersionCompatibility.
-        -->
-        <version>1.1</version>
         <version>2.0-1</version>
         <interface>
             <name>IGnss</name>
@@ -255,6 +261,13 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.identity</name>
+        <interface>
+            <name>IIdentityCredentialStore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.ir</name>
         <version>1.0</version>
@@ -451,7 +464,6 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.thermal</name>
-        <version>1.0</version>
         <version>2.0</version>
         <interface>
             <name>IThermal</name>
@@ -475,6 +487,14 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.tv.tuner</name>
+        <version>1.0</version>
+        <interface>
+            <name>ITuner</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.usb</name>
         <version>1.0-2</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.legacy.xml b/compatibility_matrices/compatibility_matrix.legacy.xml
index 224811f..8a4d2ee 100644
--- a/compatibility_matrices/compatibility_matrix.legacy.xml
+++ b/compatibility_matrices/compatibility_matrix.legacy.xml
@@ -71,7 +71,7 @@
             <instance>legacy/0</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <hal format="hidl" optional="true">
         <name>android.hardware.configstore</name>
         <version>1.0</version>
         <interface>
diff --git a/configstore/1.1/default/Android.mk b/configstore/1.1/default/Android.mk
index e7edc34..6b7bb00 100644
--- a/configstore/1.1/default/Android.mk
+++ b/configstore/1.1/default/Android.mk
@@ -35,3 +35,14 @@
 LOCAL_SRC_FILES := seccomp_policy/configstore@1.1-$(TARGET_ARCH).policy
 include $(BUILD_PREBUILT)
 endif
+
+# disable configstore
+include $(CLEAR_VARS)
+LOCAL_MODULE := disable_configstore
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_SRC_FILES:= disable_configstore.cpp
+LOCAL_OVERRIDES_MODULES := android.hardware.configstore@1.1-service
+LOCAL_VENDOR_MODULE := true
+LOCAL_UNINSTALLABLE_MODULE := true
+
+include $(BUILD_EXECUTABLE)
diff --git a/configstore/1.1/default/disable_configstore.cpp b/configstore/1.1/default/disable_configstore.cpp
new file mode 100644
index 0000000..b727ddb
--- /dev/null
+++ b/configstore/1.1/default/disable_configstore.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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.
+ */
+
+int main() {
+    return 1;
+}
diff --git a/current.txt b/current.txt
index 42981ad..47b7206 100644
--- a/current.txt
+++ b/current.txt
@@ -589,6 +589,7 @@
 a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types
 9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback
 af334f1fc85c62b343f84b74d0495eed6f495f7fecedb53463db10c202310058 android.hardware.gnss.measurement_corrections@1.0::types
+33a6b20c43af00fdfb305df891bc5911c06d9a9130b912759649932e5a4a6e6d android.hardware.gnss.visibility_control@1.0::IGnssVisibilityControlCallback
 bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider
 2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback
 b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
@@ -605,7 +606,6 @@
 5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface
 
 # HALs released in Android R
-822369cf4dc16a6f6b9622bcf86cbdc0b692dc82193fc15e967767175cbfdd8f android.hardware.audio@6.0::types
 7241bd4596a927cd46d4b82f5e29e2cbe57f194aa1b25555f1d1d352e8b15c61 android.hardware.audio@6.0::IDevice
 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory
 bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice
@@ -614,8 +614,8 @@
 164826a380f4c1700183003f62d7532e367b67381c30ea44f946c0cf00008f85 android.hardware.audio@6.0::IStreamOut
 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback
 e7ca0db9a1098210f327a9b152fa6afe6bf019c41e5264c64829d04d50c0a526 android.hardware.audio@6.0::IStreamOutEventCallback
+822369cf4dc16a6f6b9622bcf86cbdc0b692dc82193fc15e967767175cbfdd8f android.hardware.audio@6.0::types
 bee662c62d997d8065e2bcb5c1e7a9578931f22ce28fd02c219fdb4d0630abf7 android.hardware.audio.common@6.0::types
-817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect
 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect
 461b1114cb35d89f87e5694e0792ba53c112a7fa9a14d9b95188cf9c4764be23 android.hardware.audio.effect@6.0::IBassBoostEffect
@@ -630,18 +630,19 @@
 5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect
 282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect
 0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect
+817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
 7e8e1c3d0173c5d503dd01cecff8e3864478557ca6b9e8cc2291598b1a4aea62 android.hardware.biometrics.face@1.1::IBiometricsFace
-ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types
 6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint
 82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback
-79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci
+ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types
+362fd1c21641c2224f3b80c30d9797b988fa3f344243d531ba73c553779a5763 android.hardware.bluetooth@1.1::IBluetoothHci
 40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks
 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
 b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice
-99aae72ae75a8ddf63ccffbc585f3a55f4d0847b4adff3d7a0f8bd9e2305bec1 android.hardware.camera.provider@2.6::ICameraProvider
-8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
 a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types
+21086e1c7a2acc0ebe0ff8561b11f3c2009be687a92d79b608a5f00b16c5f598 android.hardware.camera.provider@2.6::ICameraProvider
+8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
 c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas
 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener
 f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService
@@ -650,25 +651,21 @@
 3581d0ba61663cdd45807494dcd697d01c074f27587df9140655f94346969cfe android.hardware.contexthub@1.1::types
 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory
 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory
-d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types
 186bc152ae189ab48f3a761a44ddf5edd0d483073c5b6ca1f802f8b50488b754 android.hardware.dumpstate@1.1::IDumpstateDevice
-769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types
+d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types
 c319e68b03829958404402c2d9c682019678087d60495807c0a7444e0a6af981 android.hardware.gnss@2.1::IGnss
 ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardware.gnss@2.1::IGnssAntennaInfo
 0bc3ed97cbc3f6abc89c68f4e9f4d124f9f723431997dc88c2186cf4d2ad47ee android.hardware.gnss@2.1::IGnssAntennaInfoCallback
 3541d83adfeac16ee3e45d183a58dffe06012ccb5aa5bcd2e4f6eeae269f69cd android.hardware.gnss@2.1::IGnssCallback
 737d750017738f0753d13ba01a3310e0161f294b8ae80b3fd63eaa227e9d9c66 android.hardware.gnss@2.1::IGnssConfiguration
 7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement
-0a16e5913e94d995cfcf959a1c6f10b0b8e9dfdb5f45ac6e7244711ddd740272 android.hardware.gnss@2.1::IGnssMeasurementCallback
+df52e2c39ed701a355b5e0fdbf83fe5fa7d04bfecd715116b39373d46dc3c682 android.hardware.gnss@2.1::IGnssMeasurementCallback
+769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types
 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections
 956c1576ca0d6f11b42980ef59052062836b6763fe973af6cb709da50787f710 android.hardware.gnss.measurement_corrections@1.1::types
 ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
 e2f8bc1868fd4a3fd587c172773ea5a8c2f5a3deaf7958394102ca455252b255 android.hardware.health@2.1::types
-0589e410f519e36514e7ece18f283f022df0f70efd2c12821d822f67f74aba98 android.hardware.identity@1.0::types
-bbeee9604128ede83ee755b67e73b5ad29e6e1dbac9ec41fea6ffe2745b0c50a android.hardware.identity@1.0::IIdentityCredential
-96ce8aad80f4c476f25261f790d357c117e79e18474c7dadd850dac704bbe65e android.hardware.identity@1.0::IIdentityCredentialStore
-8da9c938e58f7d636ddd2f92c646f99d9a9e79612e6441b6380ab12744251873 android.hardware.identity@1.0::IWritableIdentityCredential
 27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice
 adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
 ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types
@@ -680,8 +677,16 @@
 6e904be0ddca5ae1de8eba020e6c38ed935ea7d80cd08f47787f137a0ca58555 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
 2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel
 eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-c9320b04ec302624985180a02d591bea5e435601fc411a6cabb58878e4e1ad68 android.hardware.neuralnetworks@1.3::types
-b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types
+e442ab1b440327fe4e8a3b0b8ac6874e9bc6342e91fe976eb9fea77c63961ec8 android.hardware.neuralnetworks@1.3::types
+b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio
+fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication
+b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse
+6b8dcd5e3e33a524cc7ebb14671a76ad3a2d333467397ce82acc4024346386f8 android.hardware.radio@1.5::types
+3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors
+3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback
+8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types
+b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw
+4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types
 adab52e647d1a1ccfbdabdfc9c73352f8e834b61322e505bc6e3d3a0d3acc259 android.hardware.tv.tuner@1.0::IDemux
 548e1a16fc4f779346e14968a63cd6f160e1e2c8b8c99256b2bac24a24b52a9a android.hardware.tv.tuner@1.0::IDescrambler
 b84597d59f0f1d03c9997d60eb15280f3950c287d46016240d89859789db4d47 android.hardware.tv.tuner@1.0::IDvr
@@ -694,6 +699,8 @@
 b2310785bdb55f97bbbb2176e2ee73ed8d2a7ce5895bd20c997b90c5f2868ad8 android.hardware.tv.tuner@1.0::ILnbCallback
 4788787e662293d526ff7789fc24e82533e7f6ff99a967ebc3e3ec6b17628796 android.hardware.tv.tuner@1.0::ITimeFilter
 c350c7783843e0c7cf30f90c918770b0d3c09fc0fe5e532e2f2e7210fcfe71c9 android.hardware.tv.tuner@1.0::ITuner
+b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types
+7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
 c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types
@@ -702,13 +709,3 @@
 2ce1f7fb52e49f80b13a9b153d491bce530552f02357ea729acae922a8659f93 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
 77531c8d048f8f8ae532babd0ca86332a865ec9aace1b051226ef2b21123e645 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types
-99f5c26b952271d1246c957e1d0271fa39445ee65cc93aa7c187834f98914a33 android.hardware.radio@1.5::types
-b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio
-e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication
-829d3827eeb5a8f563e80fe627419b3231012fc02bc2e79782ec5e9ad9f799a4 android.hardware.radio@1.5::IRadioResponse
-3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors
-3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback
-8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types
-4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types
-b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw
-7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp
index 4be1575..ac1f912 100644
--- a/drm/1.3/vts/functional/Android.bp
+++ b/drm/1.3/vts/functional/Android.bp
@@ -30,12 +30,12 @@
         "android.hardware.drm@1.3",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
+        "libcrypto",
         "libhidlmemory",
         "libnativehelper",
     ],
     static_libs: [
         "android.hardware.drm@1.0-helper",
-        "libcrypto_static",
         "libdrmvtshelper",
     ],
     export_include_dirs: [
@@ -63,12 +63,12 @@
         "android.hardware.drm@1.3",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
+        "libcrypto",
         "libhidlmemory",
         "libnativehelper",
     ],
     static_libs: [
         "android.hardware.drm@1.0-helper",
-        "libcrypto_static",
         "libdrmvtshelper",
     ],
     test_suites: [
diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp
index d778d50..a3ea807 100644
--- a/gnss/2.0/default/GnssMeasurement.cpp
+++ b/gnss/2.0/default/GnssMeasurement.cpp
@@ -49,8 +49,8 @@
 
 Return<void> GnssMeasurement::close() {
     ALOGD("close");
-    std::unique_lock<std::mutex> lock(mMutex);
     stop();
+    std::unique_lock<std::mutex> lock(mMutex);
     sCallback = nullptr;
     return Void();
 }
diff --git a/gnss/2.0/default/GnssMeasurement.h b/gnss/2.0/default/GnssMeasurement.h
index d8ffd59..73eaa13 100644
--- a/gnss/2.0/default/GnssMeasurement.h
+++ b/gnss/2.0/default/GnssMeasurement.h
@@ -61,10 +61,14 @@
     void stop();
     void reportMeasurement(const GnssData&);
 
+    // Guarded by mMutex
     static sp<IGnssMeasurementCallback> sCallback;
+
     std::atomic<long> mMinIntervalMillis;
     std::atomic<bool> mIsActive;
     std::thread mThread;
+
+    // Synchronization lock for sCallback
     mutable std::mutex mMutex;
 };
 
diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal
index 0e6abbd..60a5423 100644
--- a/gnss/2.1/IGnssMeasurementCallback.hal
+++ b/gnss/2.1/IGnssMeasurementCallback.hal
@@ -30,13 +30,13 @@
      */
     enum GnssMeasurementFlags : @1.0::IGnssMeasurementCallback.GnssMeasurementFlags {
         /**
-         * A valid receiver inter-signal bias is stored in the data structure.
+         * A valid full inter-signal bias is stored in the data structure.
          */
-        HAS_RECEIVER_ISB = 1 << 16,
+        HAS_FULL_ISB = 1 << 16,
         /**
-         * A valid receiver inter-signal bias uncertainty is stored in the data structure.
+         * A valid full inter-signal bias uncertainty is stored in the data structure.
          */
-        HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17,
+        HAS_FULL_ISB_UNCERTAINTY = 1 << 17,
         /**
          * A valid satellite inter-signal bias is stored in the data structure.
          */
@@ -77,42 +77,58 @@
         bitfield<GnssMeasurementFlags> flags;
 
         /**
-         * The receiver inter-signal bias (ISB) in nanoseconds.
+         * The full inter-signal bias (ISB) in nanoseconds.
          *
-         * This value is the estimated receiver-side inter-system (different from the constellation
-         * in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different from the
-         * carrier frequency in GnssClock.referenceSignalTypeForIsb) bias. The reported receiver ISB
-         * must include signal delays caused by
+         * This value is the sum of the estimated receiver-side and the space-segment-side
+         * inter-system bias, inter-frequency bias and inter-code bias, including
          *
-         * - Receiver inter-constellation bias
-         * - Receiver inter-frequency bias
-         * - Receiver inter-code bias
+         * - Receiver inter-constellation bias (with respect to the constellation in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Receiver inter-frequency bias (with respect to the carrier frequency in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Receiver inter-code bias (with respect to the code type in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset
+         *   (TauGps), BDS-GLO Time Offset (BGTO)) (with respect to the constellation in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Group delay (e.g., Total Group Delay (TGD))
+         * - Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the
+         *   code type in GnssClock.referenceSignalTypeForIsb)
+         *
+         * If a component of the above is already compensated in the provided
+         * GnssMeasurement.receivedSvTimeInNs, then it must not be included in the reported full
+         * ISB.
          *
          * The value does not include the inter-frequency Ionospheric bias.
          *
-         * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
+         * The full ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
          */
-        double receiverInterSignalBiasNs;
+        double fullInterSignalBiasNs;
 
         /**
-         * 1-sigma uncertainty associated with the receiver inter-signal bias in nanoseconds.
+         * 1-sigma uncertainty associated with the full inter-signal bias in nanoseconds.
          */
-        double receiverInterSignalBiasUncertaintyNs;
+        double fullInterSignalBiasUncertaintyNs;
 
         /**
          * The satellite inter-signal bias in nanoseconds.
          *
-         * This value is the satellite-and-control-segment-side inter-system (different from the
-         * constellation in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different
-         * from the carrier frequency in GnssClock.referenceSignalTypeForIsb) bias, including:
+         * This value is the sum of the space-segment-side inter-system bias, inter-frequency bias
+         * and inter-code bias, including
          *
-         * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps),
-         *   BDS-GLO Time Offset (BGTO))
+         * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset
+         *   (TauGps), BDS-GLO Time Offset (BGTO)) (with respect to the constellation in
+         *   GnssClock.referenceSignalTypeForIsb)
          * - Group delay (e.g., Total Group Delay (TGD))
-         * - Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only),
-         *   and satellite inter-code bias (e.g., Differential Code Bias (DCB)).
+         * - Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the
+         *   code type in GnssClock.referenceSignalTypeForIsb)
          *
-         * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
+         * The satellite ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0
+         * nanoseconds.
          */
         double satelliteInterSignalBiasNs;
 
diff --git a/gnss/2.1/default/GnssAntennaInfo.cpp b/gnss/2.1/default/GnssAntennaInfo.cpp
index d32a0af..ed183a9 100644
--- a/gnss/2.1/default/GnssAntennaInfo.cpp
+++ b/gnss/2.1/default/GnssAntennaInfo.cpp
@@ -55,8 +55,8 @@
 
 Return<void> GnssAntennaInfo::close() {
     ALOGD("close");
-    std::unique_lock<std::mutex> lock(mMutex);
     stop();
+    std::unique_lock<std::mutex> lock(mMutex);
     sCallback = nullptr;
     return Void();
 }
diff --git a/gnss/2.1/default/GnssAntennaInfo.h b/gnss/2.1/default/GnssAntennaInfo.h
index f4bfd24..94b2111 100644
--- a/gnss/2.1/default/GnssAntennaInfo.h
+++ b/gnss/2.1/default/GnssAntennaInfo.h
@@ -47,10 +47,14 @@
     void reportAntennaInfo(
             const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const;
 
+    // Guarded by mMutex
     static sp<IGnssAntennaInfoCallback> sCallback;
+
     std::atomic<long> mMinIntervalMillis;
     std::atomic<bool> mIsActive;
     std::thread mThread;
+
+    // Synchronization lock for sCallback
     mutable std::mutex mMutex;
 };
 
@@ -60,4 +64,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
\ No newline at end of file
+#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp
index 34e20e5..63bbc0a 100644
--- a/gnss/2.1/default/GnssMeasurement.cpp
+++ b/gnss/2.1/default/GnssMeasurement.cpp
@@ -47,8 +47,8 @@
 
 Return<void> GnssMeasurement::close() {
     ALOGD("close");
-    std::unique_lock<std::mutex> lock(mMutex);
     stop();
+    std::unique_lock<std::mutex> lock(mMutex);
     sCallback_2_1 = nullptr;
     sCallback_2_0 = nullptr;
     return Void();
diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/2.1/default/GnssMeasurement.h
index 3ed7bc5..d446419 100644
--- a/gnss/2.1/default/GnssMeasurement.h
+++ b/gnss/2.1/default/GnssMeasurement.h
@@ -66,11 +66,17 @@
     void reportMeasurement(const GnssDataV2_0&);
     void reportMeasurement(const GnssDataV2_1&);
 
+    // Guarded by mMutex
     static sp<V2_1::IGnssMeasurementCallback> sCallback_2_1;
+
+    // Guarded by mMutex
     static sp<V2_0::IGnssMeasurementCallback> sCallback_2_0;
+
     std::atomic<long> mMinIntervalMillis;
     std::atomic<bool> mIsActive;
     std::thread mThread;
+
+    // Synchronization lock for sCallback_2_1 and sCallback_2_0
     mutable std::mutex mMutex;
 };
 
diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
index 7b054c0..33feb5e 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -98,7 +98,7 @@
  * TestGnssMeasurementFields:
  * Sets a GnssMeasurementCallback, waits for a measurement, and verifies
  * 1. basebandCN0DbHz is valid
- * 2. ISB fields are valid if HAS_INTER_SIGNAL_BIAS is true.
+ * 2. ISB fields are valid
  */
 TEST_P(GnssHalTest, TestGnssMeasurementFields) {
     const int kFirstGnssMeasurementTimeoutSeconds = 10;
@@ -126,9 +126,8 @@
         // Verify basebandCn0DbHz is valid.
         ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
 
-        if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB) > 0) &&
-            ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB_UNCERTAINTY) >
-             0) &&
+        if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_FULL_ISB) > 0) &&
+            ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
             ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) > 0) &&
             ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY) >
              0)) {
@@ -143,8 +142,8 @@
             ASSERT_TRUE(carrierFrequencyHz > 0);
             ASSERT_TRUE(codeType != "");
 
-            ASSERT_TRUE(std::abs(measurement.receiverInterSignalBiasNs) < 1.0e6);
-            ASSERT_TRUE(measurement.receiverInterSignalBiasUncertaintyNs >= 0);
+            ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
+            ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
             ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
             ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
         }
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index 2e5b873..386090e 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -39,12 +39,12 @@
             .v2_0 = gnssDataV2_0.measurements[0],
             .flags = (uint32_t)(GnssMeasurementFlagsV2_1::HAS_CARRIER_FREQUENCY |
                                 GnssMeasurementFlagsV2_1::HAS_CARRIER_PHASE |
-                                GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB |
-                                GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB_UNCERTAINTY |
+                                GnssMeasurementFlagsV2_1::HAS_FULL_ISB |
+                                GnssMeasurementFlagsV2_1::HAS_FULL_ISB_UNCERTAINTY |
                                 GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB |
                                 GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB_UNCERTAINTY),
-            .receiverInterSignalBiasNs = 10.0,
-            .receiverInterSignalBiasUncertaintyNs = 100.0,
+            .fullInterSignalBiasNs = 30.0,
+            .fullInterSignalBiasUncertaintyNs = 250.0,
             .satelliteInterSignalBiasNs = 20.0,
             .satelliteInterSignalBiasUncertaintyNs = 150.0,
             .basebandCN0DbHz = 25.0,
diff --git a/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal b/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal
index 5a582c2..5ee2923 100644
--- a/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal
+++ b/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal
@@ -82,6 +82,9 @@
         /**
          * Package name of the Android proxy application representing the non-framework
          * entity that requested location. Set to empty string if unknown.
+         *
+         * For user-initiated emergency use cases, this field must be set to empty string
+         * and the inEmergencyMode field must be set to true.
          */
         string proxyAppPackageName;
 
@@ -157,4 +160,4 @@
      * @return success True if the framework determines that the device is in emergency session.
      */
     isInEmergencySession() generates (bool success);
-};
\ No newline at end of file
+};
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
index 4942462..4e0c5ef 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
@@ -403,10 +403,6 @@
      *   cr_offset = y_size
      *   cb_offset = y_size + c_size
      *
-     * This range is reserved for vendor extensions. Formats in this range
-     * must support BufferUsage::GPU_TEXTURE. Clients must assume they do not
-     * have an alpha component.
-     *
      * This format must be accepted by the allocator when used with the
      * following usage flags:
      *
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
index 3fca53b..c04cef0 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
@@ -39,7 +39,7 @@
     /**
      * The type of this plane layout component.
      *
-     * android.hardware.graphics.common.PlaneLayoutComponent defines the standard
+     * android.hardware.graphics.common.PlaneLayoutComponentType defines the standard
      * plane layout component types. Vendors may extend this type to include any
      * non-standard plane layout component types. For instructions on how to
      * create a vendor extension, refer to ExtendableType.aidl.
diff --git a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
index 1185945..3d792f9 100644
--- a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
+++ b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
@@ -94,7 +94,7 @@
                                                     mDummyDescriptorInfo.width);
     ASSERT_EQ(Error::BAD_BUFFER, ret)
         << "validateBufferSize with raw buffer handle did not fail with BAD_BUFFER";
-    native_handle_delete(rawBufferHandle);
+    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawBufferHandle));
 }
 
 /**
@@ -179,11 +179,11 @@
     ASSERT_NO_FATAL_FAILURE(rawBufferHandle = const_cast<native_handle_t*>(
                                 mGralloc->allocate(mDummyDescriptorInfo, false)));
     mGralloc->getMapper()->getTransportSize(
-        invalidHandle, [&](const auto& tmpError, const auto&, const auto&) {
-            ASSERT_EQ(Error::BAD_BUFFER, tmpError)
-                << "getTransportSize with raw buffer handle did not fail with BAD_BUFFER";
-        });
-    native_handle_delete(rawBufferHandle);
+            rawBufferHandle, [&](const auto& tmpError, const auto&, const auto&) {
+                ASSERT_EQ(Error::BAD_BUFFER, tmpError)
+                        << "getTransportSize with raw buffer handle did not fail with BAD_BUFFER";
+            });
+    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawBufferHandle));
 }
 
 /**
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 6cc5e34..a783eaa 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -2124,8 +2124,14 @@
 
         Error err;
         mGralloc->getAllocator()->allocate(
-                descriptor, 1,
-                [&](const auto& tmpError, const auto&, const auto&) { err = tmpError; });
+                descriptor, 1, [&](const auto& tmpError, const auto&, const auto& tmpBuffers) {
+                    err = tmpError;
+                    if (err == Error::NONE) {
+                        ASSERT_EQ(1, tmpBuffers.size());
+                        ASSERT_NO_FATAL_FAILURE(bufferHandle =
+                                                        mGralloc->importBuffer(tmpBuffers[0]));
+                    }
+                });
         if (err == Error::UNSUPPORTED) {
             continue;
         }
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 10ce4c2..cc14271 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -176,6 +176,10 @@
      * @param itemsRequest
      *   If non-empty, contains request data that is signed by the reader. See above.
      *
+     * @param signingKeyBlob is either empty or a signingKeyBlob (see generateSigningKeyPair(),
+     *    below) containing the signing key to use to sign the data retrieved. If this
+     *    is not in the right format the call fails with STATUS_INVALID_DATA.
+     *
      * @param sessionTranscript
      *   Either empty or the CBOR of the SessionTranscript. See above.
      *
@@ -195,8 +199,7 @@
      *   and remove the corresponding requests from the counts.
      */
     void startRetrieval(in SecureAccessControlProfile[] accessControlProfiles,
-        in HardwareAuthToken authToken,
-        in byte[] itemsRequest,
+        in HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob,
         in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
 
     /**
@@ -254,10 +257,6 @@
      * If signingKeyBlob or the sessionTranscript parameter passed to startRetrieval() is
      * empty then the returned MAC will be empty.
      *
-     * @param signingKeyBlob is either empty or a signingKeyBlob (see generateSigningKeyPair(),
-     *    below) containing the signing key to use to sign the data retrieved. If this
-     *    is not in the right format the call fails with STATUS_INVALID_DATA.
-     *
      * @param out mac is empty if signingKeyBlob or the sessionTranscript passed to
      *    startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload
      *    and the detached content is set to DeviceAuthentication as defined below.
@@ -304,7 +303,7 @@
      *
      * @param out deviceNameSpaces the bytes of DeviceNameSpaces.
      */
-    void finishRetrieval(in byte[] signingKeyBlob, out byte[] mac, out byte[] deviceNameSpaces);
+    void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
 
     /**
      * Generate a key pair to be used for signing session data and retrieved data items.
diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp
index d5b3a0f..341fae6 100644
--- a/identity/aidl/default/IdentityCredential.cpp
+++ b/identity/aidl/default/IdentityCredential.cpp
@@ -256,8 +256,8 @@
 ndk::ScopedAStatus IdentityCredential::startRetrieval(
         const vector<SecureAccessControlProfile>& accessControlProfiles,
         const HardwareAuthToken& authToken, const vector<int8_t>& itemsRequestS,
-        const vector<int8_t>& sessionTranscriptS, const vector<int8_t>& readerSignatureS,
-        const vector<int32_t>& requestCounts) {
+        const vector<int8_t>& signingKeyBlobS, const vector<int8_t>& sessionTranscriptS,
+        const vector<int8_t>& readerSignatureS, const vector<int32_t>& requestCounts) {
     auto sessionTranscript = byteStringToUnsigned(sessionTranscriptS);
     auto itemsRequest = byteStringToUnsigned(itemsRequestS);
     auto readerSignature = byteStringToUnsigned(readerSignatureS);
@@ -498,6 +498,7 @@
     currentNameSpace_ = "";
 
     itemsRequest_ = itemsRequest;
+    signingKeyBlob_ = byteStringToUnsigned(signingKeyBlobS);
 
     numStartRetrievalCalls_ += 1;
     return ndk::ScopedAStatus::ok();
@@ -650,11 +651,8 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus IdentityCredential::finishRetrieval(const vector<int8_t>& signingKeyBlobS,
-                                                       vector<int8_t>* outMac,
+ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<int8_t>* outMac,
                                                        vector<int8_t>* outDeviceNameSpaces) {
-    auto signingKeyBlob = byteStringToUnsigned(signingKeyBlobS);
-
     if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) {
         deviceNameSpacesMap_.add(currentNameSpace_,
                                  std::move(currentNameSpaceDeviceNameSpacesMap_));
@@ -664,7 +662,8 @@
     // If there's no signing key or no sessionTranscript or no reader ephemeral
     // public key, we return the empty MAC.
     optional<vector<uint8_t>> mac;
-    if (signingKeyBlob.size() > 0 && sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0) {
+    if (signingKeyBlob_.size() > 0 && sessionTranscript_.size() > 0 &&
+        readerPublicKey_.size() > 0) {
         cppbor::Array array;
         array.add("DeviceAuthentication");
         array.add(sessionTranscriptItem_->clone());
@@ -674,7 +673,7 @@
 
         vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
         optional<vector<uint8_t>> signingKey =
-                support::decryptAes128Gcm(storageKey_, signingKeyBlob, docTypeAsBlob);
+                support::decryptAes128Gcm(storageKey_, signingKeyBlob_, docTypeAsBlob);
         if (!signingKey) {
             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                     IIdentityCredentialStore::STATUS_INVALID_DATA,
diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h
index 49ed0d4..fc29254 100644
--- a/identity/aidl/default/IdentityCredential.h
+++ b/identity/aidl/default/IdentityCredential.h
@@ -54,14 +54,14 @@
     ndk::ScopedAStatus startRetrieval(
             const vector<SecureAccessControlProfile>& accessControlProfiles,
             const HardwareAuthToken& authToken, const vector<int8_t>& itemsRequest,
-            const vector<int8_t>& sessionTranscript, const vector<int8_t>& readerSignature,
-            const vector<int32_t>& requestCounts) override;
+            const vector<int8_t>& signingKeyBlob, const vector<int8_t>& sessionTranscript,
+            const vector<int8_t>& readerSignature, const vector<int32_t>& requestCounts) override;
     ndk::ScopedAStatus startRetrieveEntryValue(
             const string& nameSpace, const string& name, int32_t entrySize,
             const vector<int32_t>& accessControlProfileIds) override;
     ndk::ScopedAStatus retrieveEntryValue(const vector<int8_t>& encryptedContent,
                                           vector<int8_t>* outContent) override;
-    ndk::ScopedAStatus finishRetrieval(const vector<int8_t>& signingKeyBlob, vector<int8_t>* outMac,
+    ndk::ScopedAStatus finishRetrieval(vector<int8_t>* outMac,
                                        vector<int8_t>* outDeviceNameSpaces) override;
     ndk::ScopedAStatus generateSigningKeyPair(vector<int8_t>* outSigningKeyBlob,
                                               Certificate* outSigningKeyCertificate) override;
@@ -88,6 +88,7 @@
 
     // Set at startRetrieval() time.
     map<int32_t, int> profileIdToAccessCheckResult_;
+    vector<uint8_t> signingKeyBlob_;
     vector<uint8_t> sessionTranscript_;
     std::unique_ptr<cppbor::Item> sessionTranscriptItem_;
     vector<uint8_t> itemsRequest_;
diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp
index ba2062d..89f7f35 100644
--- a/identity/aidl/default/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/WritableIdentityCredential.cpp
@@ -16,6 +16,9 @@
 
 #define LOG_TAG "WritableIdentityCredential"
 
+#include "WritableIdentityCredential.h"
+#include "IdentityCredentialStore.h"
+
 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
 
 #include <android-base/logging.h>
@@ -23,6 +26,8 @@
 #include <cppbor/cppbor.h>
 #include <cppbor/cppbor_parse.h>
 
+#include <utility>
+
 #include "IdentityCredentialStore.h"
 #include "Util.h"
 #include "WritableIdentityCredential.h"
@@ -33,26 +38,6 @@
 using namespace ::android::hardware::identity;
 
 bool WritableIdentityCredential::initialize() {
-    optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
-    if (!keyPair) {
-        LOG(ERROR) << "Error creating credentialKey";
-        return false;
-    }
-
-    optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
-    if (!pubKey) {
-        LOG(ERROR) << "Error getting public part of credentialKey";
-        return false;
-    }
-    credentialPubKey_ = pubKey.value();
-
-    optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
-    if (!privKey) {
-        LOG(ERROR) << "Error getting private part of credentialKey";
-        return false;
-    }
-    credentialPrivKey_ = privKey.value();
-
     optional<vector<uint8_t>> random = support::getRandom(16);
     if (!random) {
         LOG(ERROR) << "Error creating storageKey";
@@ -63,88 +48,54 @@
     return true;
 }
 
-// TODO: use |attestationApplicationId| and |attestationChallenge| and also
-//       ensure the returned certificate chain satisfy the requirements listed in
-//       the docs for IWritableIdentityCredential::getAttestationCertificate()
-//
+// This function generates the attestation certificate using the passed in
+// |attestationApplicationId| and |attestationChallenge|.  It will generate an
+// attestation certificate with current time and expires one year from now.  The
+// certificate shall contain all values as specified in hal.
 ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate(
-        const vector<int8_t>& /*attestationApplicationId*/,
-        const vector<int8_t>& /*attestationChallenge*/, vector<Certificate>* outCertificateChain) {
-    // For now, we dynamically generate an attestion key on each and every
-    // request and use that to sign CredentialKey. In a real implementation this
-    // would look very differently.
-    optional<vector<uint8_t>> attestationKeyPair = support::createEcKeyPair();
-    if (!attestationKeyPair) {
-        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                IIdentityCredentialStore::STATUS_FAILED, "Error creating attestationKey"));
-    }
-
-    optional<vector<uint8_t>> attestationPubKey =
-            support::ecKeyPairGetPublicKey(attestationKeyPair.value());
-    if (!attestationPubKey) {
+        const vector<int8_t>& attestationApplicationId,  //
+        const vector<int8_t>& attestationChallenge,      //
+        vector<Certificate>* outCertificateChain) {
+    if (!credentialPrivKey_.empty() || !credentialPubKey_.empty() || !certificateChain_.empty()) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
-                "Error getting public part of attestationKey"));
+                "Error attestation certificate previously generated"));
     }
 
-    optional<vector<uint8_t>> attestationPrivKey =
-            support::ecKeyPairGetPrivateKey(attestationKeyPair.value());
-    if (!attestationPrivKey) {
+    vector<uint8_t> challenge(attestationChallenge.begin(), attestationChallenge.end());
+    vector<uint8_t> appId(attestationApplicationId.begin(), attestationApplicationId.end());
+
+    optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> keyAttestationPair =
+            support::createEcKeyPairAndAttestation(challenge, appId);
+    if (!keyAttestationPair) {
+        LOG(ERROR) << "Error creating credentialKey and attestation";
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
-                "Error getting private part of attestationKey"));
+                "Error creating credentialKey and attestation"));
     }
 
-    string serialDecimal;
-    string issuer;
-    string subject;
-    time_t validityNotBefore = time(nullptr);
-    time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
+    vector<uint8_t> keyPair = keyAttestationPair.value().first;
+    certificateChain_ = keyAttestationPair.value().second;
 
-    // First create a certificate for |credentialPubKey| which is signed by
-    // |attestationPrivKey|.
-    //
-    serialDecimal = "0";  // TODO: set serial to |attestationChallenge|
-    issuer = "Android Open Source Project";
-    subject = "Android IdentityCredential CredentialKey";
-    optional<vector<uint8_t>> credentialPubKeyCertificate = support::ecPublicKeyGenerateCertificate(
-            credentialPubKey_, attestationPrivKey.value(), serialDecimal, issuer, subject,
-            validityNotBefore, validityNotAfter);
-    if (!credentialPubKeyCertificate) {
+    optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair);
+    if (!pubKey) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
-                "Error creating certificate for credentialPubKey"));
+                "Error getting public part of credentialKey"));
     }
+    credentialPubKey_ = pubKey.value();
 
-    // This is followed by a certificate for |attestationPubKey| self-signed by
-    // |attestationPrivKey|.
-    serialDecimal = "0";  // TODO: set serial
-    issuer = "Android Open Source Project";
-    subject = "Android IdentityCredential AttestationKey";
-    optional<vector<uint8_t>> attestationKeyCertificate = support::ecPublicKeyGenerateCertificate(
-            attestationPubKey.value(), attestationPrivKey.value(), serialDecimal, issuer, subject,
-            validityNotBefore, validityNotAfter);
-    if (!attestationKeyCertificate) {
+    optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair);
+    if (!privKey) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
-                "Error creating certificate for attestationPubKey"));
+                "Error getting private part of credentialKey"));
     }
+    credentialPrivKey_ = privKey.value();
 
-    // Concatenate the certificates to form the chain.
-    vector<uint8_t> certificateChain;
-    certificateChain.insert(certificateChain.end(), credentialPubKeyCertificate.value().begin(),
-                            credentialPubKeyCertificate.value().end());
-    certificateChain.insert(certificateChain.end(), attestationKeyCertificate.value().begin(),
-                            attestationKeyCertificate.value().end());
-
-    optional<vector<vector<uint8_t>>> splitCertChain =
-            support::certificateChainSplit(certificateChain);
-    if (!splitCertChain) {
-        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                IIdentityCredentialStore::STATUS_FAILED, "Error splitting certificate chain"));
-    }
+    // convert from vector<vector<uint8_t>>> to vector<Certificate>*
     *outCertificateChain = vector<Certificate>();
-    for (const vector<uint8_t>& cert : splitCertChain.value()) {
+    for (const vector<uint8_t>& cert : certificateChain_) {
         Certificate c = Certificate();
         c.encodedCertificate = byteStringToSigned(cert);
         outCertificateChain->push_back(std::move(c));
diff --git a/identity/aidl/default/WritableIdentityCredential.h b/identity/aidl/default/WritableIdentityCredential.h
index b380f89..b182862 100644
--- a/identity/aidl/default/WritableIdentityCredential.h
+++ b/identity/aidl/default/WritableIdentityCredential.h
@@ -64,10 +64,13 @@
     string docType_;
     bool testCredential_;
 
-    // These are set in initialize().
+    // This is set in initialize().
     vector<uint8_t> storageKey_;
+
+    // These are set in getAttestationCertificate().
     vector<uint8_t> credentialPrivKey_;
     vector<uint8_t> credentialPubKey_;
+    vector<vector<uint8_t>> certificateChain_;
 
     // These fields are initialized during startPersonalization()
     size_t numAccessControlProfileRemaining_;
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 21ff440..cecc814 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -7,10 +7,11 @@
     srcs: ["VtsHalIdentityTargetTest.cpp"],
     shared_libs: [
         "libbinder",
-        "libcppbor",
-        "android.hardware.identity-support-lib",
+        "libcrypto",
     ],
     static_libs: [
+        "libcppbor",
+        "android.hardware.identity-support-lib",
         "android.hardware.identity-cpp",
         "android.hardware.keymaster-cpp",
     ],
diff --git a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp b/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
index 5abe5a2..ea37fdc 100644
--- a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
+++ b/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
@@ -352,10 +352,15 @@
                                    readerCertificate.value());
     ASSERT_TRUE(readerSignature);
 
+    // Generate the key that will be used to sign AuthenticatedData.
+    vector<uint8_t> signingKeyBlob;
+    Certificate signingKeyCertificate;
+    ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
+
     ASSERT_TRUE(credential
                         ->startRetrieval(returnedSecureProfiles, authToken, itemsRequestBytes,
-                                         sessionTranscriptBytes, readerSignature.value(),
-                                         testEntriesEntryCounts)
+                                         signingKeyBlob, sessionTranscriptBytes,
+                                         readerSignature.value(), testEntriesEntryCounts)
                         .isOk());
 
     for (const auto& entry : testEntries) {
@@ -377,14 +382,9 @@
         EXPECT_EQ(content, entry.valueCbor);
     }
 
-    // Generate the key that will be used to sign AuthenticatedData.
-    vector<uint8_t> signingKeyBlob;
-    Certificate signingKeyCertificate;
-    ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
-
     vector<uint8_t> mac;
     vector<uint8_t> deviceNameSpacesBytes;
-    ASSERT_TRUE(credential->finishRetrieval(signingKeyBlob, &mac, &deviceNameSpacesBytes).isOk());
+    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
     cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
     ASSERT_EQ(
             "{\n"
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index 7b4546b..2b6c695 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -23,10 +23,14 @@
         "include",
     ],
     shared_libs: [
+        "android.hardware.keymaster@4.0",
         "libcrypto",
         "libbase",
         "libhidlbase",
         "libhardware",
+        "libkeymaster_portable",
+        "libsoft_attestation_cert",
+        "libpuresoftkeymasterdevice",
     ],
     static_libs: [
         "libcppbor",
diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
index 4533ad9..507e914 100644
--- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
+++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
@@ -21,6 +21,7 @@
 #include <optional>
 #include <string>
 #include <tuple>
+#include <utility>
 #include <vector>
 
 namespace android {
@@ -106,6 +107,17 @@
 // ---------------------------------------------------------------------------
 // EC crypto functionality / abstraction (only supports P-256).
 // ---------------------------------------------------------------------------
+// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
+// PKCS#8 encoded key-pair.  Also generates an attestation
+// certificate using the |challenge| and |applicationId|, and returns the generated
+// certificate in X.509 certificate chain format.
+//
+// The attestation time fields used will be the current time, and expires in one year.
+//
+// The first parameter of the return value is the keyPair generated, second return in
+// the pair is the attestation certificate generated.
+optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
+        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId);
 
 // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
 // PKCS#8 encoded key-pair.
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index e2828bf..bf6a5c3 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -47,6 +47,13 @@
 #include <cppbor.h>
 #include <cppbor_parse.h>
 
+#include <android/hardware/keymaster/4.0/types.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <keymaster/contexts/soft_attestation_cert.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/km_openssl/attestation_utils.h>
+
 namespace android {
 namespace hardware {
 namespace identity {
@@ -816,6 +823,138 @@
     return hmac;
 }
 
+// Generates the attestation certificate with the parameters passed in.  Note
+// that the passed in |activeTimeMilliSeconds| |expireTimeMilliSeconds| are in
+// milli seconds since epoch.  We are setting them to milliseconds due to
+// requirement in AuthorizationSet KM_DATE fields.  The certificate created is
+// actually in seconds.
+optional<vector<vector<uint8_t>>> createAttestation(const EVP_PKEY* key,
+                                                    const vector<uint8_t>& applicationId,
+                                                    const vector<uint8_t>& challenge,
+                                                    uint64_t activeTimeMilliSeconds,
+                                                    uint64_t expireTimeMilliSeconds) {
+    ::keymaster::AuthorizationSet auth_set(
+            ::keymaster::AuthorizationSetBuilder()
+                    .Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(),
+                                   challenge.size())
+                    .Authorization(::keymaster::TAG_ACTIVE_DATETIME, activeTimeMilliSeconds)
+                    // Even though identity attestation hal said the application
+                    // id should be in software enforced authentication set,
+                    // keymaster portable lib expect the input in this
+                    // parameter because the software enforced in input to keymaster
+                    // refers to the key software enforced properties. And this
+                    // parameter refers to properties of the attestation which
+                    // includes app id.
+                    .Authorization(::keymaster::TAG_ATTESTATION_APPLICATION_ID,
+                                   applicationId.data(), applicationId.size())
+                    .Authorization(::keymaster::TAG_USAGE_EXPIRE_DATETIME, expireTimeMilliSeconds));
+
+    // Unique id and device id is not applicable for identity credential attestation,
+    // so we don't need to set those or application id.
+    ::keymaster::AuthorizationSet swEnforced(::keymaster::AuthorizationSetBuilder().Authorization(
+            ::keymaster::TAG_CREATION_DATETIME, activeTimeMilliSeconds));
+
+    ::keymaster::AuthorizationSet hwEnforced(
+            ::keymaster::AuthorizationSetBuilder()
+                    .Authorization(::keymaster::TAG_PURPOSE, KM_PURPOSE_SIGN)
+                    .Authorization(::keymaster::TAG_KEY_SIZE, 256)
+                    .Authorization(::keymaster::TAG_ALGORITHM, KM_ALGORITHM_EC)
+                    .Authorization(::keymaster::TAG_NO_AUTH_REQUIRED)
+                    .Authorization(::keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256)
+                    .Authorization(::keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256)
+                    .Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
+
+    const keymaster_cert_chain_t* attestation_chain =
+            ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr);
+
+    if (attestation_chain == nullptr) {
+        LOG(ERROR) << "Error getting attestation chain";
+        return {};
+    }
+
+    const keymaster_key_blob_t* attestation_signing_key =
+            ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
+    if (attestation_signing_key == nullptr) {
+        LOG(ERROR) << "Error getting attestation key";
+        return {};
+    }
+
+    keymaster_error_t error;
+    ::keymaster::CertChainPtr cert_chain_out;
+    ::keymaster::PureSoftKeymasterContext context;
+
+    // set identity version to 10 per hal requirements specified in IWriteableCredential.hal
+    // For now, the identity version in the attestation is set in the keymaster
+    // version field in the portable keymaster lib, which is a bit misleading.
+    uint identity_version = 10;
+    error = generate_attestation_from_EVP(key, swEnforced, hwEnforced, auth_set, context,
+                                          identity_version, *attestation_chain,
+                                          *attestation_signing_key, &cert_chain_out);
+
+    if (KM_ERROR_OK != error || !cert_chain_out) {
+        LOG(ERROR) << "Error generate attestation from EVP key" << error;
+        return {};
+    }
+
+    // translate certificate format from keymaster_cert_chain_t to vector<uint8_t>.
+    vector<vector<uint8_t>> attestationCertificate;
+    for (int i = 0; i < cert_chain_out->entry_count; i++) {
+        attestationCertificate.insert(
+                attestationCertificate.end(),
+                vector<uint8_t>(
+                        cert_chain_out->entries[i].data,
+                        cert_chain_out->entries[i].data + cert_chain_out->entries[i].data_length));
+    }
+
+    return attestationCertificate;
+}
+
+optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
+        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) {
+    auto ec_key = ::keymaster::EC_KEY_Ptr(EC_KEY_new());
+    auto pkey = ::keymaster::EVP_PKEY_Ptr(EVP_PKEY_new());
+    auto group = ::keymaster::EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+
+    if (ec_key.get() == nullptr || pkey.get() == nullptr) {
+        LOG(ERROR) << "Memory allocation failed";
+        return {};
+    }
+
+    if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
+        EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
+        LOG(ERROR) << "Error generating key";
+        return {};
+    }
+
+    if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1) {
+        LOG(ERROR) << "Error getting private key";
+        return {};
+    }
+
+    uint64_t now = time(nullptr);
+    uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
+    uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+
+    optional<vector<vector<uint8_t>>> attestationCert =
+            createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+    if (!attestationCert) {
+        LOG(ERROR) << "Error create attestation from key and challenge";
+        return {};
+    }
+
+    int size = i2d_PrivateKey(pkey.get(), nullptr);
+    if (size == 0) {
+        LOG(ERROR) << "Error generating public key encoding";
+        return {};
+    }
+
+    vector<uint8_t> keyPair(size);
+    unsigned char* p = keyPair.data();
+    i2d_PrivateKey(pkey.get(), &p);
+
+    return make_pair(keyPair, attestationCert.value());
+}
+
 optional<vector<uint8_t>> createEcKeyPair() {
     auto ec_key = EC_KEY_Ptr(EC_KEY_new());
     auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
index 6c186f6..40eb142 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -101,6 +101,7 @@
 DECLARE_KM_4_1_TYPED_TAG(EARLY_BOOT_ONLY);
 DECLARE_KM_4_1_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION);
 DECLARE_KM_4_1_TYPED_TAG(STORAGE_KEY);
+DECLARE_KM_4_1_TYPED_TAG(IDENTITY_CREDENTIAL_KEY);
 
 }  // namespace android::hardware::keymaster::V4_1
 
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index e28605d..ae1e3a2 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -125,7 +125,9 @@
 // Test driver for those generated from ml/nn/runtime/test/spec
 void Execute(const sp<IDevice>& device, const TestModel& testModel) {
     const Model model = createModel(testModel);
-    const Request request = createRequest(testModel);
+
+    ExecutionContext context;
+    const Request request = context.createRequest(testModel);
 
     // Create IPreparedModel.
     sp<IPreparedModel> preparedModel;
@@ -143,7 +145,7 @@
     ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
 
     // Retrieve execution results.
-    const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+    const std::vector<TestBuffer> outputs = context.getOutputBuffers(request);
 
     // We want "close-enough" results.
     checkResults(testModel, outputs);
@@ -158,6 +160,10 @@
     return TestModelManager::get().getTestModels(filter);
 }
 
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
+}
+
 std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
     const auto& [namedDevice, namedModel] = info.param;
     return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
index f230a02..1a55c2f 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
@@ -37,6 +37,9 @@
 using FilterFn = std::function<bool(const test_helper::TestModel&)>;
 std::vector<NamedModel> getNamedModels(const FilterFn& filter);
 
+using FilterNameFn = std::function<bool(const std::string&)>;
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter);
+
 std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
 
 #define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp
index 0dba85a..3613e69 100644
--- a/neuralnetworks/1.0/vts/functional/Utils.cpp
+++ b/neuralnetworks/1.0/vts/functional/Utils.cpp
@@ -21,10 +21,13 @@
 
 #include <android-base/logging.h>
 #include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware_buffer.h>
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMemory.h>
 #include <hidlmemory/mapping.h>
+#include <vndk/hardware_buffer.h>
 
+#include <gtest/gtest.h>
 #include <algorithm>
 #include <iostream>
 #include <vector>
@@ -37,10 +40,64 @@
 using V1_0::Request;
 using V1_0::RequestArgument;
 
-constexpr uint32_t kInputPoolIndex = 0;
-constexpr uint32_t kOutputPoolIndex = 1;
+std::unique_ptr<TestAshmem> TestAshmem::create(uint32_t size) {
+    auto ashmem = std::make_unique<TestAshmem>(size);
+    return ashmem->mIsValid ? std::move(ashmem) : nullptr;
+}
 
-Request createRequest(const TestModel& testModel) {
+void TestAshmem::initialize(uint32_t size) {
+    mIsValid = false;
+    ASSERT_GT(size, 0);
+    mHidlMemory = nn::allocateSharedMemory(size);
+    ASSERT_TRUE(mHidlMemory.valid());
+    mMappedMemory = mapMemory(mHidlMemory);
+    ASSERT_NE(mMappedMemory, nullptr);
+    mPtr = static_cast<uint8_t*>(static_cast<void*>(mMappedMemory->getPointer()));
+    ASSERT_NE(mPtr, nullptr);
+    mIsValid = true;
+}
+
+std::unique_ptr<TestBlobAHWB> TestBlobAHWB::create(uint32_t size) {
+    auto ahwb = std::make_unique<TestBlobAHWB>(size);
+    return ahwb->mIsValid ? std::move(ahwb) : nullptr;
+}
+
+void TestBlobAHWB::initialize(uint32_t size) {
+    mIsValid = false;
+    ASSERT_GT(size, 0);
+    const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+    const AHardwareBuffer_Desc desc = {
+            .width = size,
+            .height = 1,
+            .layers = 1,
+            .format = AHARDWAREBUFFER_FORMAT_BLOB,
+            .usage = usage,
+            .stride = size,
+    };
+    ASSERT_EQ(AHardwareBuffer_allocate(&desc, &mAhwb), 0);
+    ASSERT_NE(mAhwb, nullptr);
+
+    void* buffer = nullptr;
+    ASSERT_EQ(AHardwareBuffer_lock(mAhwb, usage, -1, nullptr, &buffer), 0);
+    ASSERT_NE(buffer, nullptr);
+    mPtr = static_cast<uint8_t*>(buffer);
+
+    const native_handle_t* handle = AHardwareBuffer_getNativeHandle(mAhwb);
+    ASSERT_NE(handle, nullptr);
+    mHidlMemory = hidl_memory("hardware_buffer_blob", handle, desc.width);
+    mIsValid = true;
+}
+
+TestBlobAHWB::~TestBlobAHWB() {
+    if (mAhwb) {
+        AHardwareBuffer_unlock(mAhwb, nullptr);
+        AHardwareBuffer_release(mAhwb);
+    }
+}
+
+Request ExecutionContext::createRequest(const TestModel& testModel, MemoryType memoryType) {
+    CHECK(memoryType == MemoryType::ASHMEM || memoryType == MemoryType::BLOB_AHWB);
+
     // Model inputs.
     hidl_vec<RequestArgument> inputs(testModel.main.inputIndexes.size());
     size_t inputSize = 0;
@@ -80,16 +137,19 @@
     }
 
     // Allocate memory pools.
-    hidl_vec<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
-                                   nn::allocateSharedMemory(outputSize)};
-    CHECK_NE(pools[kInputPoolIndex].size(), 0u);
-    CHECK_NE(pools[kOutputPoolIndex].size(), 0u);
-    sp<IMemory> inputMemory = mapMemory(pools[kInputPoolIndex]);
-    CHECK(inputMemory.get() != nullptr);
-    uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
-    CHECK(inputPtr != nullptr);
+    if (memoryType == MemoryType::ASHMEM) {
+        mInputMemory = TestAshmem::create(inputSize);
+        mOutputMemory = TestAshmem::create(outputSize);
+    } else {
+        mInputMemory = TestBlobAHWB::create(inputSize);
+        mOutputMemory = TestBlobAHWB::create(outputSize);
+    }
+    EXPECT_NE(mInputMemory, nullptr);
+    EXPECT_NE(mOutputMemory, nullptr);
+    hidl_vec<hidl_memory> pools = {mInputMemory->getHidlMemory(), mOutputMemory->getHidlMemory()};
 
     // Copy input data to the memory pool.
+    uint8_t* inputPtr = mInputMemory->getPointer();
     for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
         const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
         if (op.data.size() > 0) {
@@ -102,18 +162,13 @@
     return {.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
 }
 
-std::vector<TestBuffer> getOutputBuffers(const Request& request) {
-    sp<IMemory> outputMemory = mapMemory(request.pools[kOutputPoolIndex]);
-    CHECK(outputMemory.get() != nullptr);
-    uint8_t* outputPtr = static_cast<uint8_t*>(static_cast<void*>(outputMemory->getPointer()));
-    CHECK(outputPtr != nullptr);
-
+std::vector<TestBuffer> ExecutionContext::getOutputBuffers(const Request& request) const {
     // Copy out output results.
+    uint8_t* outputPtr = mOutputMemory->getPointer();
     std::vector<TestBuffer> outputBuffers;
     for (const auto& output : request.outputs) {
         outputBuffers.emplace_back(output.location.length, outputPtr + output.location.offset);
     }
-
     return outputBuffers;
 }
 
diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
index cc15263..79d8594 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
@@ -24,6 +24,8 @@
 
 using implementation::PreparedModelCallback;
 
+using PrepareModelMutation = std::function<void(Model*)>;
+
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
 static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
@@ -54,12 +56,13 @@
 }
 
 // Primary validation function. This function will take a valid model, apply a
-// mutation to it to invalidate the model, then pass it to interface calls that
-// use the model. Note that the model here is passed by value, and any mutation
-// to the model does not leave this function.
-static void validate(const sp<IDevice>& device, const std::string& message, Model model,
-                     const std::function<void(Model*)>& mutation) {
-    mutation(&model);
+// mutation to invalidate the model, then pass these to supportedOperations and
+// prepareModel.
+static void validate(const sp<IDevice>& device, const std::string& message,
+                     const Model& originalModel, const PrepareModelMutation& mutate) {
+    Model model = originalModel;
+    mutate(&model);
+
     validateGetSupportedOperations(device, message, model);
     validatePrepareModel(device, message, model);
 }
diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
index 05eefd1..0baa85b 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
@@ -24,15 +24,17 @@
 
 using implementation::ExecutionCallback;
 
+using ExecutionMutation = std::function<void(Request*)>;
+
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
 // Primary validation function. This function will take a valid request, apply a
 // mutation to it to invalidate the request, then pass it to interface calls
-// that use the request. Note that the request here is passed by value, and any
-// mutation to the request does not leave this function.
+// that use the request.
 static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
-                     Request request, const std::function<void(Request*)>& mutation) {
-    mutation(&request);
+                     const Request& originalRequest, const ExecutionMutation& mutate) {
+    Request request = originalRequest;
+    mutate(&request);
     SCOPED_TRACE(message + " [execute]");
 
     sp<ExecutionCallback> executionCallback = new ExecutionCallback();
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
index cb22250..2c17796 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
@@ -129,11 +129,17 @@
 
 TEST_P(ValidationTest, Test) {
     const Model model = createModel(kTestModel);
-    const Request request = createRequest(kTestModel);
+    ExecutionContext context;
+    const Request request = context.createRequest(kTestModel);
     ASSERT_FALSE(kTestModel.expectFailure);
     validateEverything(kDevice, model, request);
 }
 
-INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) {
+    // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs"
+    // generated tests.
+    return testName.find("inputs_as_internal") == std::string::npos &&
+           testName.find("all_tensors_as_inputs") == std::string::npos;
+});
 
 }  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
index 6d4534c..3292f79 100644
--- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
@@ -19,6 +19,8 @@
 
 #include <android-base/logging.h>
 #include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware_buffer.h>
+#include <android/hidl/memory/1.0/IMemory.h>
 #include <algorithm>
 #include <iosfwd>
 #include <string>
@@ -28,11 +30,73 @@
 
 namespace android::hardware::neuralnetworks {
 
-// Create HIDL Request from the TestModel struct.
-V1_0::Request createRequest(const test_helper::TestModel& testModel);
+// Convenience class to manage the lifetime of memory resources.
+class TestMemoryBase {
+    DISALLOW_COPY_AND_ASSIGN(TestMemoryBase);
 
-// After execution, copy out output results from the output memory pool.
-std::vector<::test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request);
+  public:
+    TestMemoryBase() = default;
+    virtual ~TestMemoryBase() = default;
+    uint8_t* getPointer() const { return mPtr; }
+    hidl_memory getHidlMemory() const { return mHidlMemory; }
+
+  protected:
+    uint8_t* mPtr = nullptr;
+    hidl_memory mHidlMemory;
+    bool mIsValid = false;
+};
+
+class TestAshmem : public TestMemoryBase {
+  public:
+    static std::unique_ptr<TestAshmem> create(uint32_t size);
+
+    // Prefer TestAshmem::create.
+    // The constructor calls initialize, which constructs the memory resources. This is a workaround
+    // that gtest macros cannot be used directly in a constructor.
+    TestAshmem(uint32_t size) { initialize(size); }
+
+  private:
+    void initialize(uint32_t size);
+    sp<hidl::memory::V1_0::IMemory> mMappedMemory;
+};
+
+class TestBlobAHWB : public TestMemoryBase {
+  public:
+    static std::unique_ptr<TestBlobAHWB> create(uint32_t size);
+
+    // Prefer TestBlobAHWB::create.
+    // The constructor calls initialize, which constructs the memory resources. This is a
+    // workaround that gtest macros cannot be used directly in a constructor.
+    TestBlobAHWB(uint32_t size) { initialize(size); }
+    ~TestBlobAHWB();
+
+  private:
+    void initialize(uint32_t size);
+    AHardwareBuffer* mAhwb = nullptr;
+};
+
+enum class MemoryType { ASHMEM, BLOB_AHWB, DEVICE };
+
+// Manages the lifetime of memory resources used in an execution.
+class ExecutionContext {
+    DISALLOW_COPY_AND_ASSIGN(ExecutionContext);
+
+  public:
+    static constexpr uint32_t kInputPoolIndex = 0;
+    static constexpr uint32_t kOutputPoolIndex = 1;
+
+    ExecutionContext() = default;
+
+    // Create HIDL Request from the TestModel struct.
+    V1_0::Request createRequest(const test_helper::TestModel& testModel,
+                                MemoryType memoryType = MemoryType::ASHMEM);
+
+    // After execution, copy out output results from the output memory pool.
+    std::vector<test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request) const;
+
+  private:
+    std::unique_ptr<TestMemoryBase> mInputMemory, mOutputMemory;
+};
 
 // Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
 // so this is efficiently accomplished by moving the element to the end and
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
index cee15a3..a233835 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
@@ -133,7 +133,9 @@
 // Test driver for those generated from ml/nn/runtime/test/spec
 void Execute(const sp<IDevice>& device, const TestModel& testModel) {
     const Model model = createModel(testModel);
-    const Request request = createRequest(testModel);
+
+    ExecutionContext context;
+    const Request request = context.createRequest(testModel);
 
     // Create IPreparedModel.
     sp<IPreparedModel> preparedModel;
@@ -151,7 +153,7 @@
     ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
 
     // Retrieve execution results.
-    const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+    const std::vector<TestBuffer> outputs = context.getOutputBuffers(request);
 
     // We want "close-enough" results.
     checkResults(testModel, outputs);
@@ -166,6 +168,10 @@
     return TestModelManager::get().getTestModels(filter);
 }
 
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
+}
+
 std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
     const auto& [namedDevice, namedModel] = info.param;
     return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
index cf449ea..4b1a96e 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
@@ -37,6 +37,9 @@
 using FilterFn = std::function<bool(const test_helper::TestModel&)>;
 std::vector<NamedModel> getNamedModels(const FilterFn& filter);
 
+using FilterNameFn = std::function<bool(const std::string&)>;
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter);
+
 std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
 
 #define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
index 0629a1e..3b6f0f8 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
@@ -30,6 +30,8 @@
 using V1_0::OperandType;
 using V1_0::implementation::PreparedModelCallback;
 
+using PrepareModelMutation = std::function<void(Model*, ExecutionPreference*)>;
+
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
 static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
@@ -67,16 +69,19 @@
 }
 
 // Primary validation function. This function will take a valid model, apply a
-// mutation to it to invalidate the model, then pass it to interface calls that
-// use the model. Note that the model here is passed by value, and any mutation
-// to the model does not leave this function.
-static void validate(const sp<IDevice>& device, const std::string& message, Model model,
-                     const std::function<void(Model*)>& mutation,
-                     ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
-    mutation(&model);
+// mutation to invalidate either the model or the execution preference, then
+// pass these to supportedOperations and/or prepareModel if that method is
+// called with an invalid argument.
+static void validate(const sp<IDevice>& device, const std::string& message,
+                     const Model& originalModel, const PrepareModelMutation& mutate) {
+    Model model = originalModel;
+    ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER;
+    mutate(&model, &preference);
+
     if (validExecutionPreference(preference)) {
         validateGetSupportedOperations(device, message, model);
     }
+
     validatePrepareModel(device, message, model, preference);
 }
 
@@ -115,9 +120,11 @@
             const std::string message = "mutateOperandTypeTest: operand " +
                                         std::to_string(operand) + " set to value " +
                                         std::to_string(invalidOperandType);
-            validate(device, message, model, [operand, invalidOperandType](Model* model) {
-                model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
-            });
+            validate(device, message, model,
+                     [operand, invalidOperandType](Model* model, ExecutionPreference*) {
+                         model->operands[operand].type =
+                                 static_cast<OperandType>(invalidOperandType);
+                     });
         }
     }
 }
@@ -144,9 +151,10 @@
         const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
         const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
                                     " has rank of " + std::to_string(invalidRank);
-        validate(device, message, model, [operand, invalidRank](Model* model) {
-            model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
-        });
+        validate(device, message, model,
+                 [operand, invalidRank](Model* model, ExecutionPreference*) {
+                     model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+                 });
     }
 }
 
@@ -173,9 +181,10 @@
         const float invalidScale = getInvalidScale(model.operands[operand].type);
         const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
                                     " has scale of " + std::to_string(invalidScale);
-        validate(device, message, model, [operand, invalidScale](Model* model) {
-            model->operands[operand].scale = invalidScale;
-        });
+        validate(device, message, model,
+                 [operand, invalidScale](Model* model, ExecutionPreference*) {
+                     model->operands[operand].scale = invalidScale;
+                 });
     }
 }
 
@@ -204,9 +213,10 @@
             const std::string message = "mutateOperandZeroPointTest: operand " +
                                         std::to_string(operand) + " has zero point of " +
                                         std::to_string(invalidZeroPoint);
-            validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
-                model->operands[operand].zeroPoint = invalidZeroPoint;
-            });
+            validate(device, message, model,
+                     [operand, invalidZeroPoint](Model* model, ExecutionPreference*) {
+                         model->operands[operand].zeroPoint = invalidZeroPoint;
+                     });
         }
     }
 }
@@ -282,9 +292,10 @@
             const std::string message = "mutateOperationOperandTypeTest: operand " +
                                         std::to_string(operand) + " set to type " +
                                         toString(invalidOperandType);
-            validate(device, message, model, [operand, invalidOperandType](Model* model) {
-                mutateOperand(&model->operands[operand], invalidOperandType);
-            });
+            validate(device, message, model,
+                     [operand, invalidOperandType](Model* model, ExecutionPreference*) {
+                         mutateOperand(&model->operands[operand], invalidOperandType);
+                     });
         }
     }
 }
@@ -304,10 +315,11 @@
             const std::string message = "mutateOperationTypeTest: operation " +
                                         std::to_string(operation) + " set to value " +
                                         std::to_string(invalidOperationType);
-            validate(device, message, model, [operation, invalidOperationType](Model* model) {
-                model->operations[operation].type =
-                        static_cast<OperationType>(invalidOperationType);
-            });
+            validate(device, message, model,
+                     [operation, invalidOperationType](Model* model, ExecutionPreference*) {
+                         model->operations[operation].type =
+                                 static_cast<OperationType>(invalidOperationType);
+                     });
         }
     }
 }
@@ -321,9 +333,10 @@
             const std::string message = "mutateOperationInputOperandIndexTest: operation " +
                                         std::to_string(operation) + " input " +
                                         std::to_string(input);
-            validate(device, message, model, [operation, input, invalidOperand](Model* model) {
-                model->operations[operation].inputs[input] = invalidOperand;
-            });
+            validate(device, message, model,
+                     [operation, input, invalidOperand](Model* model, ExecutionPreference*) {
+                         model->operations[operation].inputs[input] = invalidOperand;
+                     });
         }
     }
 }
@@ -337,9 +350,10 @@
             const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
                                         std::to_string(operation) + " output " +
                                         std::to_string(output);
-            validate(device, message, model, [operation, output, invalidOperand](Model* model) {
-                model->operations[operation].outputs[output] = invalidOperand;
-            });
+            validate(device, message, model,
+                     [operation, output, invalidOperand](Model* model, ExecutionPreference*) {
+                         model->operations[operation].outputs[output] = invalidOperand;
+                     });
         }
     }
 }
@@ -372,7 +386,7 @@
     for (size_t operand = 0; operand < model.operands.size(); ++operand) {
         const std::string message = "removeOperandTest: operand " + std::to_string(operand);
         validate(device, message, model,
-                 [operand](Model* model) { removeOperand(model, operand); });
+                 [operand](Model* model, ExecutionPreference*) { removeOperand(model, operand); });
     }
 }
 
@@ -388,8 +402,9 @@
 static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message = "removeOperationTest: operation " + std::to_string(operation);
-        validate(device, message, model,
-                 [operation](Model* model) { removeOperation(model, operation); });
+        validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
+            removeOperation(model, operation);
+        });
     }
 }
 
@@ -409,11 +424,12 @@
             const std::string message = "removeOperationInputTest: operation " +
                                         std::to_string(operation) + ", input " +
                                         std::to_string(input);
-            validate(device, message, model, [operation, input](Model* model) {
-                uint32_t operand = model->operations[operation].inputs[input];
-                model->operands[operand].numberOfConsumers--;
-                hidl_vec_removeAt(&model->operations[operation].inputs, input);
-            });
+            validate(device, message, model,
+                     [operation, input](Model* model, ExecutionPreference*) {
+                         uint32_t operand = model->operations[operation].inputs[input];
+                         model->operands[operand].numberOfConsumers--;
+                         hidl_vec_removeAt(&model->operations[operation].inputs, input);
+                     });
         }
     }
 }
@@ -426,9 +442,10 @@
             const std::string message = "removeOperationOutputTest: operation " +
                                         std::to_string(operation) + ", output " +
                                         std::to_string(output);
-            validate(device, message, model, [operation, output](Model* model) {
-                hidl_vec_removeAt(&model->operations[operation].outputs, output);
-            });
+            validate(device, message, model,
+                     [operation, output](Model* model, ExecutionPreference*) {
+                         hidl_vec_removeAt(&model->operations[operation].outputs, output);
+                     });
         }
     }
 }
@@ -444,7 +461,7 @@
 static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
-        validate(device, message, model, [operation](Model* model) {
+        validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
             uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
             hidl_vec_push_back(&model->operations[operation].inputs, index);
             hidl_vec_push_back(&model->inputIndexes, index);
@@ -458,7 +475,7 @@
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message =
                 "addOperationOutputTest: operation " + std::to_string(operation);
-        validate(device, message, model, [operation](Model* model) {
+        validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
             uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
             hidl_vec_push_back(&model->operations[operation].outputs, index);
             hidl_vec_push_back(&model->outputIndexes, index);
@@ -474,12 +491,13 @@
 };
 
 static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
-    for (int32_t preference : invalidExecutionPreferences) {
+    for (int32_t invalidPreference : invalidExecutionPreferences) {
         const std::string message =
-                "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
-        validate(
-                device, message, model, [](Model*) {},
-                static_cast<ExecutionPreference>(preference));
+                "mutateExecutionPreferenceTest: preference " + std::to_string(invalidPreference);
+        validate(device, message, model,
+                 [invalidPreference](Model*, ExecutionPreference* preference) {
+                     *preference = static_cast<ExecutionPreference>(invalidPreference);
+                 });
     }
 }
 
diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
index 9684eb2..2914335 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
@@ -28,15 +28,17 @@
 using V1_0::Request;
 using V1_0::implementation::ExecutionCallback;
 
+using ExecutionMutation = std::function<void(Request*)>;
+
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
 // Primary validation function. This function will take a valid request, apply a
 // mutation to it to invalidate the request, then pass it to interface calls
-// that use the request. Note that the request here is passed by value, and any
-// mutation to the request does not leave this function.
+// that use the request.
 static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
-                     Request request, const std::function<void(Request*)>& mutation) {
-    mutation(&request);
+                     const Request& originalRequest, const ExecutionMutation& mutate) {
+    Request request = originalRequest;
+    mutate(&request);
     SCOPED_TRACE(message + " [execute]");
 
     sp<ExecutionCallback> executionCallback = new ExecutionCallback();
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
index d56d40b..54e8802 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
@@ -132,11 +132,17 @@
 
 TEST_P(ValidationTest, Test) {
     const Model model = createModel(kTestModel);
-    const Request request = createRequest(kTestModel);
+    ExecutionContext context;
+    const Request request = context.createRequest(kTestModel);
     ASSERT_FALSE(kTestModel.expectFailure);
     validateEverything(kDevice, model, request);
 }
 
-INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) {
+    // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs"
+    // generated tests.
+    return testName.find("inputs_as_internal") == std::string::npos &&
+           testName.find("all_tensors_as_inputs") == std::string::npos;
+});
 
 }  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 31a1a81..7c1faee 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -28,7 +28,7 @@
     ],
     header_libs: [
         "libbase_headers",
-    ]
+    ],
 }
 
 cc_test {
@@ -39,9 +39,9 @@
         "CompilationCachingTests.cpp",
         "GeneratedTestHarness.cpp",
         "TestAssertions.cpp",
+        "ValidateBurst.cpp",
         "ValidateModel.cpp",
         "ValidateRequest.cpp",
-        "ValidateBurst.cpp",
         "VtsHalNeuralnetworks.cpp",
     ],
     local_include_dirs: ["include"],
@@ -50,18 +50,17 @@
         "libnativewindow",
     ],
     static_libs: [
+        "VtsHalNeuralNetworksV1_0_utils",
+        "VtsHalNeuralNetworksV1_2Callbacks",
         "android.hardware.neuralnetworks@1.0",
         "android.hardware.neuralnetworks@1.1",
         "android.hardware.neuralnetworks@1.2",
-        "android.hardware.neuralnetworks@1.3",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libgmock",
         "libhidlmemory",
         "libneuralnetworks_generated_test_harness",
         "libneuralnetworks_utils",
-        "VtsHalNeuralNetworksV1_0_utils",
-        "VtsHalNeuralNetworksV1_2Callbacks",
     ],
     whole_static_libs: [
         "neuralnetworks_generated_V1_0_example",
@@ -71,5 +70,8 @@
     header_libs: [
         "libneuralnetworks_headers",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 10dec79..449b8f3 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -32,7 +32,6 @@
 #include "GeneratedTestHarness.h"
 #include "MemoryUtils.h"
 #include "TestHarness.h"
-#include "Utils.h"
 #include "VtsHalNeuralnetworks.h"
 
 // Forward declaration of the mobilenet generated test models in
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index 4c8fede..35275b4 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -43,7 +43,6 @@
 #include "ExecutionBurstController.h"
 #include "MemoryUtils.h"
 #include "TestHarness.h"
-#include "Utils.h"
 #include "VtsHalNeuralnetworks.h"
 
 namespace android::hardware::neuralnetworks::V1_2::vts::functional {
@@ -69,6 +68,7 @@
     Executor executor;
     MeasureTiming measureTiming;
     OutputType outputType;
+    MemoryType memoryType;
 };
 
 }  // namespace
@@ -217,7 +217,8 @@
         return;
     }
 
-    Request request = createRequest(testModel);
+    ExecutionContext context;
+    Request request = context.createRequest(testModel, testConfig.memoryType);
     if (testConfig.outputType == OutputType::INSUFFICIENT) {
         makeOutputInsufficientSize(/*outputIndex=*/0, &request);
     }
@@ -273,7 +274,7 @@
             int n;
             std::tie(n, outputShapes, timing, std::ignore) =
                     controller->compute(request, testConfig.measureTiming, keys);
-            executionStatus = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(n));
+            executionStatus = nn::legacyConvertResultCodeToErrorStatus(n);
 
             break;
         }
@@ -327,7 +328,7 @@
     }
 
     // Retrieve execution results.
-    const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+    const std::vector<TestBuffer> outputs = context.getOutputBuffers(request);
 
     // We want "close-enough" results.
     checkResults(testModel, outputs);
@@ -338,24 +339,30 @@
     std::vector<OutputType> outputTypesList;
     std::vector<MeasureTiming> measureTimingList;
     std::vector<Executor> executorList;
+    std::vector<MemoryType> memoryTypeList;
 
     if (testDynamicOutputShape) {
         outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
         measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
         executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+        memoryTypeList = {MemoryType::ASHMEM};
     } else {
         outputTypesList = {OutputType::FULLY_SPECIFIED};
         measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
         executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+        memoryTypeList = {MemoryType::ASHMEM, MemoryType::BLOB_AHWB};
     }
 
     for (const OutputType outputType : outputTypesList) {
         for (const MeasureTiming measureTiming : measureTimingList) {
             for (const Executor executor : executorList) {
-                const TestConfig testConfig = {.executor = executor,
-                                               .measureTiming = measureTiming,
-                                               .outputType = outputType};
-                EvaluatePreparedModel(preparedModel, testModel, testConfig);
+                for (const MemoryType memoryType : memoryTypeList) {
+                    const TestConfig testConfig = {.executor = executor,
+                                                   .measureTiming = measureTiming,
+                                                   .outputType = outputType,
+                                                   .memoryType = memoryType};
+                    EvaluatePreparedModel(preparedModel, testModel, testConfig);
+                }
             }
         }
     }
@@ -383,6 +390,10 @@
     return TestModelManager::get().getTestModels(filter);
 }
 
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
+}
+
 std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
     const auto& [namedDevice, namedModel] = info.param;
     return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
index dfc980c..98295ff 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
@@ -41,6 +41,9 @@
 using FilterFn = std::function<bool(const test_helper::TestModel&)>;
 std::vector<NamedModel> getNamedModels(const FilterFn& filter);
 
+using FilterNameFn = std::function<bool(const std::string&)>;
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter);
+
 std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
 
 #define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
index ec9629b..4476266 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
@@ -23,7 +23,6 @@
 #include "ExecutionBurstServer.h"
 #include "GeneratedTestHarness.h"
 #include "TestHarness.h"
-#include "Utils.h"
 
 #include <android-base/logging.h>
 #include <chrono>
@@ -38,6 +37,8 @@
 using V1_0::Request;
 using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback;
 
+using BurstExecutionMutation = std::function<void(std::vector<FmqRequestDatum>*)>;
+
 // This constant value represents the length of an FMQ that is large enough to
 // return a result from a burst execution for all of the generated test cases.
 constexpr size_t kExecutionBurstChannelLength = 1024;
@@ -116,13 +117,13 @@
 
 // Primary validation function. This function will take a valid serialized
 // request, apply a mutation to it to invalidate the serialized request, then
-// pass it to interface calls that use the serialized request. Note that the
-// serialized request here is passed by value, and any mutation to the
-// serialized request does not leave this function.
+// pass it to interface calls that use the serialized request.
 static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiver,
-                     const std::string& message, std::vector<FmqRequestDatum> serialized,
-                     const std::function<void(std::vector<FmqRequestDatum>*)>& mutation) {
-    mutation(&serialized);
+                     const std::string& message,
+                     const std::vector<FmqRequestDatum>& originalSerialized,
+                     const BurstExecutionMutation& mutate) {
+    std::vector<FmqRequestDatum> serialized = originalSerialized;
+    mutate(&serialized);
 
     // skip if packet is too large to send
     if (serialized.size() > kExecutionBurstChannelLength) {
@@ -296,8 +297,7 @@
     // collect serialized result by running regular burst
     const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] =
             controllerRegular->compute(request, MeasureTiming::NO, keys);
-    const ErrorStatus statusRegular =
-            nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nRegular));
+    const ErrorStatus statusRegular = nn::legacyConvertResultCodeToErrorStatus(nRegular);
     EXPECT_FALSE(fallbackRegular);
 
     // skip test if regular burst output isn't useful for testing a failure
@@ -313,7 +313,7 @@
     // large enough to return the serialized result
     const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] =
             controllerSmall->compute(request, MeasureTiming::NO, keys);
-    const ErrorStatus statusSmall = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nSmall));
+    const ErrorStatus statusSmall = nn::legacyConvertResultCodeToErrorStatus(nSmall);
     EXPECT_NE(ErrorStatus::NONE, statusSmall);
     EXPECT_EQ(0u, outputShapesSmall.size());
     EXPECT_TRUE(badTiming(timingSmall));
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index 30530be..7451f09 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -29,6 +29,8 @@
 using V1_1::ExecutionPreference;
 using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
 
+using PrepareModelMutation = std::function<void(Model*, ExecutionPreference*)>;
+
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
 static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
@@ -67,16 +69,19 @@
 }
 
 // Primary validation function. This function will take a valid model, apply a
-// mutation to it to invalidate the model, then pass it to interface calls that
-// use the model. Note that the model here is passed by value, and any mutation
-// to the model does not leave this function.
-static void validate(const sp<IDevice>& device, const std::string& message, Model model,
-                     const std::function<void(Model*)>& mutation,
-                     ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
-    mutation(&model);
+// mutation to invalidate either the model or the execution preference, then
+// pass these to supportedOperations and/or prepareModel if that method is
+// called with an invalid argument.
+static void validate(const sp<IDevice>& device, const std::string& message,
+                     const Model& originalModel, const PrepareModelMutation& mutate) {
+    Model model = originalModel;
+    ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER;
+    mutate(&model, &preference);
+
     if (validExecutionPreference(preference)) {
         validateGetSupportedOperations(device, message, model);
     }
+
     validatePrepareModel(device, message, model, preference);
 }
 
@@ -115,9 +120,11 @@
             const std::string message = "mutateOperandTypeTest: operand " +
                                         std::to_string(operand) + " set to value " +
                                         std::to_string(invalidOperandType);
-            validate(device, message, model, [operand, invalidOperandType](Model* model) {
-                model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
-            });
+            validate(device, message, model,
+                     [operand, invalidOperandType](Model* model, ExecutionPreference*) {
+                         model->operands[operand].type =
+                                 static_cast<OperandType>(invalidOperandType);
+                     });
         }
     }
 }
@@ -155,9 +162,10 @@
         }
         const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
                                     " has rank of " + std::to_string(invalidRank);
-        validate(device, message, model, [operand, invalidRank](Model* model) {
-            model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
-        });
+        validate(device, message, model,
+                 [operand, invalidRank](Model* model, ExecutionPreference*) {
+                     model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+                 });
     }
 }
 
@@ -192,9 +200,10 @@
         const float invalidScale = getInvalidScale(model.operands[operand].type);
         const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
                                     " has scale of " + std::to_string(invalidScale);
-        validate(device, message, model, [operand, invalidScale](Model* model) {
-            model->operands[operand].scale = invalidScale;
-        });
+        validate(device, message, model,
+                 [operand, invalidScale](Model* model, ExecutionPreference*) {
+                     model->operands[operand].scale = invalidScale;
+                 });
     }
 }
 
@@ -234,9 +243,10 @@
             const std::string message = "mutateOperandZeroPointTest: operand " +
                                         std::to_string(operand) + " has zero point of " +
                                         std::to_string(invalidZeroPoint);
-            validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
-                model->operands[operand].zeroPoint = invalidZeroPoint;
-            });
+            validate(device, message, model,
+                     [operand, invalidZeroPoint](Model* model, ExecutionPreference*) {
+                         model->operands[operand].zeroPoint = invalidZeroPoint;
+                     });
         }
     }
 }
@@ -386,9 +396,10 @@
             const std::string message = "mutateOperationOperandTypeTest: operand " +
                                         std::to_string(operand) + " set to type " +
                                         toString(invalidOperandType);
-            validate(device, message, model, [operand, invalidOperandType](Model* model) {
-                mutateOperand(&model->operands[operand], invalidOperandType);
-            });
+            validate(device, message, model,
+                     [operand, invalidOperandType](Model* model, ExecutionPreference*) {
+                         mutateOperand(&model->operands[operand], invalidOperandType);
+                     });
         }
     }
 }
@@ -407,10 +418,11 @@
             const std::string message = "mutateOperationTypeTest: operation " +
                                         std::to_string(operation) + " set to value " +
                                         std::to_string(invalidOperationType);
-            validate(device, message, model, [operation, invalidOperationType](Model* model) {
-                model->operations[operation].type =
-                        static_cast<OperationType>(invalidOperationType);
-            });
+            validate(device, message, model,
+                     [operation, invalidOperationType](Model* model, ExecutionPreference*) {
+                         model->operations[operation].type =
+                                 static_cast<OperationType>(invalidOperationType);
+                     });
         }
     }
 }
@@ -424,9 +436,10 @@
             const std::string message = "mutateOperationInputOperandIndexTest: operation " +
                                         std::to_string(operation) + " input " +
                                         std::to_string(input);
-            validate(device, message, model, [operation, input, invalidOperand](Model* model) {
-                model->operations[operation].inputs[input] = invalidOperand;
-            });
+            validate(device, message, model,
+                     [operation, input, invalidOperand](Model* model, ExecutionPreference*) {
+                         model->operations[operation].inputs[input] = invalidOperand;
+                     });
         }
     }
 }
@@ -440,9 +453,10 @@
             const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
                                         std::to_string(operation) + " output " +
                                         std::to_string(output);
-            validate(device, message, model, [operation, output, invalidOperand](Model* model) {
-                model->operations[operation].outputs[output] = invalidOperand;
-            });
+            validate(device, message, model,
+                     [operation, output, invalidOperand](Model* model, ExecutionPreference*) {
+                         model->operations[operation].outputs[output] = invalidOperand;
+                     });
         }
     }
 }
@@ -503,7 +517,7 @@
         }
         const std::string message = "removeOperandTest: operand " + std::to_string(operand);
         validate(device, message, model,
-                 [operand](Model* model) { removeOperand(model, operand); });
+                 [operand](Model* model, ExecutionPreference*) { removeOperand(model, operand); });
     }
 }
 
@@ -519,8 +533,9 @@
 static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message = "removeOperationTest: operation " + std::to_string(operation);
-        validate(device, message, model,
-                 [operation](Model* model) { removeOperation(model, operation); });
+        validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
+            removeOperation(model, operation);
+        });
     }
 }
 
@@ -601,11 +616,12 @@
             const std::string message = "removeOperationInputTest: operation " +
                                         std::to_string(operation) + ", input " +
                                         std::to_string(input);
-            validate(device, message, model, [operation, input](Model* model) {
-                uint32_t operand = model->operations[operation].inputs[input];
-                model->operands[operand].numberOfConsumers--;
-                hidl_vec_removeAt(&model->operations[operation].inputs, input);
-            });
+            validate(device, message, model,
+                     [operation, input](Model* model, ExecutionPreference*) {
+                         uint32_t operand = model->operations[operation].inputs[input];
+                         model->operands[operand].numberOfConsumers--;
+                         hidl_vec_removeAt(&model->operations[operation].inputs, input);
+                     });
         }
     }
 }
@@ -618,9 +634,10 @@
             const std::string message = "removeOperationOutputTest: operation " +
                                         std::to_string(operation) + ", output " +
                                         std::to_string(output);
-            validate(device, message, model, [operation, output](Model* model) {
-                hidl_vec_removeAt(&model->operations[operation].outputs, output);
-            });
+            validate(device, message, model,
+                     [operation, output](Model* model, ExecutionPreference*) {
+                         hidl_vec_removeAt(&model->operations[operation].outputs, output);
+                     });
         }
     }
 }
@@ -651,7 +668,7 @@
             continue;
         }
         const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
-        validate(device, message, model, [operation](Model* model) {
+        validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
             uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
             hidl_vec_push_back(&model->operations[operation].inputs, index);
             hidl_vec_push_back(&model->inputIndexes, index);
@@ -665,7 +682,7 @@
     for (size_t operation = 0; operation < model.operations.size(); ++operation) {
         const std::string message =
                 "addOperationOutputTest: operation " + std::to_string(operation);
-        validate(device, message, model, [operation](Model* model) {
+        validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
             uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
             hidl_vec_push_back(&model->operations[operation].outputs, index);
             hidl_vec_push_back(&model->outputIndexes, index);
@@ -681,12 +698,13 @@
 };
 
 static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
-    for (int32_t preference : invalidExecutionPreferences) {
+    for (int32_t invalidPreference : invalidExecutionPreferences) {
         const std::string message =
-                "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
-        validate(
-                device, message, model, [](Model*) {},
-                static_cast<ExecutionPreference>(preference));
+                "mutateExecutionPreferenceTest: preference " + std::to_string(invalidPreference);
+        validate(device, message, model,
+                 [invalidPreference](Model*, ExecutionPreference* preference) {
+                     *preference = static_cast<ExecutionPreference>(invalidPreference);
+                 });
     }
 }
 
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index 7b5ff9b..934d893 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -22,7 +22,6 @@
 #include "ExecutionBurstController.h"
 #include "GeneratedTestHarness.h"
 #include "TestHarness.h"
-#include "Utils.h"
 #include "VtsHalNeuralnetworks.h"
 
 namespace android::hardware::neuralnetworks::V1_2::vts::functional {
@@ -31,6 +30,8 @@
 using V1_0::ErrorStatus;
 using V1_0::Request;
 
+using ExecutionMutation = std::function<void(Request*)>;
+
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
 static bool badTiming(Timing timing) {
@@ -39,11 +40,11 @@
 
 // Primary validation function. This function will take a valid request, apply a
 // mutation to it to invalidate the request, then pass it to interface calls
-// that use the request. Note that the request here is passed by value, and any
-// mutation to the request does not leave this function.
+// that use the request.
 static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
-                     Request request, const std::function<void(Request*)>& mutation) {
-    mutation(&request);
+                     const Request& originalRequest, const ExecutionMutation& mutate) {
+    Request request = originalRequest;
+    mutate(&request);
 
     // We'd like to test both with timing requested and without timing
     // requested. Rather than running each test both ways, we'll decide whether
@@ -107,7 +108,7 @@
 
         // execute and verify
         const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys);
-        const ErrorStatus status = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(n));
+        const ErrorStatus status = nn::legacyConvertResultCodeToErrorStatus(n);
         EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
         EXPECT_EQ(outputShapes.size(), 0);
         EXPECT_TRUE(badTiming(timing));
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
index 4fbd0e2..a60ec4d 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
@@ -153,7 +153,8 @@
 
 TEST_P(ValidationTest, Test) {
     const Model model = createModel(kTestModel);
-    const Request request = createRequest(kTestModel);
+    ExecutionContext context;
+    const Request request = context.createRequest(kTestModel);
     if (kTestModel.expectFailure) {
         validateFailure(kDevice, model, request);
     } else {
@@ -161,7 +162,12 @@
     }
 }
 
-INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) {
+    // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs"
+    // generated tests.
+    return testName.find("inputs_as_internal") == std::string::npos &&
+           testName.find("all_tensors_as_inputs") == std::string::npos;
+});
 
 sp<IPreparedModel> getPreparedModel_1_2(const sp<implementation::PreparedModelCallback>& callback) {
     sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index daaf22e..25ec915 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -5168,6 +5168,8 @@
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
      *
+     * Supported tensor rank: from 1.
+     *
      * Inputs:
      * * 0: A tensor, specifying the input. May be zero-sized.
      * * 1: A scalar, specifying the alpha parameter.
@@ -5197,6 +5199,8 @@
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
      *
+     * Supported tensor rank: from 1.
+     *
      * Inputs:
      * * 0: A tensor, specifying the input. May be zero-sized.
      *
@@ -5215,6 +5219,8 @@
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_INT32}
      *
+     * Supported tensor rank: from 1.
+     *
      * Inputs:
      * * 0: A 1-D tensor, specifying the desired output tensor shape.
      * * 1: A scalar, specifying the value to fill the output tensors with.
@@ -5248,6 +5254,8 @@
      * * {@link OperandType::TENSOR_QUANT8_SYMM}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
      *
+     * Supported tensor rank: from 1.
+     *
      * Inputs:
      * * 0: The input tensor.
      *
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index f936267..545a5be 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -40,6 +40,7 @@
         "BasicTests.cpp",
         "CompilationCachingTests.cpp",
         "GeneratedTestHarness.cpp",
+        "MemoryDomainTests.cpp",
         "QualityOfServiceTests.cpp",
         "TestAssertions.cpp",
         "ValidateBurst.cpp",
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 83a8d94..4dbac16 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -72,21 +72,10 @@
 
 namespace {
 
-enum class Executor { ASYNC, SYNC, BURST, FENCED };
-
 enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT, MISSED_DEADLINE };
 
-enum class MemoryType { SHARED, DEVICE };
-
 enum class IOType { INPUT, OUTPUT };
 
-static void waitForSyncFence(int syncFd) {
-    constexpr int kInfiniteTimeout = -1;
-    ASSERT_GT(syncFd, 0);
-    int r = sync_wait(syncFd, kInfiniteTimeout);
-    ASSERT_GE(r, 0);
-}
-
 struct TestConfig {
     Executor executor;
     MeasureTiming measureTiming;
@@ -277,6 +266,13 @@
 
 }  // namespace
 
+void waitForSyncFence(int syncFd) {
+    constexpr int kInfiniteTimeout = -1;
+    ASSERT_GT(syncFd, 0);
+    int r = sync_wait(syncFd, kInfiniteTimeout);
+    ASSERT_GE(r, 0);
+}
+
 Model createModel(const TestModel& testModel) {
     uint32_t constCopySize = 0;
     uint32_t constRefSize = 0;
@@ -338,21 +334,39 @@
     }
 }
 
-constexpr uint32_t kInputPoolIndex = 0;
-constexpr uint32_t kOutputPoolIndex = 1;
-constexpr uint32_t kDeviceMemoryBeginIndex = 2;
+class ExecutionContextV1_3 {
+  public:
+    ExecutionContextV1_3(sp<IDevice> device, sp<IPreparedModel> preparedModel)
+        : kDevice(std::move(device)), kPreparedModel(std::move(preparedModel)) {}
 
-static std::pair<Request, std::vector<sp<IBuffer>>> createRequest(
-        const sp<IDevice>& device, const sp<IPreparedModel>& preparedModel,
-        const TestModel& testModel, bool preferDeviceMemory) {
+    std::optional<Request> createRequest(const TestModel& testModel, MemoryType memoryType);
+    std::vector<TestBuffer> getOutputBuffers(const TestModel& testModel,
+                                             const Request& request) const;
+
+  private:
+    // Get a TestBuffer with data copied from an IBuffer object.
+    void getBuffer(const sp<IBuffer>& buffer, size_t size, TestBuffer* testBuffer) const;
+
+    static constexpr uint32_t kInputPoolIndex = 0;
+    static constexpr uint32_t kOutputPoolIndex = 1;
+    static constexpr uint32_t kDeviceMemoryBeginIndex = 2;
+
+    const sp<IDevice> kDevice;
+    const sp<IPreparedModel> kPreparedModel;
+    std::unique_ptr<TestMemoryBase> mInputMemory, mOutputMemory;
+    std::vector<sp<IBuffer>> mBuffers;
+};
+
+std::optional<Request> ExecutionContextV1_3::createRequest(const TestModel& testModel,
+                                                           MemoryType memoryType) {
     // Memory pools are organized as:
     // - 0: Input shared memory pool
     // - 1: Output shared memory pool
     // - [2, 2+i): Input device memories
     // - [2+i, 2+i+o): Output device memories
-    DeviceMemoryAllocator allocator(device, preparedModel, testModel);
-    std::vector<sp<IBuffer>> buffers;
+    DeviceMemoryAllocator allocator(kDevice, kPreparedModel, testModel);
     std::vector<uint32_t> tokens;
+    mBuffers.clear();
 
     // Model inputs.
     hidl_vec<RequestArgument> inputs(testModel.main.inputIndexes.size());
@@ -363,13 +377,13 @@
             // Omitted input.
             inputs[i] = {.hasNoValue = true};
             continue;
-        } else if (preferDeviceMemory) {
+        } else if (memoryType == MemoryType::DEVICE) {
             SCOPED_TRACE("Input index = " + std::to_string(i));
             auto [buffer, token] = allocator.allocate<IOType::INPUT>(i);
             if (buffer != nullptr) {
-                DataLocation loc = {.poolIndex = static_cast<uint32_t>(buffers.size() +
+                DataLocation loc = {.poolIndex = static_cast<uint32_t>(mBuffers.size() +
                                                                        kDeviceMemoryBeginIndex)};
-                buffers.push_back(std::move(buffer));
+                mBuffers.push_back(std::move(buffer));
                 tokens.push_back(token);
                 inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
                 continue;
@@ -389,13 +403,13 @@
     size_t outputSize = 0;
     for (uint32_t i = 0; i < testModel.main.outputIndexes.size(); i++) {
         const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
-        if (preferDeviceMemory) {
+        if (memoryType == MemoryType::DEVICE) {
             SCOPED_TRACE("Output index = " + std::to_string(i));
             auto [buffer, token] = allocator.allocate<IOType::OUTPUT>(i);
             if (buffer != nullptr) {
-                DataLocation loc = {.poolIndex = static_cast<uint32_t>(buffers.size() +
+                DataLocation loc = {.poolIndex = static_cast<uint32_t>(mBuffers.size() +
                                                                        kDeviceMemoryBeginIndex)};
-                buffers.push_back(std::move(buffer));
+                mBuffers.push_back(std::move(buffer));
                 tokens.push_back(token);
                 outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
                 continue;
@@ -418,21 +432,29 @@
         outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
     }
 
+    if (memoryType == MemoryType::DEVICE && mBuffers.empty()) {
+        return std::nullopt;
+    }
+
     // Memory pools.
-    hidl_vec<Request::MemoryPool> pools(kDeviceMemoryBeginIndex + buffers.size());
-    pools[kInputPoolIndex].hidlMemory(nn::allocateSharedMemory(std::max<size_t>(inputSize, 1)));
-    pools[kOutputPoolIndex].hidlMemory(nn::allocateSharedMemory(std::max<size_t>(outputSize, 1)));
-    CHECK_NE(pools[kInputPoolIndex].hidlMemory().size(), 0u);
-    CHECK_NE(pools[kOutputPoolIndex].hidlMemory().size(), 0u);
-    for (uint32_t i = 0; i < buffers.size(); i++) {
+    hidl_vec<Request::MemoryPool> pools(kDeviceMemoryBeginIndex + mBuffers.size());
+    if (memoryType == MemoryType::BLOB_AHWB) {
+        mInputMemory = TestBlobAHWB::create(std::max<size_t>(inputSize, 1));
+        mOutputMemory = TestBlobAHWB::create(std::max<size_t>(outputSize, 1));
+    } else {
+        mInputMemory = TestAshmem::create(std::max<size_t>(inputSize, 1));
+        mOutputMemory = TestAshmem::create(std::max<size_t>(outputSize, 1));
+    }
+    EXPECT_NE(mInputMemory, nullptr);
+    EXPECT_NE(mOutputMemory, nullptr);
+    pools[kInputPoolIndex].hidlMemory(mInputMemory->getHidlMemory());
+    pools[kOutputPoolIndex].hidlMemory(mOutputMemory->getHidlMemory());
+    for (uint32_t i = 0; i < mBuffers.size(); i++) {
         pools[kDeviceMemoryBeginIndex + i].token(tokens[i]);
     }
 
     // Copy input data to the input shared memory pool.
-    sp<IMemory> inputMemory = mapMemory(pools[kInputPoolIndex].hidlMemory());
-    CHECK(inputMemory.get() != nullptr);
-    uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
-    CHECK(inputPtr != nullptr);
+    uint8_t* inputPtr = mInputMemory->getPointer();
     for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
         if (!inputs[i].hasNoValue && inputs[i].location.poolIndex == kInputPoolIndex) {
             const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
@@ -441,14 +463,38 @@
             std::copy(begin, end, inputPtr + inputs[i].location.offset);
         }
     }
-
-    Request request = {
+    return Request{
             .inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
-    return {std::move(request), std::move(buffers)};
+}
+
+std::vector<TestBuffer> ExecutionContextV1_3::getOutputBuffers(const TestModel& testModel,
+                                                               const Request& request) const {
+    // Copy out output results.
+    uint8_t* outputPtr = mOutputMemory->getPointer();
+    std::vector<TestBuffer> outputBuffers;
+    for (uint32_t i = 0; i < request.outputs.size(); i++) {
+        const auto& outputLoc = request.outputs[i].location;
+        if (outputLoc.poolIndex == kOutputPoolIndex) {
+            outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset);
+        } else {
+            const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
+            if (op.data.size() == 0) {
+                outputBuffers.emplace_back(0, nullptr);
+            } else {
+                SCOPED_TRACE("Output index = " + std::to_string(i));
+                const uint32_t bufferIndex = outputLoc.poolIndex - kDeviceMemoryBeginIndex;
+                TestBuffer buffer;
+                getBuffer(mBuffers[bufferIndex], op.data.size(), &buffer);
+                outputBuffers.push_back(std::move(buffer));
+            }
+        }
+    }
+    return outputBuffers;
 }
 
 // Get a TestBuffer with data copied from an IBuffer object.
-static void getBuffer(const sp<IBuffer>& buffer, size_t size, TestBuffer* testBuffer) {
+void ExecutionContextV1_3::getBuffer(const sp<IBuffer>& buffer, size_t size,
+                                     TestBuffer* testBuffer) const {
     // IBuffer -> Shared memory.
     hidl_memory tmp = nn::allocateSharedMemory(size);
     const auto ret = buffer->copyTo(tmp);
@@ -464,33 +510,11 @@
     *testBuffer = TestBuffer(size, outputPtr);
 }
 
-static std::vector<TestBuffer> getOutputBuffers(const TestModel& testModel, const Request& request,
-                                                const std::vector<sp<IBuffer>>& buffers) {
-    sp<IMemory> outputMemory = mapMemory(request.pools[kOutputPoolIndex].hidlMemory());
-    CHECK(outputMemory.get() != nullptr);
-    uint8_t* outputPtr = static_cast<uint8_t*>(static_cast<void*>(outputMemory->getPointer()));
-    CHECK(outputPtr != nullptr);
-
-    // Copy out output results.
-    std::vector<TestBuffer> outputBuffers;
-    for (uint32_t i = 0; i < request.outputs.size(); i++) {
-        const auto& outputLoc = request.outputs[i].location;
-        if (outputLoc.poolIndex == kOutputPoolIndex) {
-            outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset);
-        } else {
-            const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
-            if (op.data.size() == 0) {
-                outputBuffers.emplace_back();
-            } else {
-                SCOPED_TRACE("Output index = " + std::to_string(i));
-                const uint32_t bufferIndex = outputLoc.poolIndex - kDeviceMemoryBeginIndex;
-                TestBuffer buffer;
-                getBuffer(buffers[bufferIndex], op.data.size(), &buffer);
-                outputBuffers.push_back(std::move(buffer));
-            }
-        }
-    }
-    return outputBuffers;
+static bool hasZeroSizedOutput(const TestModel& testModel) {
+    return std::any_of(testModel.main.outputIndexes.begin(), testModel.main.outputIndexes.end(),
+                       [&testModel](uint32_t index) {
+                           return testModel.main.operands[index].data.size() == 0;
+                       });
 }
 
 static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
@@ -536,13 +560,14 @@
         return;
     }
 
-    auto [request, buffers] =
-            createRequest(device, preparedModel, testModel,
-                          /*preferDeviceMemory=*/testConfig.memoryType == MemoryType::DEVICE);
+    ExecutionContextV1_3 context(device, preparedModel);
+    auto maybeRequest = context.createRequest(testModel, testConfig.memoryType);
     // Skip if testing memory domain but no device memory has been allocated.
-    if (testConfig.memoryType == MemoryType::DEVICE && buffers.empty()) {
+    if (!maybeRequest.has_value()) {
         return;
     }
+
+    Request request = std::move(maybeRequest.value());
     if (testConfig.outputType == OutputType::INSUFFICIENT) {
         makeOutputInsufficientSize(/*outputIndex=*/0, &request);
     }
@@ -641,6 +666,7 @@
                 ASSERT_EQ(syncFenceHandle.getNativeHandle(), nullptr);
                 ASSERT_EQ(fencedCallback, nullptr);
                 executionStatus = result;
+                timing = {UINT64_MAX, UINT64_MAX};
             } else if (syncFenceHandle.getNativeHandle()) {
                 // If a sync fence is returned, try start another run waiting for the sync fence.
                 ret = preparedModel->executeFenced(request, {syncFenceHandle},
@@ -689,6 +715,11 @@
 
     switch (testConfig.outputType) {
         case OutputType::FULLY_SPECIFIED:
+            if (testConfig.executor == Executor::FENCED && hasZeroSizedOutput(testModel)) {
+                // Executor::FENCED does not support zero-sized output.
+                ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
+                return;
+            }
             // If the model output operands are fully specified, outputShapes must be either
             // either empty, or have the same number of elements as the number of outputs.
             ASSERT_EQ(ErrorStatus::NONE, executionStatus);
@@ -732,7 +763,7 @@
     }
 
     // Retrieve execution results.
-    const std::vector<TestBuffer> outputs = getOutputBuffers(testModel, request, buffers);
+    const std::vector<TestBuffer> outputs = context.getOutputBuffers(testModel, request);
 
     // We want "close-enough" results.
     checkResults(testModel, outputs);
@@ -743,29 +774,32 @@
     std::vector<OutputType> outputTypesList;
     std::vector<MeasureTiming> measureTimingList;
     std::vector<Executor> executorList;
-    MemoryType memoryType = MemoryType::SHARED;
+    std::vector<MemoryType> memoryTypeList;
 
     switch (testKind) {
         case TestKind::GENERAL: {
             outputTypesList = {OutputType::FULLY_SPECIFIED};
             measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
             executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+            memoryTypeList = {MemoryType::ASHMEM};
         } break;
         case TestKind::DYNAMIC_SHAPE: {
             outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
             measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
             executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST, Executor::FENCED};
+            memoryTypeList = {MemoryType::ASHMEM};
         } break;
         case TestKind::MEMORY_DOMAIN: {
             outputTypesList = {OutputType::FULLY_SPECIFIED};
             measureTimingList = {MeasureTiming::NO};
             executorList = {Executor::ASYNC, Executor::SYNC, Executor::FENCED};
-            memoryType = MemoryType::DEVICE;
+            memoryTypeList = {MemoryType::BLOB_AHWB, MemoryType::DEVICE};
         } break;
         case TestKind::FENCED_COMPUTE: {
             outputTypesList = {OutputType::FULLY_SPECIFIED};
             measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
             executorList = {Executor::FENCED};
+            memoryTypeList = {MemoryType::ASHMEM};
         } break;
         case TestKind::QUANTIZATION_COUPLING: {
             LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel";
@@ -776,14 +810,17 @@
             measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
             // Burst does not support V1_3 loop timeout.
             executorList = {Executor::ASYNC, Executor::SYNC, Executor::FENCED};
+            memoryTypeList = {MemoryType::ASHMEM};
         } break;
     }
 
     for (const OutputType outputType : outputTypesList) {
         for (const MeasureTiming measureTiming : measureTimingList) {
             for (const Executor executor : executorList) {
-                const TestConfig testConfig(executor, measureTiming, outputType, memoryType);
-                EvaluatePreparedModel(device, preparedModel, testModel, testConfig);
+                for (const MemoryType memoryType : memoryTypeList) {
+                    const TestConfig testConfig(executor, measureTiming, outputType, memoryType);
+                    EvaluatePreparedModel(device, preparedModel, testModel, testConfig);
+                }
             }
         }
     }
@@ -802,7 +839,7 @@
     for (const OutputType outputType : outputTypesList) {
         for (const MeasureTiming measureTiming : measureTimingList) {
             for (const Executor executor : executorList) {
-                const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::SHARED,
+                const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::ASHMEM,
                                             /*reportSkipping=*/false);
                 bool baseSkipped = false;
                 EvaluatePreparedModel(device, preparedModel, testModel, testConfig, &baseSkipped);
@@ -879,6 +916,10 @@
     return TestModelManager::get().getTestModels(filter);
 }
 
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
+}
+
 std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
     const auto& [namedDevice, namedModel] = info.param;
     return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
@@ -936,16 +977,12 @@
 INSTANTIATE_GENERATED_TEST(MemoryDomainTest,
                            [](const TestModel& testModel) { return !testModel.expectFailure; });
 
-INSTANTIATE_GENERATED_TEST(FencedComputeTest, [](const TestModel& testModel) {
-    return !testModel.expectFailure &&
-           std::all_of(testModel.main.outputIndexes.begin(), testModel.main.outputIndexes.end(),
-                       [&testModel](uint32_t index) {
-                           return testModel.main.operands[index].data.size() > 0;
-                       });
-});
+INSTANTIATE_GENERATED_TEST(FencedComputeTest,
+                           [](const TestModel& testModel) { return !testModel.expectFailure; });
 
 INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) {
-    return testModel.hasQuant8CoupledOperands() && testModel.main.operations.size() == 1;
+    return !testModel.expectFailure && testModel.hasQuant8CoupledOperands() &&
+           testModel.main.operations.size() == 1;
 });
 
 INSTANTIATE_GENERATED_TEST(InfiniteLoopTimeoutTest, [](const TestModel& testModel) {
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
index 834d335..4f05c48 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
@@ -41,6 +41,9 @@
 using FilterFn = std::function<bool(const test_helper::TestModel&)>;
 std::vector<NamedModel> getNamedModels(const FilterFn& filter);
 
+using FilterNameFn = std::function<bool(const std::string&)>;
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter);
+
 std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
 
 #define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
@@ -77,6 +80,8 @@
 void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>& preparedModel,
                            const test_helper::TestModel& testModel, TestKind testKind);
 
+void waitForSyncFence(int syncFd);
+
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
 
 #endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H
diff --git a/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp
new file mode 100644
index 0000000..3c0c885
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp
@@ -0,0 +1,1203 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+#include "1.3/Callbacks.h"
+#include "1.3/Utils.h"
+#include "GeneratedTestHarness.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using namespace test_helper;
+using implementation::ExecutionCallback;
+using implementation::PreparedModelCallback;
+using V1_0::RequestArgument;
+using V1_1::ExecutionPreference;
+using V1_2::Constant;
+using V1_2::MeasureTiming;
+using V1_2::OutputShape;
+using V1_2::Timing;
+
+namespace {
+
+const auto kNamedDeviceChoices = testing::ValuesIn(getNamedDevices());
+
+// A 1.3 driver is likely to support at least one of the following operand types.
+const std::vector<TestOperandType> kTestOperandTypeChoicesVector = {
+        TestOperandType::TENSOR_FLOAT32,
+        TestOperandType::TENSOR_FLOAT16,
+        TestOperandType::TENSOR_QUANT8_ASYMM,
+        TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED,
+};
+const auto kTestOperandTypeChoices = testing::ValuesIn(kTestOperandTypeChoicesVector);
+
+bool isInChoices(TestOperandType type) {
+    return std::count(kTestOperandTypeChoicesVector.begin(), kTestOperandTypeChoicesVector.end(),
+                      type) > 0;
+}
+
+bool isFloat(TestOperandType type) {
+    CHECK(isInChoices(type));
+    return type == TestOperandType::TENSOR_FLOAT32 || type == TestOperandType::TENSOR_FLOAT16;
+}
+
+// Create dummy buffers for model constants as well as inputs and outputs.
+// We only care about the size here because we will not check accuracy in validation tests.
+void createDummyData(TestModel* testModel) {
+    for (auto& operand : testModel->main.operands) {
+        if (operand.data != nullptr) continue;
+        switch (operand.lifetime) {
+            case TestOperandLifeTime::SUBGRAPH_INPUT:
+            case TestOperandLifeTime::SUBGRAPH_OUTPUT:
+            case TestOperandLifeTime::CONSTANT_COPY:
+            case TestOperandLifeTime::CONSTANT_REFERENCE: {
+                const uint32_t size = nn::nonExtensionOperandSizeOfData(
+                        static_cast<OperandType>(operand.type), operand.dimensions);
+                operand.data = TestBuffer(size);
+            } break;
+            default:
+                break;
+        }
+    }
+}
+
+TestOperand createInt32Scalar(int32_t value) {
+    return {
+            .type = TestOperandType::INT32,
+            .dimensions = {},
+            .numberOfConsumers = 1,
+            .scale = 0.0f,
+            .zeroPoint = 0,
+            .lifetime = TestOperandLifeTime::CONSTANT_COPY,
+            .data = TestBuffer::createFromVector<int32_t>({value}),
+    };
+}
+
+// Construct a test model with multiple CONV_2D operations with the given operand as inputs.
+// The dimensions of the filters are chosen to ensure outputs has the same dimensions as inputs.
+// We choose CONV_2D operation because it is commonly supported by most drivers.
+TestModel createConvModel(const TestOperand& operand, uint32_t numOperations) {
+    CHECK(isInChoices(operand.type));
+
+    TestOperand weight = {.type = operand.type,
+                          .dimensions = {operand.dimensions[3], 3, 3, operand.dimensions[3]},
+                          .numberOfConsumers = 1,
+                          .scale = isFloat(operand.type) ? 0.0f : 1.0f,
+                          .zeroPoint = 0,
+                          .lifetime = TestOperandLifeTime::CONSTANT_COPY};
+
+    TestOperand bias = {
+            .type = isFloat(operand.type) ? operand.type : TestOperandType::TENSOR_INT32,
+            .dimensions = {operand.dimensions[3]},
+            .numberOfConsumers = 1,
+            .scale = operand.scale * weight.scale,
+            .zeroPoint = 0,
+            .lifetime = TestOperandLifeTime::CONSTANT_COPY};
+
+    TestOperand output = operand;
+    output.numberOfConsumers = 0;
+    output.lifetime = TestOperandLifeTime::SUBGRAPH_OUTPUT;
+
+    const std::vector<TestOperand> operands = {
+            operand,
+            std::move(weight),
+            std::move(bias),
+            createInt32Scalar(1),  // same padding
+            createInt32Scalar(1),  // width stride
+            createInt32Scalar(1),  // height stride
+            createInt32Scalar(0),  // activation = NONE
+            std::move(output),
+    };
+
+    TestModel model;
+    for (uint32_t i = 0; i < numOperations; i++) {
+        model.main.operands.insert(model.main.operands.end(), operands.begin(), operands.end());
+        const uint32_t inputIndex = operands.size() * i;
+        const uint32_t outputIndex = inputIndex + operands.size() - 1;
+        std::vector<uint32_t> inputs(operands.size() - 1);
+        std::iota(inputs.begin(), inputs.end(), inputIndex);
+        model.main.operations.push_back({.type = TestOperationType::CONV_2D,
+                                         .inputs = std::move(inputs),
+                                         .outputs = {outputIndex}});
+        model.main.inputIndexes.push_back(inputIndex);
+        model.main.outputIndexes.push_back(outputIndex);
+    }
+    createDummyData(&model);
+    return model;
+}
+
+// Construct a test model with a single ADD operation with the given operand as input0 and input1.
+// This is to cover additional cases that the CONV_2D model does not support, e.g. arbitrary input
+// operand rank, scalar input operand. We choose ADD operation because it is commonly supported by
+// most drivers.
+TestModel createSingleAddModel(const TestOperand& operand) {
+    CHECK(isInChoices(operand.type));
+
+    TestOperand act = {
+            .type = TestOperandType::INT32,
+            .dimensions = {},
+            .numberOfConsumers = 1,
+            .scale = 0.0f,
+            .zeroPoint = 0,
+            .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT,
+    };
+
+    TestOperand output = operand;
+    output.numberOfConsumers = 0;
+    output.lifetime = TestOperandLifeTime::SUBGRAPH_OUTPUT;
+
+    TestModel model = {
+            .main =
+                    {
+                            .operands =
+                                    {
+                                            operand,
+                                            operand,
+                                            std::move(act),
+                                            output,
+                                    },
+                            .operations = {{.type = TestOperationType::ADD,
+                                            .inputs = {0, 1, 2},
+                                            .outputs = {3}}},
+                            .inputIndexes = {0, 1, 2},
+                            .outputIndexes = {3},
+                    },
+    };
+    createDummyData(&model);
+    return model;
+}
+
+// A dummy invalid IPreparedModel class for MemoryDomainAllocateTest.InvalidPreparedModel
+class InvalidPreparedModel : public IPreparedModel {
+  public:
+    Return<V1_0::ErrorStatus> execute(const V1_0::Request&,
+                                      const sp<V1_0::IExecutionCallback>&) override {
+        return V1_0::ErrorStatus::GENERAL_FAILURE;
+    }
+    Return<V1_0::ErrorStatus> execute_1_2(const V1_0::Request&, V1_2::MeasureTiming,
+                                          const sp<V1_2::IExecutionCallback>&) override {
+        return V1_0::ErrorStatus::GENERAL_FAILURE;
+    }
+    Return<V1_3::ErrorStatus> execute_1_3(const V1_3::Request&, V1_2::MeasureTiming,
+                                          const V1_3::OptionalTimePoint&,
+                                          const V1_3::OptionalTimeoutDuration&,
+                                          const sp<V1_3::IExecutionCallback>&) override {
+        return V1_3::ErrorStatus::GENERAL_FAILURE;
+    }
+    Return<void> executeSynchronously(const V1_0::Request&, V1_2::MeasureTiming,
+                                      executeSynchronously_cb) override {
+        return Void();
+    }
+    Return<void> executeSynchronously_1_3(const V1_3::Request&, V1_2::MeasureTiming,
+                                          const V1_3::OptionalTimePoint&,
+                                          const V1_3::OptionalTimeoutDuration&,
+                                          executeSynchronously_1_3_cb) override {
+        return Void();
+    }
+    Return<void> configureExecutionBurst(const sp<V1_2::IBurstCallback>&,
+                                         const MQDescriptorSync<V1_2::FmqRequestDatum>&,
+                                         const MQDescriptorSync<V1_2::FmqResultDatum>&,
+                                         configureExecutionBurst_cb) override {
+        return Void();
+    }
+    Return<void> executeFenced(const V1_3::Request&, const hidl_vec<hidl_handle>&,
+                               V1_2::MeasureTiming, const V1_3::OptionalTimePoint&,
+                               const V1_3::OptionalTimeoutDuration&,
+                               const V1_3::OptionalTimeoutDuration&, executeFenced_cb) override {
+        return Void();
+    }
+};
+
+}  // namespace
+
+class MemoryDomainTestBase : public testing::Test {
+  protected:
+    MemoryDomainTestBase(sp<IDevice> device, TestOperandType type)
+        : kDevice(std::move(device)),
+          kTestOperandType(type),
+          kTestOperand(kTestOperandMap.at(type)),
+          kTestOperandDataSize(nn::nonExtensionOperandSizeOfData(static_cast<OperandType>(type),
+                                                                 kTestOperand.dimensions)) {}
+
+    void SetUp() override {
+        testing::Test::SetUp();
+        ASSERT_NE(kDevice, nullptr);
+    }
+
+    sp<IPreparedModel> createConvPreparedModel(const TestOperand& testOperand,
+                                               uint32_t numOperations = 1) {
+        const TestModel testModel = createConvModel(testOperand, numOperations);
+        const Model model = createModel(testModel);
+        sp<IPreparedModel> preparedModel;
+        createPreparedModel(kDevice, model, &preparedModel, /*reportSkipping=*/false);
+        return preparedModel;
+    }
+
+    sp<IPreparedModel> createAddPreparedModel(const TestOperand& testOperand) {
+        const TestModel testModel = createSingleAddModel(testOperand);
+        const Model model = createModel(testModel);
+        sp<IPreparedModel> preparedModel;
+        createPreparedModel(kDevice, model, &preparedModel, /*reportSkipping=*/false);
+        return preparedModel;
+    }
+
+    static const std::map<TestOperandType, TestOperand> kTestOperandMap;
+
+    const sp<IDevice> kDevice;
+    const TestOperandType kTestOperandType;
+    const TestOperand& kTestOperand;
+    const uint32_t kTestOperandDataSize;
+};
+
+const std::map<TestOperandType, TestOperand> MemoryDomainTestBase::kTestOperandMap = {
+        {TestOperandType::TENSOR_FLOAT32,
+         {
+                 .type = TestOperandType::TENSOR_FLOAT32,
+                 .dimensions = {1, 32, 32, 8},
+                 .numberOfConsumers = 1,
+                 .scale = 0.0f,
+                 .zeroPoint = 0,
+                 .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT,
+         }},
+        {TestOperandType::TENSOR_FLOAT16,
+         {
+                 .type = TestOperandType::TENSOR_FLOAT16,
+                 .dimensions = {1, 32, 32, 8},
+                 .numberOfConsumers = 1,
+                 .scale = 0.0f,
+                 .zeroPoint = 0,
+                 .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT,
+         }},
+        {TestOperandType::TENSOR_QUANT8_ASYMM,
+         {
+                 .type = TestOperandType::TENSOR_QUANT8_ASYMM,
+                 .dimensions = {1, 32, 32, 8},
+                 .numberOfConsumers = 1,
+                 .scale = 0.5f,
+                 .zeroPoint = 0,
+                 .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT,
+         }},
+        {TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED,
+         {
+                 .type = TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED,
+                 .dimensions = {1, 32, 32, 8},
+                 .numberOfConsumers = 1,
+                 .scale = 0.5f,
+                 .zeroPoint = 0,
+                 .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT,
+         }},
+};
+
+using MemoryDomainAllocateTestParam = std::tuple<NamedDevice, TestOperandType>;
+class MemoryDomainAllocateTest : public MemoryDomainTestBase,
+                                 public testing::WithParamInterface<MemoryDomainAllocateTestParam> {
+  protected:
+    MemoryDomainAllocateTest()
+        : MemoryDomainTestBase(getData(std::get<NamedDevice>(GetParam())),
+                               std::get<TestOperandType>(GetParam())) {}
+
+    struct AllocateTestArgs {
+        hidl_vec<uint32_t> dimensions;
+        hidl_vec<sp<IPreparedModel>> preparedModels;
+        hidl_vec<BufferRole> inputRoles;
+        hidl_vec<BufferRole> outputRoles;
+    };
+
+    // Validation test for IDevice::allocate. The driver is expected to fail with INVALID_ARGUMENT,
+    // or GENERAL_FAILURE if memory domain is not supported.
+    void validateAllocate(AllocateTestArgs args) {
+        const auto ret = kDevice->allocate(
+                {.dimensions = std::move(args.dimensions)}, std::move(args.preparedModels),
+                std::move(args.inputRoles), std::move(args.outputRoles),
+                [](ErrorStatus status, const sp<IBuffer>& buffer, uint32_t token) {
+                    EXPECT_TRUE(status == ErrorStatus::INVALID_ARGUMENT ||
+                                status == ErrorStatus::GENERAL_FAILURE);
+                    EXPECT_EQ(buffer, nullptr);
+                    EXPECT_EQ(token, 0);
+                });
+        ASSERT_TRUE(ret.isOk());
+    }
+
+    void testConflictOperands(const sp<IPreparedModel>& model1, const sp<IPreparedModel>& model2) {
+        validateAllocate({
+                .preparedModels = {model1, model2},
+                .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+                               {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+        });
+        validateAllocate({
+                .preparedModels = {model1, model2},
+                .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+                .outputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+        });
+        validateAllocate({
+                .preparedModels = {model1, model2},
+                .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+                                {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+        });
+    }
+};
+
+TEST_P(MemoryDomainAllocateTest, EmptyRole) {
+    // Test with empty prepared models and roles.
+    validateAllocate({});
+
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    if (preparedModel == nullptr) return;
+
+    // Test again with non-empty prepared models but empty roles.
+    validateAllocate({
+            .preparedModels = {preparedModel},
+    });
+}
+
+TEST_P(MemoryDomainAllocateTest, NullptrPreparedModel) {
+    // Test with nullptr prepared model as input role.
+    validateAllocate({
+            .preparedModels = {nullptr},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+    });
+
+    // Test with nullptr prepared model as output role.
+    validateAllocate({
+            .preparedModels = {nullptr},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+    });
+}
+
+TEST_P(MemoryDomainAllocateTest, InvalidPreparedModel) {
+    sp<InvalidPreparedModel> invalidPreparedModel = new InvalidPreparedModel();
+
+    // Test with invalid prepared model as input role.
+    validateAllocate({
+            .preparedModels = {invalidPreparedModel},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+    });
+
+    // Test with invalid prepared model as output role.
+    validateAllocate({
+            .preparedModels = {invalidPreparedModel},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+    });
+}
+
+TEST_P(MemoryDomainAllocateTest, InvalidModelIndex) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    if (preparedModel == nullptr) return;
+
+    // This should fail, because the model index is out of bound.
+    validateAllocate({
+            .preparedModels = {preparedModel},
+            .inputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+    });
+
+    // This should fail, because the model index is out of bound.
+    validateAllocate({
+            .preparedModels = {preparedModel},
+            .outputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+    });
+}
+
+TEST_P(MemoryDomainAllocateTest, InvalidIOIndex) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    if (preparedModel == nullptr) return;
+
+    // This should fail, because the model only has one input.
+    validateAllocate({
+            .preparedModels = {preparedModel},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 1, .frequency = 1.0f}},
+    });
+
+    // This should fail, because the model only has one output.
+    validateAllocate({
+            .preparedModels = {preparedModel},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 1, .frequency = 1.0f}},
+    });
+}
+
+TEST_P(MemoryDomainAllocateTest, InvalidFrequency) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    if (preparedModel == nullptr) return;
+
+    for (float invalidFreq : {10.0f, 0.0f, -0.5f}) {
+        // Test with invalid frequency for input roles.
+        validateAllocate({
+                .preparedModels = {preparedModel},
+                .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = invalidFreq}},
+        });
+        // Test with invalid frequency for output roles.
+        validateAllocate({
+                .preparedModels = {preparedModel},
+                .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = invalidFreq}},
+        });
+    }
+}
+
+TEST_P(MemoryDomainAllocateTest, SameRoleSpecifiedTwice) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    if (preparedModel == nullptr) return;
+
+    // Same role with same model index.
+    validateAllocate({
+            .preparedModels = {preparedModel},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+                           {.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+    });
+    validateAllocate({
+            .preparedModels = {preparedModel},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+                            {.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+    });
+
+    // Different model indexes, but logically referring to the same role.
+    validateAllocate({
+            .preparedModels = {preparedModel, preparedModel},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+                           {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+    });
+    validateAllocate({
+            .preparedModels = {preparedModel, preparedModel},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+                            {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+    });
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictOperandType) {
+    const std::map<TestOperandType, TestOperandType> conflictTypeMap = {
+            {TestOperandType::TENSOR_FLOAT32, TestOperandType::TENSOR_FLOAT16},
+            {TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_FLOAT32},
+            {TestOperandType::TENSOR_QUANT8_ASYMM, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+            {TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED, TestOperandType::TENSOR_QUANT8_ASYMM},
+    };
+
+    TestOperand conflictTestOperand = kTestOperand;
+    const auto it = conflictTypeMap.find(kTestOperandType);
+    ASSERT_FALSE(it == conflictTypeMap.end());
+    conflictTestOperand.type = it->second;
+
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand);
+    if (preparedModel == nullptr || conflictPreparedModel == nullptr) return;
+    testConflictOperands(preparedModel, conflictPreparedModel);
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictScale) {
+    if (isFloat(kTestOperandType)) return;
+
+    TestOperand conflictTestOperand = kTestOperand;
+    ASSERT_NE(conflictTestOperand.scale, 1.0f);
+    conflictTestOperand.scale = 1.0f;
+
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand);
+    if (preparedModel == nullptr || conflictPreparedModel == nullptr) return;
+    testConflictOperands(preparedModel, conflictPreparedModel);
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictZeroPoint) {
+    if (isFloat(kTestOperandType)) return;
+
+    TestOperand conflictTestOperand = kTestOperand;
+    ASSERT_NE(conflictTestOperand.zeroPoint, 10);
+    conflictTestOperand.zeroPoint = 10;
+
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand);
+    if (preparedModel == nullptr || conflictPreparedModel == nullptr) return;
+    testConflictOperands(preparedModel, conflictPreparedModel);
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictRankBetweenRoles) {
+    TestOperand conflictTestOperand = kTestOperand;
+    conflictTestOperand.dimensions.pop_back();
+
+    auto preparedModel = createAddPreparedModel(kTestOperand);
+    auto conflictPreparedModel = createAddPreparedModel(conflictTestOperand);
+    if (preparedModel == nullptr || conflictPreparedModel == nullptr) return;
+    testConflictOperands(preparedModel, conflictPreparedModel);
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictDimensionsBetweenRoles) {
+    TestOperand conflictTestOperand = kTestOperand;
+    conflictTestOperand.dimensions[0] = 4;
+
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand);
+    if (preparedModel == nullptr || conflictPreparedModel == nullptr) return;
+    testConflictOperands(preparedModel, conflictPreparedModel);
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictRankBetweenRoleAndDesc) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    if (preparedModel == nullptr) return;
+
+    auto badDimensions = kTestOperand.dimensions;
+    badDimensions.pop_back();
+
+    validateAllocate({
+            .dimensions = badDimensions,
+            .preparedModels = {preparedModel},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+    });
+    validateAllocate({
+            .dimensions = badDimensions,
+            .preparedModels = {preparedModel},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+    });
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictDimensionsBetweenRoleAndDesc) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    if (preparedModel == nullptr) return;
+
+    auto badDimensions = kTestOperand.dimensions;
+    badDimensions[0] = 4;
+
+    validateAllocate({
+            .dimensions = badDimensions,
+            .preparedModels = {preparedModel},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+    });
+    validateAllocate({
+            .dimensions = badDimensions,
+            .preparedModels = {preparedModel},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+    });
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictRankWithScalarRole) {
+    auto preparedModel = createAddPreparedModel(kTestOperand);
+    if (preparedModel == nullptr) return;
+
+    // This should fail, because the target operand is a scalar but a non-empty dimension is
+    // specified.
+    validateAllocate({
+            .dimensions = {1},
+            .preparedModels = {preparedModel},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 2, .frequency = 1.0f}},
+    });
+}
+
+std::string printMemoryDomainAllocateTest(
+        const testing::TestParamInfo<MemoryDomainAllocateTestParam>& info) {
+    const auto& [namedDevice, operandType] = info.param;
+    const std::string type = toString(static_cast<OperandType>(operandType));
+    return gtestCompliantName(getName(namedDevice) + "_" + type);
+}
+
+INSTANTIATE_TEST_CASE_P(TestMemoryDomain, MemoryDomainAllocateTest,
+                        testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices),
+                        printMemoryDomainAllocateTest);
+
+class MemoryDomainCopyTestBase : public MemoryDomainTestBase {
+  protected:
+    MemoryDomainCopyTestBase(sp<IDevice> device, TestOperandType type)
+        : MemoryDomainTestBase(std::move(device), type) {}
+
+    // Allocates device memory for roles of a single prepared model.
+    // Returns {IBuffer, token} if success; returns {nullptr, 0} if not supported.
+    std::pair<sp<IBuffer>, uint32_t> allocateBuffer(const sp<IPreparedModel>& preparedModel,
+                                                    const std::vector<uint32_t>& inputIndexes,
+                                                    const std::vector<uint32_t>& outputIndexes,
+                                                    const std::vector<uint32_t>& dimensions) {
+        if (preparedModel == nullptr) {
+            return {nullptr, 0};
+        }
+
+        hidl_vec<BufferRole> inputRoles(inputIndexes.size()), outputRoles(outputIndexes.size());
+        auto trans = [](uint32_t ind) -> BufferRole {
+            return {.modelIndex = 0, .ioIndex = ind, .frequency = 1.0f};
+        };
+        std::transform(inputIndexes.begin(), inputIndexes.end(), inputRoles.begin(), trans);
+        std::transform(outputIndexes.begin(), outputIndexes.end(), outputRoles.begin(), trans);
+
+        sp<IBuffer> buffer;
+        uint32_t token = 0;
+        const auto ret = kDevice->allocate(
+                {.dimensions = dimensions}, {preparedModel}, std::move(inputRoles),
+                std::move(outputRoles),
+                [&buffer, &token](ErrorStatus err, const sp<IBuffer>& buf, uint32_t tok) {
+                    if (err == ErrorStatus::NONE) {
+                        EXPECT_NE(buf, nullptr);
+                        EXPECT_GT(tok, 0);
+                        buffer = buf;
+                        token = tok;
+                    } else {
+                        EXPECT_EQ(err, ErrorStatus::GENERAL_FAILURE);
+                        EXPECT_EQ(buf, nullptr);
+                        EXPECT_EQ(tok, 0);
+                    }
+                });
+        EXPECT_TRUE(ret.isOk());
+        return {std::move(buffer), token};
+    }
+
+    std::pair<sp<IBuffer>, uint32_t> allocateBuffer(const sp<IPreparedModel>& preparedModel,
+                                                    const std::vector<uint32_t>& inputIndexes,
+                                                    const std::vector<uint32_t>& outputIndexes) {
+        return allocateBuffer(preparedModel, inputIndexes, outputIndexes, {});
+    }
+
+    hidl_memory allocateSharedMemory(uint32_t size) {
+        hidl_memory memory = nn::allocateSharedMemory(size);
+        EXPECT_EQ(memory.size(), size);
+        return memory;
+    }
+
+    void testCopyFrom(const sp<IBuffer>& buffer, const hidl_memory& memory,
+                      const std::vector<uint32_t>& dimensions, ErrorStatus expectedStatus) {
+        const auto ret = buffer->copyFrom(memory, dimensions);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(static_cast<ErrorStatus>(ret), expectedStatus);
+    }
+
+    void testCopyTo(const sp<IBuffer>& buffer, const hidl_memory& memory,
+                    ErrorStatus expectedStatus) {
+        const auto ret = buffer->copyTo(memory);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(static_cast<ErrorStatus>(ret), expectedStatus);
+    }
+
+    void initializeDeviceMemory(const sp<IBuffer>& buffer) {
+        hidl_memory memory = nn::allocateSharedMemory(kTestOperandDataSize);
+        ASSERT_EQ(memory.size(), kTestOperandDataSize);
+        testCopyFrom(buffer, memory, kTestOperand.dimensions, ErrorStatus::NONE);
+    }
+};
+
+using MemoryDomainCopyTestParam = std::tuple<NamedDevice, TestOperandType>;
+class MemoryDomainCopyTest : public MemoryDomainCopyTestBase,
+                             public testing::WithParamInterface<MemoryDomainCopyTestParam> {
+  protected:
+    MemoryDomainCopyTest()
+        : MemoryDomainCopyTestBase(getData(std::get<NamedDevice>(GetParam())),
+                                   std::get<TestOperandType>(GetParam())) {}
+};
+
+TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidMemorySize) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+    if (buffer == nullptr) return;
+
+    uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2;
+    hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1);
+    hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2);
+    testCopyFrom(buffer, badMemory1, {}, ErrorStatus::INVALID_ARGUMENT);
+    testCopyFrom(buffer, badMemory2, {}, ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidMemorySize_DynamicShape) {
+    TestOperand testOperand = kTestOperand;
+    testOperand.dimensions[0] = 0;
+    auto preparedModel = createConvPreparedModel(testOperand);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+    if (buffer == nullptr) return;
+
+    uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2;
+    hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1);
+    hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2);
+    hidl_memory goodMemory = allocateSharedMemory(kTestOperandDataSize);
+
+    auto badDimensions = kTestOperand.dimensions;
+    badDimensions[0] = 2;
+
+    testCopyFrom(buffer, badMemory1, kTestOperand.dimensions, ErrorStatus::INVALID_ARGUMENT);
+    testCopyFrom(buffer, badMemory2, kTestOperand.dimensions, ErrorStatus::INVALID_ARGUMENT);
+    testCopyFrom(buffer, goodMemory, kTestOperand.dimensions, ErrorStatus::NONE);
+    testCopyFrom(buffer, goodMemory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidDimensions) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+    if (buffer == nullptr) return;
+
+    hidl_memory memory = allocateSharedMemory(kTestOperandDataSize);
+
+    std::vector<uint32_t> badDimensions;
+    badDimensions = kTestOperand.dimensions;
+    badDimensions.pop_back();
+    testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+    badDimensions = kTestOperand.dimensions;
+    badDimensions[0] = 2;
+    testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+    badDimensions = kTestOperand.dimensions;
+    badDimensions[0] = 0;
+    testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+    testCopyFrom(buffer, memory, {}, ErrorStatus::NONE);
+    testCopyFrom(buffer, memory, kTestOperand.dimensions, ErrorStatus::NONE);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidDimensions_DynamicShape) {
+    TestOperand testOperand = kTestOperand;
+    testOperand.dimensions[0] = 0;
+    auto preparedModel = createConvPreparedModel(testOperand);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+    if (buffer == nullptr) return;
+
+    hidl_memory memory = allocateSharedMemory(kTestOperandDataSize);
+
+    std::vector<uint32_t> badDimensions;
+    badDimensions = kTestOperand.dimensions;
+    badDimensions.pop_back();
+    testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+    badDimensions = kTestOperand.dimensions;
+    badDimensions[0] = 2;
+    badDimensions[3] = 4;
+    testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+    badDimensions = kTestOperand.dimensions;
+    badDimensions[0] = 1;
+    badDimensions[3] = 0;
+    testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+    testCopyFrom(buffer, memory, {}, ErrorStatus::INVALID_ARGUMENT);
+    testCopyFrom(buffer, memory, kTestOperand.dimensions, ErrorStatus::NONE);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyTo_UninitializedMemory) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+    if (buffer == nullptr) return;
+
+    hidl_memory memory = allocateSharedMemory(kTestOperandDataSize);
+    testCopyTo(buffer, memory, ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyTo_InvalidMemorySize) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+    if (buffer == nullptr) return;
+
+    uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2;
+    hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1);
+    hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2);
+    hidl_memory goodMemory = allocateSharedMemory(kTestOperandDataSize);
+
+    initializeDeviceMemory(buffer);
+    testCopyTo(buffer, badMemory1, ErrorStatus::INVALID_ARGUMENT);
+    testCopyTo(buffer, badMemory2, ErrorStatus::INVALID_ARGUMENT);
+    testCopyTo(buffer, goodMemory, ErrorStatus::NONE);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyTo_InvalidMemorySize_DynamicShape) {
+    TestOperand testOperand = kTestOperand;
+    testOperand.dimensions[0] = 0;
+    auto preparedModel = createConvPreparedModel(testOperand);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+    if (buffer == nullptr) return;
+
+    uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2;
+    hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1);
+    hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2);
+    hidl_memory goodMemory = allocateSharedMemory(kTestOperandDataSize);
+
+    initializeDeviceMemory(buffer);
+    testCopyTo(buffer, badMemory1, ErrorStatus::INVALID_ARGUMENT);
+    testCopyTo(buffer, badMemory2, ErrorStatus::INVALID_ARGUMENT);
+    testCopyTo(buffer, goodMemory, ErrorStatus::NONE);
+}
+
+std::string printMemoryDomainCopyTest(
+        const testing::TestParamInfo<MemoryDomainCopyTestParam>& info) {
+    const auto& [namedDevice, operandType] = info.param;
+    const std::string type = toString(static_cast<OperandType>(operandType));
+    return gtestCompliantName(getName(namedDevice) + "_" + type);
+}
+
+INSTANTIATE_TEST_CASE_P(TestMemoryDomain, MemoryDomainCopyTest,
+                        testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices),
+                        printMemoryDomainCopyTest);
+
+using MemoryDomainExecutionTestParam = std::tuple<NamedDevice, TestOperandType, Executor>;
+class MemoryDomainExecutionTest
+    : public MemoryDomainCopyTestBase,
+      public testing::WithParamInterface<MemoryDomainExecutionTestParam> {
+  protected:
+    MemoryDomainExecutionTest()
+        : MemoryDomainCopyTestBase(getData(std::get<NamedDevice>(GetParam())),
+                                   std::get<TestOperandType>(GetParam())) {}
+
+    Request::MemoryPool createSharedMemoryPool(uint32_t size) {
+        hidl_memory memory = allocateSharedMemory(size);
+        Request::MemoryPool pool;
+        pool.hidlMemory(memory);
+        return pool;
+    }
+
+    Request::MemoryPool createDeviceMemoryPool(uint32_t token) {
+        Request::MemoryPool pool;
+        pool.token(token);
+        return pool;
+    }
+
+    void testExecution(const sp<IPreparedModel>& preparedModel, const Request& request,
+                       ErrorStatus expectedStatus) {
+        switch (kExecutor) {
+            case Executor::ASYNC:
+                EXPECT_EQ(executeAsync(preparedModel, request), expectedStatus);
+                break;
+            case Executor::SYNC:
+                EXPECT_EQ(executeSync(preparedModel, request), expectedStatus);
+                break;
+            case Executor::FENCED:
+                EXPECT_EQ(executeFenced(preparedModel, request), expectedStatus);
+                break;
+            default:
+                ASSERT_TRUE(false);
+        }
+    }
+
+    ErrorStatus executeAsync(const sp<IPreparedModel>& preparedModel, const Request& request) {
+        ErrorStatus executionStatus;
+
+        // launch execution
+        sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+        const auto ret =
+                preparedModel->execute_1_3(request, MeasureTiming::NO, {}, {}, executionCallback);
+        EXPECT_TRUE(ret.isOk());
+        executionStatus = static_cast<ErrorStatus>(ret);
+
+        // retrieve execution status
+        executionCallback->wait();
+        if (executionStatus == ErrorStatus::NONE) {
+            executionStatus = executionCallback->getStatus();
+        } else {
+            EXPECT_EQ(executionStatus, executionCallback->getStatus());
+        }
+        const auto timing = executionCallback->getTiming();
+        EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
+        EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
+        if (executionStatus != ErrorStatus::NONE) {
+            EXPECT_EQ(executionCallback->getOutputShapes().size(), 0);
+        }
+        return executionStatus;
+    }
+
+    ErrorStatus executeSync(const sp<IPreparedModel>& preparedModel, const Request& request) {
+        ErrorStatus executionStatus;
+        const auto ret = preparedModel->executeSynchronously_1_3(
+                request, MeasureTiming::NO, {}, {},
+                [&executionStatus](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
+                                   const Timing& time) {
+                    executionStatus = error;
+                    EXPECT_EQ(UINT64_MAX, time.timeOnDevice);
+                    EXPECT_EQ(UINT64_MAX, time.timeInDriver);
+                    if (executionStatus != ErrorStatus::NONE) {
+                        EXPECT_EQ(shapes.size(), 0);
+                    }
+                });
+        EXPECT_TRUE(ret.isOk());
+        return executionStatus;
+    }
+
+    ErrorStatus executeFenced(const sp<IPreparedModel>& preparedModel, const Request& request) {
+        ErrorStatus executionStatus;
+        hidl_handle syncFenceHandle;
+        sp<IFencedExecutionCallback> fencedCallback;
+        const auto callbackFunc = [&executionStatus, &syncFenceHandle, &fencedCallback](
+                                          ErrorStatus error, const hidl_handle& handle,
+                                          const sp<IFencedExecutionCallback>& callback) {
+            executionStatus = error;
+            syncFenceHandle = handle;
+            fencedCallback = callback;
+        };
+        Return<void> ret = preparedModel->executeFenced(request, {}, MeasureTiming::NO, {}, {}, {},
+                                                        callbackFunc);
+        EXPECT_TRUE(ret.isOk());
+        if (executionStatus != ErrorStatus::NONE) {
+            EXPECT_EQ(syncFenceHandle.getNativeHandle(), nullptr);
+            EXPECT_EQ(fencedCallback, nullptr);
+            return executionStatus;
+        }
+        if (syncFenceHandle.getNativeHandle()) {
+            waitForSyncFence(syncFenceHandle.getNativeHandle()->data[0]);
+        }
+        EXPECT_NE(fencedCallback, nullptr);
+        ret = fencedCallback->getExecutionInfo(
+                [&executionStatus](ErrorStatus error, Timing t, Timing) {
+                    executionStatus = error;
+                    EXPECT_EQ(UINT64_MAX, t.timeOnDevice);
+                    EXPECT_EQ(UINT64_MAX, t.timeInDriver);
+                });
+        EXPECT_TRUE(ret.isOk());
+        return executionStatus;
+    }
+
+    const Executor kExecutor = std::get<Executor>(GetParam());
+};
+
+TEST_P(MemoryDomainExecutionTest, InvalidToken) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    if (preparedModel == nullptr) return;
+
+    Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
+    Request::MemoryPool badDeviceMemory1 = createDeviceMemoryPool(0);    // Invalid token.
+    Request::MemoryPool badDeviceMemory2 = createDeviceMemoryPool(100);  // Unknown token.
+    RequestArgument sharedMemoryArg = {
+            .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+    RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
+
+    testExecution(preparedModel,
+                  {.inputs = {deviceMemoryArg},
+                   .outputs = {sharedMemoryArg},
+                   .pools = {sharedMemory, badDeviceMemory1}},
+                  ErrorStatus::INVALID_ARGUMENT);
+    testExecution(preparedModel,
+                  {.inputs = {deviceMemoryArg},
+                   .outputs = {sharedMemoryArg},
+                   .pools = {sharedMemory, badDeviceMemory2}},
+                  ErrorStatus::INVALID_ARGUMENT);
+    testExecution(preparedModel,
+                  {.inputs = {sharedMemoryArg},
+                   .outputs = {deviceMemoryArg},
+                   .pools = {sharedMemory, badDeviceMemory1}},
+                  ErrorStatus::INVALID_ARGUMENT);
+    testExecution(preparedModel,
+                  {.inputs = {sharedMemoryArg},
+                   .outputs = {deviceMemoryArg},
+                   .pools = {sharedMemory, badDeviceMemory2}},
+                  ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainExecutionTest, InvalidPreparedModel) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+    if (buffer == nullptr) return;
+    auto badPreparedModel = createConvPreparedModel(kTestOperand);
+    if (badPreparedModel == nullptr) return;
+
+    Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
+    Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+    RequestArgument sharedMemoryArg = {
+            .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+    RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
+
+    // This should fail, because the buffer is not allocated for badPreparedModel.
+    initializeDeviceMemory(buffer);
+    testExecution(badPreparedModel,
+                  {.inputs = {deviceMemoryArg},
+                   .outputs = {sharedMemoryArg},
+                   .pools = {sharedMemory, deviceMemory}},
+                  ErrorStatus::INVALID_ARGUMENT);
+    testExecution(badPreparedModel,
+                  {.inputs = {sharedMemoryArg},
+                   .outputs = {deviceMemoryArg},
+                   .pools = {sharedMemory, deviceMemory}},
+                  ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainExecutionTest, InvalidIOIndex) {
+    auto preparedModel = createConvPreparedModel(kTestOperand, 2);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {});
+    if (buffer == nullptr) return;
+
+    Request::MemoryPool sharedMemory1 = createSharedMemoryPool(kTestOperandDataSize);
+    Request::MemoryPool sharedMemory2 = createSharedMemoryPool(kTestOperandDataSize);
+    Request::MemoryPool sharedMemory3 = createSharedMemoryPool(kTestOperandDataSize);
+    Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+    RequestArgument sharedMemoryArg1 = {
+            .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+    RequestArgument sharedMemoryArg2 = {
+            .location = {.poolIndex = 1, .offset = 0, .length = kTestOperandDataSize}};
+    RequestArgument sharedMemoryArg3 = {
+            .location = {.poolIndex = 2, .offset = 0, .length = kTestOperandDataSize}};
+    RequestArgument deviceMemoryArg = {.location = {.poolIndex = 3}};
+
+    // This should fail, because the device memory is not allocated for input 1.
+    initializeDeviceMemory(buffer);
+    testExecution(preparedModel,
+                  {.inputs = {sharedMemoryArg1, deviceMemoryArg},
+                   .outputs = {sharedMemoryArg2, sharedMemoryArg3},
+                   .pools = {sharedMemory1, sharedMemory2, sharedMemory3, deviceMemory}},
+                  ErrorStatus::INVALID_ARGUMENT);
+
+    // This should fail, because the device memory is not allocated for output 1.
+    testExecution(preparedModel,
+                  {.inputs = {sharedMemoryArg1, sharedMemoryArg2},
+                   .outputs = {sharedMemoryArg3, deviceMemoryArg},
+                   .pools = {sharedMemory1, sharedMemory2, sharedMemory3, deviceMemory}},
+                  ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainExecutionTest, InvalidIOType) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto [inputBuffer, inputToken] = allocateBuffer(preparedModel, {0}, {});
+    auto [outputBuffer, outputToken] = allocateBuffer(preparedModel, {}, {0});
+    if (inputBuffer == nullptr || outputBuffer == nullptr) return;
+
+    Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
+    Request::MemoryPool deviceMemory = createDeviceMemoryPool(inputToken);
+    RequestArgument sharedMemoryArg = {
+            .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+    RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
+
+    // This should fail, because the device memory is allocated for input but used as output.
+    testExecution(preparedModel,
+                  {.inputs = {sharedMemoryArg},
+                   .outputs = {deviceMemoryArg},
+                   .pools = {sharedMemory, deviceMemory}},
+                  ErrorStatus::INVALID_ARGUMENT);
+
+    // This should fail, because the device memory is allocated for output but used as input.
+    deviceMemory.token(outputToken);
+    initializeDeviceMemory(outputBuffer);
+    testExecution(preparedModel,
+                  {.inputs = {deviceMemoryArg},
+                   .outputs = {sharedMemoryArg},
+                   .pools = {sharedMemory, deviceMemory}},
+                  ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainExecutionTest, UninitializedMemory) {
+    auto preparedModel = createConvPreparedModel(kTestOperand);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+    if (buffer == nullptr) return;
+
+    Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
+    Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+    RequestArgument sharedMemoryArg = {
+            .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+    RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
+
+    // This should fail, because the device memory is not initialized.
+    testExecution(preparedModel,
+                  {.inputs = {deviceMemoryArg},
+                   .outputs = {sharedMemoryArg},
+                   .pools = {sharedMemory, deviceMemory}},
+                  ErrorStatus::GENERAL_FAILURE);
+
+    // This should initialize the device memory.
+    testExecution(preparedModel,
+                  {.inputs = {sharedMemoryArg},
+                   .outputs = {deviceMemoryArg},
+                   .pools = {sharedMemory, deviceMemory}},
+                  ErrorStatus::NONE);
+
+    // Test again with initialized device memory.
+    testExecution(preparedModel,
+                  {.inputs = {deviceMemoryArg},
+                   .outputs = {sharedMemoryArg},
+                   .pools = {sharedMemory, deviceMemory}},
+                  ErrorStatus::NONE);
+}
+
+TEST_P(MemoryDomainExecutionTest, SameRequestMultipleRoles) {
+    auto preparedModel = createConvPreparedModel(kTestOperand, 2);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0, 1}, {0, 1});
+    if (buffer == nullptr) return;
+
+    Request::MemoryPool sharedMemory1 = createSharedMemoryPool(kTestOperandDataSize);
+    Request::MemoryPool sharedMemory2 = createSharedMemoryPool(kTestOperandDataSize);
+    Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+    RequestArgument sharedMemoryArg1 = {
+            .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+    RequestArgument sharedMemoryArg2 = {
+            .location = {.poolIndex = 1, .offset = 0, .length = kTestOperandDataSize}};
+    RequestArgument deviceMemoryArg = {.location = {.poolIndex = 2}};
+
+    // This should fail, because the same device memory cannot be used for both input and output.
+    initializeDeviceMemory(buffer);
+    testExecution(preparedModel,
+                  {.inputs = {deviceMemoryArg, sharedMemoryArg1},
+                   .outputs = {deviceMemoryArg, sharedMemoryArg2},
+                   .pools = {sharedMemory1, sharedMemory2, deviceMemory}},
+                  ErrorStatus::INVALID_ARGUMENT);
+
+    // This should fail, because the same device memory cannot be used for multiple outputs.
+    testExecution(preparedModel,
+                  {.inputs = {sharedMemoryArg1, sharedMemoryArg2},
+                   .outputs = {deviceMemoryArg, deviceMemoryArg},
+                   .pools = {sharedMemory1, sharedMemory2, deviceMemory}},
+                  ErrorStatus::INVALID_ARGUMENT);
+
+    // The same device memory can be used for multiple inputs.
+    initializeDeviceMemory(buffer);
+    testExecution(preparedModel,
+                  {.inputs = {deviceMemoryArg, deviceMemoryArg},
+                   .outputs = {sharedMemoryArg1, sharedMemoryArg2},
+                   .pools = {sharedMemory1, sharedMemory2, deviceMemory}},
+                  ErrorStatus::NONE);
+}
+
+TEST_P(MemoryDomainExecutionTest, InvalidDimensions) {
+    // FENCED execution does not support dynamic shape.
+    if (kExecutor == Executor::FENCED) return;
+
+    TestOperand testOperand = kTestOperand;
+    testOperand.dimensions[0] = 0;
+    auto preparedModel = createConvPreparedModel(testOperand);
+    auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}, kTestOperand.dimensions);
+    if (buffer == nullptr) return;
+
+    Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
+    Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+    auto badDimensions = kTestOperand.dimensions;
+    badDimensions[0] = 2;
+    RequestArgument sharedMemoryArg = {
+            .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize},
+            .dimensions = badDimensions};
+    RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
+    RequestArgument deviceMemoryArgWithBadDimensions = {.location = {.poolIndex = 1},
+                                                        .dimensions = badDimensions};
+
+    initializeDeviceMemory(buffer);
+    testExecution(preparedModel,
+                  {.inputs = {deviceMemoryArgWithBadDimensions},
+                   .outputs = {sharedMemoryArg},
+                   .pools = {sharedMemory, deviceMemory}},
+                  ErrorStatus::INVALID_ARGUMENT);
+
+    testExecution(preparedModel,
+                  {.inputs = {sharedMemoryArg},
+                   .outputs = {deviceMemoryArgWithBadDimensions},
+                   .pools = {sharedMemory, deviceMemory}},
+                  ErrorStatus::INVALID_ARGUMENT);
+
+    testExecution(preparedModel,
+                  {.inputs = {sharedMemoryArg},
+                   .outputs = {deviceMemoryArg},
+                   .pools = {sharedMemory, deviceMemory}},
+                  ErrorStatus::GENERAL_FAILURE);
+}
+
+const auto kExecutorChoices = testing::Values(Executor::ASYNC, Executor::SYNC, Executor::FENCED);
+
+std::string printMemoryDomainExecutionTest(
+        const testing::TestParamInfo<MemoryDomainExecutionTestParam>& info) {
+    const auto& [namedDevice, operandType, executor] = info.param;
+    const std::string type = toString(static_cast<OperandType>(operandType));
+    const std::string executorStr = toString(executor);
+    return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + executorStr);
+}
+
+INSTANTIATE_TEST_CASE_P(TestMemoryDomain, MemoryDomainExecutionTest,
+                        testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices,
+                                         kExecutorChoices),
+                        printMemoryDomainExecutionTest);
+
+}  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
index 879989e..2ef1e8f 100644
--- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
@@ -214,7 +214,8 @@
 }
 
 void runExecutionTest(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
-                      const Request& request, bool synchronous, DeadlineBoundType deadlineBound) {
+                      const Request& request, const ExecutionContext& context, bool synchronous,
+                      DeadlineBoundType deadlineBound) {
     const ExecutionFunction execute = synchronous ? executeSynchronously : executeAsynchronously;
     const auto deadline = makeDeadline(deadlineBound);
 
@@ -261,7 +262,7 @@
     // Retrieve execution results.
     ASSERT_TRUE(nn::compliantWithV1_0(request));
     const V1_0::Request request10 = nn::convertToV1_0(request);
-    const std::vector<TestBuffer> outputs = getOutputBuffers(request10);
+    const std::vector<TestBuffer> outputs = context.getOutputBuffers(request10);
 
     // We want "close-enough" results.
     if (status == ErrorStatus::NONE) {
@@ -270,10 +271,11 @@
 }
 
 void runExecutionTests(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
-                       const Request& request) {
+                       const Request& request, const ExecutionContext& context) {
     for (bool synchronous : {false, true}) {
         for (auto deadlineBound : deadlineBounds) {
-            runExecutionTest(preparedModel, testModel, request, synchronous, deadlineBound);
+            runExecutionTest(preparedModel, testModel, request, context, synchronous,
+                             deadlineBound);
         }
     }
 }
@@ -291,8 +293,9 @@
     if (preparedModel == nullptr) return;
 
     // run execution tests
-    const Request request = nn::convertToV1_3(createRequest(testModel));
-    runExecutionTests(preparedModel, testModel, request);
+    ExecutionContext context;
+    const Request request = nn::convertToV1_3(context.createRequest(testModel));
+    runExecutionTests(preparedModel, testModel, request, context);
 }
 
 class DeadlineTest : public GeneratedTestBase {};
diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
index 6ff9dfd..c78439c 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
@@ -23,7 +23,6 @@
 #include "ExecutionBurstServer.h"
 #include "GeneratedTestHarness.h"
 #include "TestHarness.h"
-#include "Utils.h"
 
 #include <android-base/logging.h>
 #include <chrono>
@@ -43,6 +42,8 @@
 using V1_2::Timing;
 using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback;
 
+using BurstExecutionMutation = std::function<void(std::vector<FmqRequestDatum>*)>;
+
 // This constant value represents the length of an FMQ that is large enough to
 // return a result from a burst execution for all of the generated test cases.
 constexpr size_t kExecutionBurstChannelLength = 1024;
@@ -122,13 +123,13 @@
 
 // Primary validation function. This function will take a valid serialized
 // request, apply a mutation to it to invalidate the serialized request, then
-// pass it to interface calls that use the serialized request. Note that the
-// serialized request here is passed by value, and any mutation to the
-// serialized request does not leave this function.
+// pass it to interface calls that use the serialized request.
 static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiver,
-                     const std::string& message, std::vector<FmqRequestDatum> serialized,
-                     const std::function<void(std::vector<FmqRequestDatum>*)>& mutation) {
-    mutation(&serialized);
+                     const std::string& message,
+                     const std::vector<FmqRequestDatum>& originalSerialized,
+                     const BurstExecutionMutation& mutate) {
+    std::vector<FmqRequestDatum> serialized = originalSerialized;
+    mutate(&serialized);
 
     // skip if packet is too large to send
     if (serialized.size() > kExecutionBurstChannelLength) {
@@ -302,8 +303,7 @@
     // collect serialized result by running regular burst
     const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] =
             controllerRegular->compute(request, MeasureTiming::NO, keys);
-    const V1_0::ErrorStatus statusRegular =
-            nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nRegular));
+    const V1_0::ErrorStatus statusRegular = nn::legacyConvertResultCodeToErrorStatus(nRegular);
     EXPECT_FALSE(fallbackRegular);
 
     // skip test if regular burst output isn't useful for testing a failure
@@ -319,8 +319,7 @@
     // large enough to return the serialized result
     const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] =
             controllerSmall->compute(request, MeasureTiming::NO, keys);
-    const V1_0::ErrorStatus statusSmall =
-            nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nSmall));
+    const V1_0::ErrorStatus statusSmall = nn::legacyConvertResultCodeToErrorStatus(nSmall);
     EXPECT_NE(V1_0::ErrorStatus::NONE, statusSmall);
     EXPECT_EQ(0u, outputShapesSmall.size());
     EXPECT_TRUE(badTiming(timingSmall));
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 7da2da9..4c0100e 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -30,6 +30,8 @@
 using HidlToken =
         hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
 
+using PrepareModelMutation = std::function<void(Model*, ExecutionPreference*, Priority*)>;
+
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
 static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
@@ -44,13 +46,14 @@
 }
 
 static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
-                                 const Model& model, ExecutionPreference preference) {
+                                 const Model& model, ExecutionPreference preference,
+                                 Priority priority) {
     SCOPED_TRACE(message + " [prepareModel_1_3]");
 
     sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
-    Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3(
-            model, preference, kDefaultPriority, {}, hidl_vec<hidl_handle>(),
-            hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
+    Return<ErrorStatus> prepareLaunchStatus =
+            device->prepareModel_1_3(model, preference, priority, {}, hidl_vec<hidl_handle>(),
+                                     hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
 
@@ -67,18 +70,26 @@
            preference == ExecutionPreference::SUSTAINED_SPEED;
 }
 
+static bool validExecutionPriority(Priority priority) {
+    return priority == Priority::LOW || priority == Priority::MEDIUM || priority == Priority::HIGH;
+}
+
 // Primary validation function. This function will take a valid model, apply a
-// mutation to it to invalidate the model, then pass it to interface calls that
-// use the model. Note that the model here is passed by value, and any mutation
-// to the model does not leave this function.
-static void validate(const sp<IDevice>& device, const std::string& message, Model model,
-                     const std::function<void(Model*)>& mutation,
-                     ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
-    mutation(&model);
-    if (validExecutionPreference(preference)) {
+// mutation to invalidate the model, the execution preference, or the priority,
+// then pass these to supportedOperations and/or prepareModel if that method is
+// called with an invalid argument.
+static void validate(const sp<IDevice>& device, const std::string& message,
+                     const Model& originalModel, const PrepareModelMutation& mutate) {
+    Model model = originalModel;
+    ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER;
+    Priority priority = kDefaultPriority;
+    mutate(&model, &preference, &priority);
+
+    if (validExecutionPreference(preference) && validExecutionPriority(priority)) {
         validateGetSupportedOperations(device, message, model);
     }
-    validatePrepareModel(device, message, model, preference);
+
+    validatePrepareModel(device, message, model, preference, priority);
 }
 
 static uint32_t addOperand(Model* model) {
@@ -116,9 +127,11 @@
             const std::string message = "mutateOperandTypeTest: operand " +
                                         std::to_string(operand) + " set to value " +
                                         std::to_string(invalidOperandType);
-            validate(device, message, model, [operand, invalidOperandType](Model* model) {
-                model->main.operands[operand].type = static_cast<OperandType>(invalidOperandType);
-            });
+            validate(device, message, model,
+                     [operand, invalidOperandType](Model* model, ExecutionPreference*, Priority*) {
+                         model->main.operands[operand].type =
+                                 static_cast<OperandType>(invalidOperandType);
+                     });
         }
     }
 }
@@ -156,9 +169,11 @@
         }
         const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
                                     " has rank of " + std::to_string(invalidRank);
-        validate(device, message, model, [operand, invalidRank](Model* model) {
-            model->main.operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
-        });
+        validate(device, message, model,
+                 [operand, invalidRank](Model* model, ExecutionPreference*, Priority*) {
+                     model->main.operands[operand].dimensions =
+                             std::vector<uint32_t>(invalidRank, 0);
+                 });
     }
 }
 
@@ -194,9 +209,10 @@
         const float invalidScale = getInvalidScale(model.main.operands[operand].type);
         const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
                                     " has scale of " + std::to_string(invalidScale);
-        validate(device, message, model, [operand, invalidScale](Model* model) {
-            model->main.operands[operand].scale = invalidScale;
-        });
+        validate(device, message, model,
+                 [operand, invalidScale](Model* model, ExecutionPreference*, Priority*) {
+                     model->main.operands[operand].scale = invalidScale;
+                 });
     }
 }
 
@@ -237,9 +253,10 @@
             const std::string message = "mutateOperandZeroPointTest: operand " +
                                         std::to_string(operand) + " has zero point of " +
                                         std::to_string(invalidZeroPoint);
-            validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
-                model->main.operands[operand].zeroPoint = invalidZeroPoint;
-            });
+            validate(device, message, model,
+                     [operand, invalidZeroPoint](Model* model, ExecutionPreference*, Priority*) {
+                         model->main.operands[operand].zeroPoint = invalidZeroPoint;
+                     });
         }
     }
 }
@@ -425,9 +442,10 @@
             const std::string message = "mutateOperationOperandTypeTest: operand " +
                                         std::to_string(operand) + " set to type " +
                                         toString(invalidOperandType);
-            validate(device, message, model, [operand, invalidOperandType](Model* model) {
-                mutateOperand(&model->main.operands[operand], invalidOperandType);
-            });
+            validate(device, message, model,
+                     [operand, invalidOperandType](Model* model, ExecutionPreference*, Priority*) {
+                         mutateOperand(&model->main.operands[operand], invalidOperandType);
+                     });
         }
     }
 }
@@ -446,10 +464,12 @@
             const std::string message = "mutateOperationTypeTest: operation " +
                                         std::to_string(operation) + " set to value " +
                                         std::to_string(invalidOperationType);
-            validate(device, message, model, [operation, invalidOperationType](Model* model) {
-                model->main.operations[operation].type =
-                        static_cast<OperationType>(invalidOperationType);
-            });
+            validate(device, message, model,
+                     [operation, invalidOperationType](Model* model, ExecutionPreference*,
+                                                       Priority*) {
+                         model->main.operations[operation].type =
+                                 static_cast<OperationType>(invalidOperationType);
+                     });
         }
     }
 }
@@ -463,9 +483,11 @@
             const std::string message = "mutateOperationInputOperandIndexTest: operation " +
                                         std::to_string(operation) + " input " +
                                         std::to_string(input);
-            validate(device, message, model, [operation, input, invalidOperand](Model* model) {
-                model->main.operations[operation].inputs[input] = invalidOperand;
-            });
+            validate(device, message, model,
+                     [operation, input, invalidOperand](Model* model, ExecutionPreference*,
+                                                        Priority*) {
+                         model->main.operations[operation].inputs[input] = invalidOperand;
+                     });
         }
     }
 }
@@ -480,9 +502,11 @@
             const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
                                         std::to_string(operation) + " output " +
                                         std::to_string(output);
-            validate(device, message, model, [operation, output, invalidOperand](Model* model) {
-                model->main.operations[operation].outputs[output] = invalidOperand;
-            });
+            validate(device, message, model,
+                     [operation, output, invalidOperand](Model* model, ExecutionPreference*,
+                                                         Priority*) {
+                         model->main.operations[operation].outputs[output] = invalidOperand;
+                     });
         }
     }
 }
@@ -548,8 +572,9 @@
             continue;
         }
         const std::string message = "removeOperandTest: operand " + std::to_string(operand);
-        validate(device, message, model,
-                 [operand](Model* model) { removeOperand(model, operand); });
+        validate(device, message, model, [operand](Model* model, ExecutionPreference*, Priority*) {
+            removeOperand(model, operand);
+        });
     }
 }
 
@@ -566,7 +591,9 @@
     for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
         const std::string message = "removeOperationTest: operation " + std::to_string(operation);
         validate(device, message, model,
-                 [operation](Model* model) { removeOperation(model, operation); });
+                 [operation](Model* model, ExecutionPreference*, Priority*) {
+                     removeOperation(model, operation);
+                 });
     }
 }
 
@@ -654,11 +681,12 @@
             const std::string message = "removeOperationInputTest: operation " +
                                         std::to_string(operation) + ", input " +
                                         std::to_string(input);
-            validate(device, message, model, [operation, input](Model* model) {
-                uint32_t operand = model->main.operations[operation].inputs[input];
-                model->main.operands[operand].numberOfConsumers--;
-                hidl_vec_removeAt(&model->main.operations[operation].inputs, input);
-            });
+            validate(device, message, model,
+                     [operation, input](Model* model, ExecutionPreference*, Priority*) {
+                         uint32_t operand = model->main.operations[operation].inputs[input];
+                         model->main.operands[operand].numberOfConsumers--;
+                         hidl_vec_removeAt(&model->main.operations[operation].inputs, input);
+                     });
         }
     }
 }
@@ -672,9 +700,10 @@
             const std::string message = "removeOperationOutputTest: operation " +
                                         std::to_string(operation) + ", output " +
                                         std::to_string(output);
-            validate(device, message, model, [operation, output](Model* model) {
-                hidl_vec_removeAt(&model->main.operations[operation].outputs, output);
-            });
+            validate(device, message, model,
+                     [operation, output](Model* model, ExecutionPreference*, Priority*) {
+                         hidl_vec_removeAt(&model->main.operations[operation].outputs, output);
+                     });
         }
     }
 }
@@ -707,11 +736,12 @@
             continue;
         }
         const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
-        validate(device, message, model, [operation](Model* model) {
-            uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT);
-            hidl_vec_push_back(&model->main.operations[operation].inputs, index);
-            hidl_vec_push_back(&model->main.inputIndexes, index);
-        });
+        validate(device, message, model,
+                 [operation](Model* model, ExecutionPreference*, Priority*) {
+                     uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT);
+                     hidl_vec_push_back(&model->main.operations[operation].inputs, index);
+                     hidl_vec_push_back(&model->main.inputIndexes, index);
+                 });
     }
 }
 
@@ -721,11 +751,12 @@
     for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
         const std::string message =
                 "addOperationOutputTest: operation " + std::to_string(operation);
-        validate(device, message, model, [operation](Model* model) {
-            uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT);
-            hidl_vec_push_back(&model->main.operations[operation].outputs, index);
-            hidl_vec_push_back(&model->main.outputIndexes, index);
-        });
+        validate(device, message, model,
+                 [operation](Model* model, ExecutionPreference*, Priority*) {
+                     uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT);
+                     hidl_vec_push_back(&model->main.operations[operation].outputs, index);
+                     hidl_vec_push_back(&model->main.outputIndexes, index);
+                 });
     }
 }
 
@@ -737,12 +768,31 @@
 };
 
 static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
-    for (int32_t preference : invalidExecutionPreferences) {
+    for (int32_t invalidPreference : invalidExecutionPreferences) {
         const std::string message =
-                "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
-        validate(
-                device, message, model, [](Model*) {},
-                static_cast<ExecutionPreference>(preference));
+                "mutateExecutionPreferenceTest: preference " + std::to_string(invalidPreference);
+        validate(device, message, model,
+                 [invalidPreference](Model*, ExecutionPreference* preference, Priority*) {
+                     *preference = static_cast<ExecutionPreference>(invalidPreference);
+                 });
+    }
+}
+
+///////////////////////// VALIDATE PRIORITY /////////////////////////
+
+static const int32_t invalidPriorities[] = {
+        static_cast<int32_t>(Priority::LOW) - 1,   // lower bound
+        static_cast<int32_t>(Priority::HIGH) + 1,  // upper bound
+};
+
+static void mutateExecutionPriorityTest(const sp<IDevice>& device, const Model& model) {
+    for (int32_t invalidPriority : invalidPriorities) {
+        const std::string message =
+                "mutatePriorityTest: priority " + std::to_string(invalidPriority);
+        validate(device, message, model,
+                 [invalidPriority](Model*, ExecutionPreference*, Priority* priority) {
+                     *priority = static_cast<Priority>(invalidPriority);
+                 });
     }
 }
 
@@ -764,6 +814,7 @@
     addOperationInputTest(device, model);
     addOperationOutputTest(device, model);
     mutateExecutionPreferenceTest(device, model);
+    mutateExecutionPriorityTest(device, model);
 }
 
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 5e806e5..1ae8b3f 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -34,6 +34,8 @@
 using V1_2::OutputShape;
 using V1_2::Timing;
 
+using ExecutionMutation = std::function<void(Request*)>;
+
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
 static bool badTiming(Timing timing) {
@@ -42,11 +44,11 @@
 
 // Primary validation function. This function will take a valid request, apply a
 // mutation to it to invalidate the request, then pass it to interface calls
-// that use the request. Note that the request here is passed by value, and any
-// mutation to the request does not leave this function.
+// that use the request.
 static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
-                     Request request, const std::function<void(Request*)>& mutation) {
-    mutation(&request);
+                     const Request& originalRequest, const ExecutionMutation& mutate) {
+    Request request = originalRequest;
+    mutate(&request);
 
     // We'd like to test both with timing requested and without timing
     // requested. Rather than running each test both ways, we'll decide whether
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
index 5b07034..df1e453 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -177,7 +177,8 @@
 
 TEST_P(ValidationTest, Test) {
     const Model model = createModel(kTestModel);
-    const Request request = nn::convertToV1_3(createRequest(kTestModel));
+    ExecutionContext context;
+    const Request request = nn::convertToV1_3(context.createRequest(kTestModel));
     if (kTestModel.expectFailure) {
         validateFailure(kDevice, model, request);
     } else {
@@ -185,11 +186,31 @@
     }
 }
 
-INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) {
+    // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs"
+    // generated tests.
+    return testName.find("inputs_as_internal") == std::string::npos &&
+           testName.find("all_tensors_as_inputs") == std::string::npos;
+});
 
 sp<IPreparedModel> getPreparedModel_1_3(const sp<PreparedModelCallback>& callback) {
     sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
     return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
 }
 
+std::string toString(Executor executor) {
+    switch (executor) {
+        case Executor::ASYNC:
+            return "ASYNC";
+        case Executor::SYNC:
+            return "SYNC";
+        case Executor::BURST:
+            return "BURST";
+        case Executor::FENCED:
+            return "FENCED";
+        default:
+            CHECK(false);
+    }
+}
+
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
index 4e51052..de082c3 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
@@ -52,6 +52,10 @@
 // Utility function to get PreparedModel from callback and downcast to V1_2.
 sp<IPreparedModel> getPreparedModel_1_3(const sp<implementation::PreparedModelCallback>& callback);
 
+enum class Executor { ASYNC, SYNC, BURST, FENCED };
+
+std::string toString(Executor executor);
+
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
 
 #endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
index d04cb36..9b6cc96 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
@@ -578,7 +578,7 @@
 TEST_P(RadioHidlTest, nvResetConfig) {
     serial = GetRandomSerialNumber();
 
-    radio->nvResetConfig(serial, ResetNvType::ERASE);
+    radio->nvResetConfig(serial, ResetNvType::FACTORY_RESET);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
     EXPECT_EQ(serial, radioRsp->rspInfo.serial);
diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal
index c40b473..58e988f 100644
--- a/radio/1.5/IRadioIndication.hal
+++ b/radio/1.5/IRadioIndication.hal
@@ -95,4 +95,21 @@
      * CellInfo.
      */
     oneway networkScanResult_1_5(RadioIndicationType type, NetworkScanResult result);
+
+    /**
+     * Indicates data call contexts have changed.
+     *
+     * This indication is updated from IRadioIndication@1.4 to report the @1.5 version of
+     * SetupDataCallResult.
+     *
+     * @param type Type of radio indication
+     * @param dcList Array of SetupDataCallResult identical to that returned by
+     *        IRadio.getDataCallList(). It is the complete list of current data contexts including
+     *        new contexts that have been activated. A data call is only removed from this list
+     *        when below conditions matched.
+     *        1. The framework sends a IRadio.deactivateDataCall().
+     *        2. The radio is powered off/on.
+     *        3. Unsolicited disconnect from either modem or network side.
+     */
+    oneway dataCallListChanged_1_5(RadioIndicationType type, vec<SetupDataCallResult> dcList);
 };
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index e87cad2..1380da3 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -20,6 +20,7 @@
 import @1.0::SendSmsResult;
 import @1.4::IRadioResponse;
 import @1.5::BarringInfo;
+import @1.5::CardStatus;
 import @1.5::CellIdentity;
 import @1.5::CellInfo;
 import @1.5::PersoSubstate;
@@ -120,6 +121,20 @@
 
     /**
      * @param info Response info struct containing response type, serial no. and error
+     * @param dcResponse List of SetupDataCallResult as defined in types.hal
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:NO_RESOURCES
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:SIM_ABSENT
+     */
+    oneway getDataCallListResponse_1_5(RadioResponseInfo info, vec<SetupDataCallResult> dcResponse);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
      *   RadioError:NONE
@@ -303,5 +318,18 @@
      *   RadioError:REQUEST_NOT_SUPPORTED
      */
     oneway supplySimDepersonalizationResponse(RadioResponseInfo info,
-        PersoSubstate persoType, int32_t remainingRetries);
+            PersoSubstate persoType, int32_t remainingRetries);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param cardStatus ICC card status as defined by CardStatus in types.hal
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:NO_RESOURCES
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     */
+    oneway getIccCardStatusResponse_1_5(RadioResponseInfo info, CardStatus cardStatus);
 };
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 4d3c2d5..248f56e 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -17,6 +17,7 @@
 package android.hardware.radio@1.5;
 
 import @1.0::ApnAuthType;
+import @1.0::AppStatus;
 import @1.0::DataProfileId;
 import @1.0::DataProfileInfoType;
 import @1.0::GsmSignalStrength;
@@ -43,6 +44,7 @@
 import @1.2::WcdmaSignalStrength;
 import @1.4::AccessNetwork;
 import @1.4::ApnTypes;
+import @1.4::CardStatus;
 import @1.4::CellIdentityNr;
 import @1.4::DataCallFailCause;
 import @1.4::DataConnActiveStatus;
@@ -1021,16 +1023,54 @@
  * 3GPP2 C.S0068-0.
  */
 enum PersoSubstate : @1.0::PersoSubstate {
+    /**
+     * The device is personalized using the content of the Service Provider Name (SPN) in the SIM
+     * card.
+     */
     SIM_SPN,
     SIM_SPN_PUK,
-    /** Equivalent Home PLMN */
+    /**
+     * Service Provider and Equivalent Home PLMN
+     * The device is personalized using both the content of the GID1 (equivalent to service provider
+     * personalization) and the content of the Equivalent Home PLMN (EHPLMN) in the SIM card.
+     * If the GID1 in the SIM is absent, then just the content of the Equivalent Home PLMN
+     * is matched.
+     */
     SIM_SP_EHPLMN,
     SIM_SP_EHPLMN_PUK,
+    /**
+     * Device is personalized using the first digits of the ICCID of the SIM card.
+     */
     SIM_ICCID,
     SIM_ICCID_PUK,
+    /**
+     * Device is personalized using the content of the IMPI in the ISIM.
+     */
     SIM_IMPI,
     SIM_IMPI_PUK,
-    /** Network subset service provider */
+    /**
+     * Network Subset and Service Provider
+     * Device is personalized using both the content of GID1 (equivalent to service provider
+     * personalization) and the first digits of the IMSI (equivalent to network subset
+     * personalization).
+     */
     SIM_NS_SP,
     SIM_NS_SP_PUK,
 };
+
+/** Extended from @1.0::AppStatus to update PersoSubstate to 1.5 version. */
+struct AppStatus {
+    @1.0::AppStatus base;
+
+    /** Applicable only if appState == SUBSCRIPTION_PERSO */
+    PersoSubstate persoSubstate;
+};
+
+
+/** Extended from @1.4::CardStatus to use 1.5 version of AppStatus. */
+struct CardStatus {
+    @1.4::CardStatus base;
+
+    /** size <= RadioConst::CARD_MAX_APPS */
+    vec<AppStatus> applications;
+};
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 003f58e..32c02cb 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -408,7 +408,7 @@
  */
 TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) {
     // This test case only test SIM ABSENT case.
-    if (cardStatus.base.base.cardState != CardState::ABSENT) return;
+    if (cardStatus.base.base.base.cardState != CardState::ABSENT) return;
 
     // Disable Uicc applications.
     serial = GetRandomSerialNumber();
@@ -435,7 +435,7 @@
  */
 TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) {
     // This test case only test SIM ABSENT case.
-    if (cardStatus.base.base.cardState != CardState::PRESENT) return;
+    if (cardStatus.base.base.base.cardState != CardState::PRESENT) return;
 
     // Disable Uicc applications.
     serial = GetRandomSerialNumber();
@@ -489,9 +489,9 @@
 
     // If SIM is absent, RadioError::SIM_ABSENT should be thrown. Otherwise there shouldn't be any
     // error.
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error);
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
     }
 }
@@ -563,9 +563,9 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
     ALOGI("startNetworkScan, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str());
 
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do
         // not support the required manual GSM search functionality. This is
         // tracked in b/112206766. Modems have "GSM" rat scan need to
@@ -592,10 +592,10 @@
     ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n",
           toString(radioRsp_v1_5->rspInfo.error).c_str());
 
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_5->rspInfo.error,
                 {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -631,10 +631,10 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
     ALOGI("startNetworkScan_InvalidInterval1, rspInfo.error = %s\n",
           toString(radioRsp_v1_5->rspInfo.error).c_str());
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_5->rspInfo.error,
                 {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -670,10 +670,10 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
     ALOGI("startNetworkScan_InvalidInterval2, rspInfo.error = %s\n",
           toString(radioRsp_v1_5->rspInfo.error).c_str());
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_5->rspInfo.error,
                 {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -709,10 +709,10 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
     ALOGI("startNetworkScan_InvalidMaxSearchTime1, rspInfo.error = %s\n",
           toString(radioRsp_v1_5->rspInfo.error).c_str());
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_5->rspInfo.error,
                 {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -748,10 +748,10 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
     ALOGI("startNetworkScan_InvalidMaxSearchTime2, rspInfo.error = %s\n",
           toString(radioRsp_v1_5->rspInfo.error).c_str());
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_5->rspInfo.error,
                 {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -787,10 +787,10 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
     ALOGI("startNetworkScan_InvalidPeriodicity1, rspInfo.error = %s\n",
           toString(radioRsp_v1_5->rspInfo.error).c_str());
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_5->rspInfo.error,
                 {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -826,10 +826,10 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
     ALOGI("startNetworkScan_InvalidPeriodicity2, rspInfo.error = %s\n",
           toString(radioRsp_v1_5->rspInfo.error).c_str());
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_5->rspInfo.error,
                 {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -865,10 +865,10 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
     ALOGI("startNetworkScan_GoodRequest1, rspInfo.error = %s\n",
           toString(radioRsp_v1_5->rspInfo.error).c_str());
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::SIM_ABSENT}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
                                       RadioError::REQUEST_NOT_SUPPORTED}));
@@ -905,10 +905,10 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
     ALOGI("startNetworkScan_GoodRequest2, rspInfo.error = %s\n",
           toString(radioRsp_v1_5->rspInfo.error).c_str());
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::SIM_ABSENT}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
                                       RadioError::REQUEST_NOT_SUPPORTED}));
@@ -961,11 +961,11 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
 
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE,
                                       RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
                                       RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
@@ -1006,10 +1006,10 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
 
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
     }
@@ -1053,10 +1053,10 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
 
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE}));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
     }
@@ -1106,12 +1106,12 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
 
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME,
                                       RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE},
                                      CHECK_GENERAL_ERROR));
-    } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
                                       RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE},
@@ -1155,7 +1155,7 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
 
-    if (cardStatus.base.base.cardState == CardState::ABSENT) {
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_5->rspInfo.error,
                 {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
index ca6bbeb..7313de4 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
@@ -41,7 +41,7 @@
     ASSERT_NE(nullptr, radioConfig.get());
 
     /* Enforce Vts Testing with Sim Status Present only. */
-    EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.cardState);
+    EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState);
 }
 
 /*
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index 6488609..6a369cc 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -55,7 +55,7 @@
 #define RADIO_SERVICE_NAME "slot1"
 
 class RadioHidlTest_v1_5;
-extern ::android::hardware::radio::V1_4::CardStatus cardStatus;
+extern ::android::hardware::radio::V1_5::CardStatus cardStatus;
 
 /* Callback class for radio response v1_5 */
 class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioResponse {
@@ -556,6 +556,10 @@
             const RadioResponseInfo& info,
             const android::hardware::radio::V1_5::SetupDataCallResult& dcResponse);
 
+    Return<void> getDataCallListResponse_1_5(
+            const RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& dcResponse);
+
     Return<void> setInitialAttachApnResponse_1_5(const RadioResponseInfo& info);
 
     Return<void> setDataProfileResponse_1_5(const RadioResponseInfo& info);
@@ -591,6 +595,10 @@
     Return<void> supplySimDepersonalizationResponse(
             const RadioResponseInfo& info,
             ::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries);
+
+    Return<void> getIccCardStatusResponse_1_5(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_5::CardStatus& card_status);
 };
 
 /* Callback class for radio indication */
@@ -614,6 +622,10 @@
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::CellInfo>&
                     records);
 
+    Return<void> dataCallListChanged_1_5(
+            RadioIndicationType type,
+            const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& dcList);
+
     /* 1.4 Api */
     Return<void> currentEmergencyNumberList(
             RadioIndicationType type,
diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp
index d448a22..1e5ce16 100644
--- a/radio/1.5/vts/functional/radio_indication.cpp
+++ b/radio/1.5/vts/functional/radio_indication.cpp
@@ -18,6 +18,46 @@
 
 RadioIndication_v1_5::RadioIndication_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
 
+/* 1.5 Apis */
+Return<void> RadioIndication_v1_5::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/,
+                                                                     bool /*enabled*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::registrationFailed(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
+        const hidl_string& /*chosenPlmn*/,
+        ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> /*domain*/,
+        int32_t /*causeCode*/, int32_t /*additionalCauseCode*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::barringInfoChanged(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
+        const hidl_vec<::android::hardware::radio::V1_5::BarringInfo>& /*barringInfos*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkScanResult_1_5(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_5::NetworkScanResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_5(
+        RadioIndicationType /*type*/,
+        const hidl_vec<::android::hardware::radio::V1_5::CellInfo>& /*records*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::dataCallListChanged_1_5(
+        RadioIndicationType /*type*/,
+        const hidl_vec<android::hardware::radio::V1_5::SetupDataCallResult>& /*dcList*/) {
+    return Void();
+}
+
 /* 1.4 Apis */
 Return<void> RadioIndication_v1_5::currentPhysicalChannelConfigs_1_4(
         RadioIndicationType /*type*/,
@@ -328,38 +368,3 @@
                                               const ::android::hardware::hidl_string& /*reason*/) {
     return Void();
 }
-
-Return<void> RadioIndication_v1_5::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/,
-                                                                     bool /*enabled*/) {
-    return Void();
-}
-
-Return<void> RadioIndication_v1_5::registrationFailed(
-        RadioIndicationType /*type*/,
-        const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
-        const ::android::hardware::hidl_string& /*chosenPlmn*/,
-        ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> /*domain*/,
-        int32_t /*causeCode*/, int32_t /*additionalCauseCode*/) {
-    return Void();
-}
-
-Return<void> RadioIndication_v1_5::barringInfoChanged(
-        RadioIndicationType /*type*/,
-        const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
-        const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>&
-        /*barringInfos*/) {
-    return Void();
-}
-
-Return<void> RadioIndication_v1_5::networkScanResult_1_5(
-        RadioIndicationType /*type*/,
-        const ::android::hardware::radio::V1_5::NetworkScanResult& /*result*/) {
-    return Void();
-}
-
-Return<void> RadioIndication_v1_5::cellInfoList_1_5(
-        RadioIndicationType /*type*/,
-        const ::android::hardware::hidl_vec<
-                ::android::hardware::radio::V1_5::CellInfo>& /*records*/) {
-    return Void();
-}
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index e4f9ce8..8cbb2d0 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -16,7 +16,7 @@
 
 #include <radio_hidl_hal_utils_v1_5.h>
 
-::android::hardware::radio::V1_4::CardStatus cardStatus;
+::android::hardware::radio::V1_5::CardStatus cardStatus;
 
 RadioResponse_v1_5::RadioResponse_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
 
@@ -829,9 +829,8 @@
 
 Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_4(
         const RadioResponseInfo& info,
-        const ::android::hardware::radio::V1_4::CardStatus& card_status) {
+        const ::android::hardware::radio::V1_4::CardStatus& /*card_status*/) {
     rspInfo = info;
-    cardStatus = card_status;
     parent_v1_5.notify(info.serial);
     return Void();
 }
@@ -944,6 +943,14 @@
     return Void();
 }
 
+Return<void> RadioResponse_v1_5::getDataCallListResponse_1_5(
+        const RadioResponseInfo& info,
+        const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& /* dcResponse */) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
 Return<void> RadioResponse_v1_5::setInitialAttachApnResponse_1_5(const RadioResponseInfo& info) {
     rspInfo = info;
     parent_v1_5.notify(info.serial);
@@ -1021,3 +1028,12 @@
         int32_t /*remainingRetries*/) {
     return Void();
 }
+
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_5(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_5::CardStatus& card_status) {
+    rspInfo = info;
+    cardStatus = card_status;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp
index d2422b9..adb2010 100644
--- a/rebootescrow/aidl/default/HadamardUtils.cpp
+++ b/rebootescrow/aidl/default/HadamardUtils.cpp
@@ -16,8 +16,6 @@
 
 #include <HadamardUtils.h>
 
-#include <limits>
-
 #include <android-base/logging.h>
 
 namespace aidl {
@@ -92,6 +90,31 @@
     return result;
 }
 
+// Constant-time conditional copy, to fix b/146520538
+// ctl must be 0 or 1; we do the copy if it's 1.
+static void CondCopy(uint32_t ctl, void* dest, const void* src, size_t len) {
+    const auto cdest = reinterpret_cast<uint8_t*>(dest);
+    const auto csrc = reinterpret_cast<const uint8_t*>(src);
+    for (size_t i = 0; i < len; i++) {
+        const uint32_t d = cdest[i];
+        const uint32_t s = csrc[i];
+        cdest[i] = d ^ (-ctl & (s ^ d));
+    }
+}
+
+struct CodewordWinner {
+    uint16_t codeword;
+    int32_t score;
+};
+
+// Replace dest with src if it has a higher score
+static void CopyWinner(CodewordWinner* dest, const CodewordWinner& src) {
+    // Scores are between - 2^15 and 2^15, so taking the difference won't
+    // overflow; we use the sign bit of the difference here.
+    CondCopy(static_cast<uint32_t>(dest->score - src.score) >> 31, dest, &src,
+             sizeof(CodewordWinner));
+}
+
 // Decode a single codeword. Because of the way codewords are striped together
 // this takes the entire input, plus an offset telling it which word to decode.
 static uint16_t DecodeWord(size_t word, const std::vector<uint8_t>& encoded) {
@@ -118,20 +141,15 @@
             }
         }
     }
-    auto hiscore = std::numeric_limits<int32_t>::min();
-    uint16_t winner;
-    // TODO(b/146520538): this needs to be constant time
+    // -ENCODE_LENGTH is least possible score, so start one less than that
+    auto best = CodewordWinner{0, -static_cast<int32_t>(ENCODE_LENGTH + 1)};
+    // For every possible codeword value, look at its score, and replace best if it's higher,
+    // in constant time.
     for (size_t i = 0; i < ENCODE_LENGTH; i++) {
-        if (scores[i] > hiscore) {
-            winner = i;
-            hiscore = scores[i];
-
-        } else if (-scores[i] > hiscore) {
-            winner = i | (1 << CODE_K);
-            hiscore = -scores[i];
-        }
+        CopyWinner(&best, CodewordWinner{static_cast<uint16_t>(i), scores[i]});
+        CopyWinner(&best, CodewordWinner{static_cast<uint16_t>(i | (1 << CODE_K)), -scores[i]});
     }
-    return winner;
+    return best.codeword;
 }
 
 std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& shuffled) {
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
index 84556b5..406a899 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
@@ -23,6 +23,9 @@
     /* Period of silence preceding primitive. */
     int delayMs;
     CompositePrimitive primitive;
-    /* 0.0 (exclusive) - 1.0 (inclusive) */
+    /*
+     * 0.0 (inclusive) - 1.0 (inclusive),
+     * where 0.0 is minimum "feelable" amplitude.
+     */
     float scale;
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
index 0fdfa5d..8e82db0 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -21,37 +21,53 @@
 enum CompositePrimitive {
     /**
      * No haptic effect. Used to generate extended delays between primitives.
+     *
+     * Support is required.
      */
     NOOP,
     /**
      * This effect should produce a sharp, crisp click sensation.
+     *
+     * Support is required.
      */
     CLICK,
     /**
      * A haptic effect that simulates downwards movement with gravity. Often
      * followed by extra energy of hitting and reverberation to augment
      * physicality.
+     *
+     * Support is optional.
      */
     THUD,
     /**
      * A haptic effect that simulates spinning momentum.
+     *
+     * Support is optional.
      */
     SPIN,
     /**
      * A haptic effect that simulates quick upward movement against gravity.
+     *
+     * Support is required.
      */
     QUICK_RISE,
     /**
      * A haptic effect that simulates slow upward movement against gravity.
+     *
+     * Support is required.
      */
     SLOW_RISE,
     /**
      * A haptic effect that simulates quick downwards movement with gravity.
+     *
+     * Support is required.
      */
     QUICK_FALL,
     /**
      * This very short effect should produce a light crisp sensation intended
      * to be used repetitively for dynamic feedback.
+     *
+     * Support is required.
      */
     LIGHT_TICK,
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index 6489c1d..0b21248 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -161,8 +161,8 @@
      * List of supported effect primitive.
      *
      * Return the effect primitives which are supported by the compose API.
-     * Implementations are expected to support all primitives of the interface
-     * version that they implement.
+     * Implementations are expected to support all required primitives of the
+     * interface version that they implement (see primitive definitions).
      */
     CompositePrimitive[] getSupportedPrimitives();
 
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 9236b95..b359100 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -146,7 +146,7 @@
         if (e.delayMs > kComposeDelayMaxMs) {
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
-        if (e.scale <= 0.0f || e.scale > 1.0f) {
+        if (e.scale < 0.0f || e.scale > 1.0f) {
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
         if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 411fe7a..8340517 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -21,6 +21,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 
+#include <cmath>
 #include <future>
 
 using android::ProcessState;
@@ -53,6 +54,11 @@
         android::enum_range<CompositePrimitive>().begin(),
         android::enum_range<CompositePrimitive>().end()};
 
+const std::vector<CompositePrimitive> kOptionalPrimitives = {
+        CompositePrimitive::THUD,
+        CompositePrimitive::SPIN,
+};
+
 const std::vector<CompositePrimitive> kInvalidPrimitives = {
         static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
         static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
@@ -128,7 +134,6 @@
             } else {
                 EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
                         << toString(effect) << " " << toString(strength);
-                EXPECT_EQ(lengthMs, 0);
             }
         }
     }
@@ -157,7 +162,6 @@
                 EXPECT_GT(lengthMs, 0);
             } else {
                 EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
-                EXPECT_EQ(lengthMs, 0);
             }
 
             if (!status.isOk()) continue;
@@ -177,7 +181,6 @@
             int lengthMs;
             Status status = vibrator->perform(effect, strength, callback, &lengthMs);
             EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
-            EXPECT_EQ(lengthMs, 0);
         }
     }
 }
@@ -267,38 +270,56 @@
 
         EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());
 
-        std::sort(supported.begin(), supported.end());
+        for (auto primitive : kCompositePrimitives) {
+            bool isPrimitiveSupported =
+                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
+            bool isPrimitiveOptional =
+                    std::find(kOptionalPrimitives.begin(), kOptionalPrimitives.end(), primitive) !=
+                    kOptionalPrimitives.end();
 
-        EXPECT_EQ(kCompositePrimitives, supported);
+            EXPECT_TRUE(isPrimitiveSupported || isPrimitiveOptional) << toString(primitive);
+        }
     }
 }
 
 TEST_P(VibratorAidl, GetPrimitiveDuration) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
-        int32_t duration;
+        std::vector<CompositePrimitive> supported;
+        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
 
         for (auto primitive : kCompositePrimitives) {
-            EXPECT_EQ(Status::EX_NONE,
-                      vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode());
+            bool isPrimitiveSupported =
+                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
+            int32_t duration;
+
+            Status status = vibrator->getPrimitiveDuration(primitive, &duration);
+
+            if (isPrimitiveSupported) {
+                EXPECT_EQ(Status::EX_NONE, status.exceptionCode());
+            } else {
+                EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
+            }
         }
     }
 }
 
 TEST_P(VibratorAidl, ComposeValidPrimitives) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        std::vector<CompositePrimitive> supported;
         int32_t maxDelay, maxSize;
 
+        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
         EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
         EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
 
         std::vector<CompositeEffect> composite;
 
-        for (auto primitive : kCompositePrimitives) {
+        for (auto primitive : supported) {
             CompositeEffect effect;
 
             effect.delayMs = std::rand() % (maxDelay + 1);
             effect.primitive = primitive;
-            effect.scale = static_cast<float>(std::rand()) / RAND_MAX ?: 1.0f;
+            effect.scale = static_cast<float>(std::rand()) / RAND_MAX;
             composite.emplace_back(effect);
 
             if (composite.size() == maxSize) {
@@ -317,7 +338,21 @@
 
 TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
-        for (auto primitive : kInvalidPrimitives) {
+        auto unsupported = kInvalidPrimitives;
+        std::vector<CompositePrimitive> supported;
+
+        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
+
+        for (auto primitive : kCompositePrimitives) {
+            bool isPrimitiveSupported =
+                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
+
+            if (!isPrimitiveSupported) {
+                unsupported.push_back(primitive);
+            }
+        }
+
+        for (auto primitive : unsupported) {
             std::vector<CompositeEffect> composite(1);
 
             for (auto& effect : composite) {
@@ -332,7 +367,33 @@
     }
 }
 
-TEST_P(VibratorAidl, CompseDelayBoundary) {
+TEST_P(VibratorAidl, ComposeScaleBoundary) {
+    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        std::vector<CompositeEffect> composite(1);
+        CompositeEffect& effect = composite[0];
+
+        effect.delayMs = 0;
+        effect.primitive = CompositePrimitive::CLICK;
+
+        effect.scale = std::nextafter(0.0f, -1.0f);
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->compose(composite, nullptr).exceptionCode());
+
+        effect.scale = 0.0f;
+        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+
+        effect.scale = 1.0f;
+        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+
+        effect.scale = std::nextafter(1.0f, 2.0f);
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->compose(composite, nullptr).exceptionCode());
+
+        vibrator->off();
+    }
+}
+
+TEST_P(VibratorAidl, ComposeDelayBoundary) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
         int32_t maxDelay;
 
@@ -357,7 +418,7 @@
     }
 }
 
-TEST_P(VibratorAidl, CompseSizeBoundary) {
+TEST_P(VibratorAidl, ComposeSizeBoundary) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
         int32_t maxSize;