Merge changes from topic "sk_hal" into main

* changes:
  VTS test for ISecretkeeper
  Secretkeeper implementation: in-HAL/nonsecure impl
  Introduce Secretkeeper HAL interface
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl
index 9f97de0..98ecee0 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl
@@ -35,12 +35,13 @@
 @VintfStability
 union Spatializer {
   android.hardware.audio.effect.VendorExtension vendor;
-  android.media.audio.common.Spatialization.Level spatializationLevel;
-  android.media.audio.common.HeadTracking.Mode headTrackingMode;
   android.media.audio.common.AudioChannelLayout[] supportedChannelLayout;
+  android.media.audio.common.Spatialization.Level spatializationLevel;
   android.media.audio.common.Spatialization.Mode spatializationMode;
-  float[6] headToStage;
-  const int HEAD_TO_STAGE_VEC_SIZE = 6;
+  int headTrackingSensorId;
+  android.media.audio.common.HeadTracking.Mode headTrackingMode;
+  android.media.audio.common.HeadTracking.ConnectionMode headTrackingConnectionMode;
+  android.media.audio.common.HeadTracking.SensorData headTrackingSensorData;
   @VintfStability
   union Id {
     android.hardware.audio.effect.VendorExtension vendorExtensionTag;
diff --git a/audio/aidl/android/hardware/audio/effect/Spatializer.aidl b/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
index 4edb2e8..6ebe0d5 100644
--- a/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
@@ -52,29 +52,37 @@
     VendorExtension vendor;
 
     /**
-     * Level of spatialization.
-     */
-    Spatialization.Level spatializationLevel;
-
-    /**
-     * Head tracking mode for spatialization.
-     */
-    HeadTracking.Mode headTrackingMode;
-
-    /**
      * List of supported input channel layouts.
      */
     AudioChannelLayout[] supportedChannelLayout;
 
     /**
+     * Level of spatialization.
+     */
+    Spatialization.Level spatializationLevel;
+
+    /**
      * Spatialization mode, Binaural or Transaural for example.
      */
     Spatialization.Mode spatializationMode;
 
     /**
-     * Vector representing of the head-to-stage pose with six floats: first three are a translation
-     * vector, and the last three are a rotation vector.
+     * Head tracking sensor ID.
      */
-    const int HEAD_TO_STAGE_VEC_SIZE = 6;
-    float[HEAD_TO_STAGE_VEC_SIZE] headToStage;
+    int headTrackingSensorId;
+
+    /**
+     * Head tracking mode for spatialization.
+     */
+    HeadTracking.Mode headTrackingMode;
+
+    /**
+     * Head tracking sensor connection mode for spatialization.
+     */
+    HeadTracking.ConnectionMode headTrackingConnectionMode;
+
+    /**
+     * Headtracking sensor data.
+     */
+    HeadTracking.SensorData headTrackingSensorData;
 }
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index a633d83..2b86271 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -17,6 +17,9 @@
 #include <algorithm>
 #include <chrono>
 
+#define LOG_TAG "VtsHalAudio.ModuleConfig"
+#include <android-base/logging.h>
+
 #include <Utils.h>
 #include <aidl/android/media/audio/common/AudioInputFlags.h>
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
diff --git a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
index 8a085e5..4d0995d 100644
--- a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
+++ b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
@@ -76,30 +76,20 @@
 using ::android::hardware::automotive::vehicle::V2_0::vms::VmsLayerOffering;
 using ::android::hardware::automotive::vehicle::V2_0::vms::VmsOffers;
 
-constexpr const char kCarMake[] = "Default Car";
-constexpr VehicleProperty kVehicleProp[] = {VehicleProperty::INVALID,
-                                            VehicleProperty::HVAC_FAN_SPEED,
-                                            VehicleProperty::INFO_MAKE,
-                                            VehicleProperty::DISPLAY_BRIGHTNESS,
-                                            VehicleProperty::INFO_FUEL_CAPACITY,
-                                            VehicleProperty::HVAC_SEAT_TEMPERATURE};
-constexpr DiagnosticIntegerSensorIndex kDiagnosticIntIndex[] = {
-        DiagnosticIntegerSensorIndex::FUEL_SYSTEM_STATUS,
-        DiagnosticIntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON,
-        DiagnosticIntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT,
-        DiagnosticIntegerSensorIndex::FUEL_TYPE};
-constexpr DiagnosticFloatSensorIndex kDiagnosticFloatIndex[] = {
-        DiagnosticFloatSensorIndex::CALCULATED_ENGINE_LOAD,
-        DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1,
-        DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1,
-        DiagnosticFloatSensorIndex::THROTTLE_POSITION};
-constexpr size_t kVehiclePropArrayLength = std::size(kVehicleProp);
-constexpr size_t kIntSensorArrayLength = std::size(kDiagnosticIntIndex);
-constexpr size_t kFloatSensorArrayLength = std::size(kDiagnosticFloatIndex);
-constexpr VmsMessageType kAvailabilityMessageType[] = {VmsMessageType::AVAILABILITY_CHANGE,
-                                                       VmsMessageType::AVAILABILITY_RESPONSE};
-constexpr VmsMessageType kSubscriptionMessageType[] = {VmsMessageType::SUBSCRIPTIONS_CHANGE,
-                                                       VmsMessageType::SUBSCRIPTIONS_RESPONSE};
+std::string kCarMake;
+constexpr int32_t kMaxCaseMessage = 8;
+constexpr int32_t kMaxRuns = 20;
+constexpr int32_t kMaxSize = 1000;
+constexpr int32_t kMinSize = 0;
+constexpr int32_t kMaxFileSize = 100;
+float kFloatValue;
+std::vector<int32_t> kVec32;
+std::vector<int64_t> kVec64;
+std::vector<uint8_t> kVec8;
+std::vector<float> kVecFloat;
+static const std::vector<std::string> kSampleDtcs = {"P0070",
+                                                     "P0102"
+                                                     "P0123"};
 
 MockedVehicleHal::VehiclePropValuePtr MockedVehicleHal::get(
         const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
@@ -113,23 +103,23 @@
 
     switch (property) {
         case VehicleProperty::INFO_MAKE:
-            pValue = getValuePool()->obtainString(kCarMake);
+            pValue = getValuePool()->obtainString(kCarMake.c_str());
             break;
         case VehicleProperty::INFO_FUEL_CAPACITY:
             if (mFuelCapacityAttemptsLeft-- > 0) {
                 *outStatus = StatusCode::TRY_AGAIN;
             } else {
-                pValue = getValuePool()->obtainFloat(42.42);
+                pValue = getValuePool()->obtainFloat(kFloatValue);
             }
             break;
         default:
             if (requestedPropValue.prop == kCustomComplexProperty) {
                 pValue = getValuePool()->obtainComplex();
-                pValue->value.int32Values = hidl_vec<int32_t>{10, 20};
-                pValue->value.int64Values = hidl_vec<int64_t>{30, 40};
-                pValue->value.floatValues = hidl_vec<float_t>{1.1, 2.2};
-                pValue->value.bytes = hidl_vec<uint8_t>{1, 2, 3};
-                pValue->value.stringValue = kCarMake;
+                pValue->value.int32Values = hidl_vec<int32_t>{kVec32};
+                pValue->value.int64Values = hidl_vec<int64_t>{kVec64};
+                pValue->value.floatValues = hidl_vec<float_t>{kVecFloat};
+                pValue->value.bytes = hidl_vec<uint8_t>{kVec8};
+                pValue->value.stringValue = kCarMake.c_str();
                 break;
             }
             auto key = makeKey(toInt(property), areaId);
@@ -145,28 +135,72 @@
     return pValue;
 }
 
+void VehicleHalManagerFuzzer::initValue() {
+    kCarMake = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+    kFloatValue = mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+    fillParameter<int32_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+                           kVec32);
+    fillParameter<int64_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+                           kVec64);
+    fillParameter<uint8_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+                           kVec8);
+    size_t size = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+    for (size_t i = 0; i < size; ++i) {
+        kVecFloat.push_back(mFuzzedDataProvider->ConsumeFloatingPoint<float>());
+    }
+}
+
 void VehicleHalManagerFuzzer::process(const uint8_t* data, size_t size) {
     mFuzzedDataProvider = new FuzzedDataProvider(data, size);
-    invokeDebug();
-    invokePropConfigs();
-    invokeSubscribe();
-    invokeSetAndGetValues();
-    invokeObd2SensorStore();
-    invokeVmsUtils();
-    invokeVehiclePropStore();
-    invokeWatchDogClient();
+    initValue();
+    /* Limited while loop runs to prevent timeouts caused
+     * by repeated calls to high-execution-time APIs.
+     */
+    size_t maxRuns = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxRuns);
+    size_t itr = 0;
+    while (mFuzzedDataProvider->remaining_bytes() && ++itr <= maxRuns) {
+        auto invokeVehicleHalManagerFuzzer =
+                mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                        [&]() { invokeDebug(); },
+                        [&]() { invokePropConfigs(); },
+                        [&]() { invokeSubscribe(); },
+                        [&]() { invokeSetAndGetValues(); },
+                        [&]() { invokeObd2SensorStore(); },
+                        [&]() { invokeVmsUtils(); },
+                        [&]() { invokeVehiclePropStore(); },
+                        [&]() { invokeWatchDogClient(); },
+                });
+        invokeVehicleHalManagerFuzzer();
+    }
 }
 
 void VehicleHalManagerFuzzer::invokeDebug() {
-    hidl_string debugOption = mFuzzedDataProvider->PickValueInArray(
-            {"--help", "--list", "--get", "--set", "", "invalid"});
     hidl_handle fd = {};
 
     native_handle_t* rawHandle = native_handle_create(/*numFds=*/1, /*numInts=*/0);
     fd.setTo(native_handle_clone(rawHandle), /*shouldOwn=*/true);
+    int32_t size = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxFileSize);
+    hidl_vec<hidl_string> options(size);
 
-    mManager->debug(fd, {});
-    mManager->debug(fd, {debugOption});
+    for (int32_t idx = 0; idx < size; ++idx) {
+        if (idx == 0 && mFuzzedDataProvider->ConsumeBool()) {
+            options[idx] = mFuzzedDataProvider->PickValueInArray(
+                    {"--help", "--list", "--get", "--set", "", "invalid"});
+        } else if (idx == 2 && mFuzzedDataProvider->ConsumeBool()) {
+            options[idx] =
+                    mFuzzedDataProvider->PickValueInArray({"-i", "-i64", "-f", "-s", "-b", "-a"});
+        } else if (mFuzzedDataProvider->ConsumeBool()) {
+            options[idx] = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxSize);
+        } else {
+            options[idx] = std::to_string(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+        }
+    }
+
+    if (mFuzzedDataProvider->ConsumeBool()) {
+        mManager->debug(fd, {});
+    } else {
+        mManager->debug(fd, options);
+    }
     native_handle_delete(rawHandle);
 }
 
@@ -175,178 +209,245 @@
     int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
 
     hidl_vec<int32_t> properties = {vehicleProp1, vehicleProp2};
+    auto invokePropConfigsAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() {
+                mManager->getPropConfigs(
+                        properties, []([[maybe_unused]] StatusCode status,
+                                       [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
+            },
+            [&]() {
+                mManager->getPropConfigs(
+                        {mFuzzedDataProvider->ConsumeIntegral<int32_t>()},
+                        []([[maybe_unused]] StatusCode status,
+                           [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
+            },
+            [&]() {
+                mManager->getAllPropConfigs(
+                        []([[maybe_unused]] const hidl_vec<VehiclePropConfig>& propConfigs) {});
+            },
 
-    mManager->getPropConfigs(properties,
-                             []([[maybe_unused]] StatusCode status,
-                                [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
-
-    mManager->getPropConfigs({toInt(kVehicleProp[abs(vehicleProp1) % kVehiclePropArrayLength])},
-                             []([[maybe_unused]] StatusCode status,
-                                [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
-
-    mManager->getAllPropConfigs(
-            []([[maybe_unused]] const hidl_vec<VehiclePropConfig>& propConfigs) {});
+    });
+    invokePropConfigsAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeSubscribe() {
-    int32_t vehicleProp1 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
     int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
     int32_t vehicleProp3 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
 
-    const auto prop1 = toInt(kVehicleProp[abs(vehicleProp1) % kVehiclePropArrayLength]);
     sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+    VehiclePropertyType type =
+            static_cast<VehiclePropertyType>(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
 
-    hidl_vec<SubscribeOptions> options = {
-            SubscribeOptions{.propId = prop1, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
+    auto invokeSubscribeAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() {
+                size_t size =
+                        mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+                hidl_vec<SubscribeOptions> options(size);
+                for (size_t idx = 0; idx < size; ++idx) {
+                    options[idx] = {SubscribeOptions{
+                            .propId = mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                            .flags = static_cast<SubscribeFlags>(
+                                    mFuzzedDataProvider->ConsumeIntegral<int32_t>())}};
+                }
+                mManager->subscribe(cb, options);
+            },
+            [&]() {
+                auto unsubscribedValue = mObjectPool->obtain(type);
+                if (!unsubscribedValue) {
+                    return;
+                }
+                unsubscribedValue->prop = vehicleProp2;
+                unsubscribedValue->value.int32Values[0] = INT32_MAX;
+                mHal->sendPropEvent(std::move(unsubscribedValue));
+                cb->waitForExpectedEvents(mFuzzedDataProvider->ConsumeIntegral<size_t>());
+            },
+            [&]() {
+                const auto prop1 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                mManager->unsubscribe(cb, prop1);
+            },
+            [&]() {
+                mHal->sendHalError(StatusCode::TRY_AGAIN, vehicleProp3,
+                                   mFuzzedDataProvider->ConsumeIntegral<int32_t>() /*areaId=*/);
+            },
 
-    mManager->subscribe(cb, options);
-
-    auto unsubscribedValue = mObjectPool->obtain(VehiclePropertyType::INT32);
-    unsubscribedValue->prop = toInt(kVehicleProp[abs(vehicleProp2) % kVehiclePropArrayLength]);
-
-    mHal->sendPropEvent(std::move(unsubscribedValue));
-    cb->getReceivedEvents();
-    cb->waitForExpectedEvents(0);
-
-    auto subscribedValue = mObjectPool->obtain(VehiclePropertyType::INT32);
-    subscribedValue->prop = toInt(kVehicleProp[abs(vehicleProp2) % kVehiclePropArrayLength]);
-    subscribedValue->value.int32Values[0] = INT32_MAX;
-
-    cb->reset();
-    VehiclePropValue actualValue(*subscribedValue.get());
-    mHal->sendPropEvent(std::move(subscribedValue));
-    cb->waitForExpectedEvents(1);
-    mManager->unsubscribe(cb, prop1);
-
-    sp<MockedVehicleCallback> cb2 = new MockedVehicleCallback();
-
-    hidl_vec<SubscribeOptions> options2 = {
-            SubscribeOptions{
-                    .propId = toInt(kVehicleProp[abs(vehicleProp3) % kVehiclePropArrayLength]),
-                    .flags = SubscribeFlags::EVENTS_FROM_CAR},
-    };
-
-    mManager->subscribe(cb2, options2);
-
-    mHal->sendHalError(StatusCode::TRY_AGAIN,
-                       toInt(kVehicleProp[abs(vehicleProp3) % kVehiclePropArrayLength]),
-                       /*areaId=*/0);
+    });
+    invokeSubscribeAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeSetAndGetValues() {
-    uint32_t vehicleProp1 =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
-    uint32_t vehicleProp2 =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
-    uint32_t vehicleProp3 =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
-
-    invokeGet(kCustomComplexProperty, 0);
-    invokeGet(toInt(kVehicleProp[vehicleProp2]), 0);
-    invokeGet(toInt(kVehicleProp[vehicleProp1]), 0);
-
-    auto expectedValue = mObjectPool->obtainInt32(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
-    mObjectPool->obtainInt64(mFuzzedDataProvider->ConsumeIntegral<int64_t>());
-    mObjectPool->obtainFloat(mFuzzedDataProvider->ConsumeFloatingPoint<float>());
-    mObjectPool->obtainBoolean(mFuzzedDataProvider->ConsumeBool());
-    expectedValue->prop = toInt(kVehicleProp[vehicleProp2]);
-    expectedValue->areaId = 0;
-
-    mManager->set(*expectedValue.get());
-    invokeGet(toInt(kVehicleProp[vehicleProp2]), 0);
-    expectedValue->prop = toInt(kVehicleProp[vehicleProp3]);
-    mManager->set(*expectedValue.get());
-    expectedValue->prop = toInt(VehicleProperty::INVALID);
-    mManager->set(*expectedValue.get());
+    auto invokeSetAndGetAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() {
+                invokeGet(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                          mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+            },
+            [&]() { mObjectPool->obtainInt64(mFuzzedDataProvider->ConsumeIntegral<int64_t>()); },
+            [&]() { mObjectPool->obtainFloat(mFuzzedDataProvider->ConsumeFloatingPoint<float>()); },
+            [&]() { mObjectPool->obtainBoolean(mFuzzedDataProvider->ConsumeBool()); },
+            [&]() {
+                int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                auto expectedValue =
+                        mObjectPool->obtainInt32(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+                expectedValue->prop = vehicleProp2;
+                expectedValue->areaId = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                mManager->set(*expectedValue.get());
+            },
+    });
+    invokeSetAndGetAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeObd2SensorStore() {
-    uint32_t diagnosticIntIndex =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kIntSensorArrayLength - 1);
-    int32_t diagnosticIntValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
-    uint32_t diagnosticFloatIndex =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kFloatSensorArrayLength - 1);
-    float diagnosticFloatValue = mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+    size_t diagnosticInt = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+    size_t diagnosticFloat =
+            mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
 
     std::unique_ptr<Obd2SensorStore> sensorStore(
-            new Obd2SensorStore(kIntSensorArrayLength, kFloatSensorArrayLength));
-    if (sensorStore) {
-        sensorStore->setIntegerSensor(kDiagnosticIntIndex[diagnosticIntIndex], diagnosticIntValue);
-        sensorStore->setFloatSensor(kDiagnosticFloatIndex[diagnosticFloatIndex],
-                                    diagnosticFloatValue);
-        sensorStore->getIntegerSensors();
-        sensorStore->getFloatSensors();
-        sensorStore->getSensorsBitmask();
-        static std::vector<std::string> sampleDtcs = {"P0070",
-                                                      "P0102"
-                                                      "P0123"};
-        for (auto&& dtc : sampleDtcs) {
-            auto freezeFrame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
-            sensorStore->fillPropValue(dtc, freezeFrame.get());
-            freezeFrame->prop = static_cast<int>(VehicleProperty::OBD2_FREEZE_FRAME);
-        }
+            new Obd2SensorStore(diagnosticInt, diagnosticFloat));
+
+    if (!sensorStore.get()) {
+        return;
     }
+
+    auto invokeObd2SensorStoreAPI =
+            mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                    [&]() {
+                        int32_t diagnosticIntValue =
+                                mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                        int32_t diagnosticIntIndex =
+                                mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+                                        kMinSize,
+                                        toInt(DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX) +
+                                                diagnosticInt);
+                        sensorStore->setIntegerSensor(
+                                static_cast<DiagnosticIntegerSensorIndex>(diagnosticIntIndex),
+                                diagnosticIntValue);
+                    },
+                    [&]() {
+                        float diagnosticFloatValue =
+                                mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+                        int32_t diagnosticFloatIndex =
+                                mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+                                        kMinSize,
+                                        toInt(DiagnosticFloatSensorIndex::LAST_SYSTEM_INDEX) +
+                                                diagnosticFloat);
+                        sensorStore->setFloatSensor(
+                                static_cast<DiagnosticFloatSensorIndex>(diagnosticFloatIndex),
+                                diagnosticFloatValue);
+                    },
+                    [&]() { sensorStore->getIntegerSensors(); },
+                    [&]() { sensorStore->getFloatSensors(); },
+                    [&]() { sensorStore->getSensorsBitmask(); },
+                    [&]() {
+                        for (auto&& dtc : kSampleDtcs) {
+                            VehiclePropertyType type = static_cast<VehiclePropertyType>(
+                                    mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+                            auto freezeFrame = createVehiclePropValue(
+                                    type, mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+                                                  kMinSize, kMaxSize));
+                            if (!freezeFrame.get()) {
+                                return;
+                            }
+                            freezeFrame->prop = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                            sensorStore->fillPropValue(dtc, freezeFrame.get());
+                        }
+                    },
+            });
+    invokeObd2SensorStoreAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeVmsUtils() {
-    bool availabilityMsgType = mFuzzedDataProvider->ConsumeBool();
-    bool subscriptionMsgType = mFuzzedDataProvider->ConsumeBool();
+    std::unique_ptr<VehiclePropValue> message;
     int32_t intValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+    VmsLayer layer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                   mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                   mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+    VmsOffers offers = {
+            intValue,
+            {VmsLayerOffering(VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>()))}};
+    const VmsLayerAndPublisher layer_and_publisher(
+            VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                     mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                     mFuzzedDataProvider->ConsumeIntegral<int32_t>()),
+            intValue);
 
-    VmsLayer layer(1, 0, 2);
-    auto message = createSubscribeMessage(layer);
+    switch (mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxCaseMessage)) {
+        case 0: {
+            message = createSubscribeMessage(layer);
+            break;
+        }
+        case 1: {
+            message = createUnsubscribeMessage(layer);
+            break;
+        }
+        case 2: {
+            message = createSubscriptionsRequest();
+            break;
+        }
+        case 3: {
+            message = createOfferingMessage(offers);
+            break;
+        }
+        case 4: {
+            message = createAvailabilityRequest();
+            break;
+        }
+        case 5: {
+            std::string pub_bytes;
+            if (mFuzzedDataProvider->ConsumeBool()) {
+                pub_bytes = "pub_id";
+            } else {
+                pub_bytes = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+            }
+            message = createPublisherIdRequest(pub_bytes);
+            break;
+        }
+        case 6: {
+            std::string bytes = "placeholder";
+            if (mFuzzedDataProvider->ConsumeBool()) {
+                bytes = "placeholder";
+            } else {
+                bytes = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+            }
+            message = createDataMessageWithLayerPublisherInfo(layer_and_publisher, bytes);
+            break;
+        }
+        case 7: {
+            message = createBaseVmsMessage(
+                    mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize));
+            break;
+        }
+        case 8: {
+            message = createStartSessionMessage(intValue, intValue + 1);
+            break;
+        }
+    }
+
     isValidVmsMessage(*message);
-    message = createUnsubscribeMessage(layer);
-
-    VmsOffers offers = {intValue, {VmsLayerOffering(VmsLayer(1, 0, 2))}};
-    message = createOfferingMessage(offers);
-    std::vector<VmsLayer> dependencies = {VmsLayer(2, 0, 2), VmsLayer(3, 0, 3)};
-    std::vector<VmsLayerOffering> offering = {VmsLayerOffering(layer, dependencies)};
-    offers = {intValue, offering};
-    message = createOfferingMessage(offers);
-
-    message = createAvailabilityRequest();
-    message = createSubscriptionsRequest();
-
-    std::string bytes = "placeholder";
-    const VmsLayerAndPublisher layer_and_publisher(VmsLayer(2, 0, 1), intValue);
-    message = createDataMessageWithLayerPublisherInfo(layer_and_publisher, bytes);
-    parseData(*message);
-    createSubscribeToPublisherMessage(layer_and_publisher);
-    createUnsubscribeToPublisherMessage(layer_and_publisher);
-
-    std::string pub_bytes = "pub_id";
-    message = createPublisherIdRequest(pub_bytes);
-    message = createBaseVmsMessage(2);
     message->value.int32Values =
-            hidl_vec<int32_t>{toInt(VmsMessageType::PUBLISHER_ID_RESPONSE), intValue};
-    parsePublisherIdResponse(*message);
+            hidl_vec<int32_t>{mFuzzedDataProvider->ConsumeIntegral<int32_t>(), intValue};
 
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kSubscriptionMessageType[subscriptionMsgType]), intValue};
-    getSequenceNumberForSubscriptionsState(*message);
-
-    message->value.int32Values = hidl_vec<int32_t>{toInt(kSubscriptionMessageType[0]), intValue};
-    isSequenceNumberNewer(*message, intValue + 1);
-    invokeGetSubscribedLayers(kSubscriptionMessageType[subscriptionMsgType]);
-
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), 0};
-    hasServiceNewlyStarted(*message);
-    message = createStartSessionMessage(intValue, intValue + 1);
-    parseMessageType(*message);
-
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), intValue};
-    isAvailabilitySequenceNumberNewer(*message, intValue + 1);
-
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), intValue};
-    getSequenceNumberForAvailabilityState(*message);
-    message = createBaseVmsMessage(3);
-    int new_service_id;
-    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 0, -1};
-    parseStartSessionMessage(*message, -1, 0, &new_service_id);
+    auto invokeVmsUtilsAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() { parseData(*message); },
+            [&]() { createSubscribeToPublisherMessage(layer_and_publisher); },
+            [&]() { createUnsubscribeToPublisherMessage(layer_and_publisher); },
+            [&]() { parsePublisherIdResponse(*message); },
+            [&]() { getSequenceNumberForSubscriptionsState(*message); },
+            [&]() { isSequenceNumberNewer(*message, intValue + 1); },
+            [&]() {
+                invokeGetSubscribedLayers(
+                        (VmsMessageType)mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+            },
+            [&]() { hasServiceNewlyStarted(*message); },
+            [&]() { parseMessageType(*message); },
+            [&]() { isAvailabilitySequenceNumberNewer(*message, intValue + 1); },
+            [&]() { getSequenceNumberForAvailabilityState(*message); },
+            [&]() {
+                int32_t new_service_id;
+                parseStartSessionMessage(*message, -1, 0, &new_service_id);
+            },
+    });
+    invokeVmsUtilsAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeGet(int32_t property, int32_t areaId) {
@@ -367,27 +468,31 @@
     mActualStatusCode = refStatus;
 }
 
-void VehicleHalManagerFuzzer::invokeGetSubscribedLayers(VmsMessageType type) {
-    VmsOffers offers = {123,
-                        {VmsLayerOffering(VmsLayer(1, 0, 1), {VmsLayer(4, 1, 1)}),
-                         VmsLayerOffering(VmsLayer(2, 0, 1))}};
-    auto message = createBaseVmsMessage(16);
-    message->value.int32Values = hidl_vec<int32_t>{toInt(type),
-                                                   1234,  // sequence number
-                                                   2,     // number of layers
-                                                   1,     // number of associated layers
-                                                   1,     // layer 1
-                                                   0,           1,
-                                                   4,  // layer 2
-                                                   1,           1,
-                                                   2,  // associated layer
-                                                   0,           1,
-                                                   2,    // number of publisher IDs
-                                                   111,  // publisher IDs
-                                                   123};
-    isValidVmsMessage(*message);
-    getSubscribedLayers(*message, offers);
-    getAvailableLayers(*message);
+void VehicleHalManagerFuzzer::invokeGetSubscribedLayers(VmsMessageType /*type*/) {
+    int32_t intValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+    VmsOffers offers = {
+            intValue,
+            {VmsLayerOffering(VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>()))}};
+    auto message = createBaseVmsMessage(
+            mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxFileSize));
+    std::vector<int32_t> v;
+    size_t size = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+    for (size_t i = 0; i < size; i++) {
+        v.push_back(mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxSize));
+    }
+
+    message->value.int32Values = hidl_vec<int32_t>(v);
+    if (!isValidVmsMessage(*message)) {
+        return;
+    }
+
+    if (mFuzzedDataProvider->ConsumeBool()) {
+        getSubscribedLayers(*message, offers);
+    } else {
+        getAvailableLayers(*message);
+    }
 }
 
 void VehicleHalManagerFuzzer::invokeVehiclePropStore() {
@@ -398,33 +503,49 @@
             .prop = vehicleProp,
             .access = VehiclePropertyAccess::READ,
             .changeMode = VehiclePropertyChangeMode::STATIC,
-            .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+            .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (mFuzzedDataProvider->ConsumeIntegral<int32_t>())}},
     };
-    store->registerProperty(config);
     VehiclePropValue propValue{};
     propValue.prop = vehicleProp;
-    propValue.areaId = 0;
-    store->writeValue(propValue, shouldWriteStatus);
-    store->readAllValues();
-    store->getAllConfigs();
-    store->getConfigOrNull(vehicleProp);
-    store->readValuesForProperty(vehicleProp);
-    store->readValueOrNull(propValue);
-    store->readValueOrNull(propValue.prop, propValue.areaId, 0);
-    store->removeValuesForProperty(vehicleProp);
-    store->removeValue(propValue);
-    store->getConfigOrDie(vehicleProp);
+    propValue.areaId = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+
+    auto invokeVehiclePropStoreAPI =
+            mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                    [&]() { store->registerProperty(config); },
+                    [&]() { store->writeValue(propValue, shouldWriteStatus); },
+                    [&]() { store->readAllValues(); },
+                    [&]() { store->getAllConfigs(); },
+                    [&]() { store->getConfigOrNull(vehicleProp); },
+                    [&]() { store->readValuesForProperty(vehicleProp); },
+                    [&]() { store->readValueOrNull(propValue); },
+                    [&]() {
+                        store->readValueOrNull(propValue.prop, propValue.areaId,
+                                               mFuzzedDataProvider->ConsumeIntegralInRange<int64_t>(
+                                                       kMinSize, kMaxFileSize));
+                    },
+                    [&]() { store->removeValuesForProperty(vehicleProp); },
+                    [&]() { store->removeValue(propValue); },
+                    [&]() {
+                        if (store->getConfigOrNull(vehicleProp)) {
+                            store->getConfigOrDie(vehicleProp);
+                        }
+                    },
+            });
+    invokeVehiclePropStoreAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeWatchDogClient() {
-    auto service = new VehicleHalManager(mHal.get());
     sp<Looper> looper(Looper::prepare(/*opts=*/mFuzzedDataProvider->ConsumeBool()));
-    if (auto watchdogClient = ndk::SharedRefBase::make<WatchdogClient>(looper, service);
+    if (auto watchdogClient = ndk::SharedRefBase::make<WatchdogClient>(looper, mManager.get());
         watchdogClient->initialize()) {
-        watchdogClient->checkIfAlive(-1, TimeoutLength::TIMEOUT_NORMAL);
+        if (mFuzzedDataProvider->ConsumeBool()) {
+            watchdogClient->checkIfAlive(
+                    mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                    (TimeoutLength)mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+        }
         watchdogClient->prepareProcessTermination();
     }
-    delete service;
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
index e9335d3..26ac11e 100644
--- a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
+++ b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
@@ -98,6 +98,13 @@
     }
     void process(const uint8_t* data, size_t size);
 
+    template <typename T>
+    void fillParameter(size_t size, std::vector<T>& data) {
+        for (size_t i = 0; i < size; ++i) {
+            data.push_back(mFuzzedDataProvider->ConsumeIntegral<T>());
+        }
+    }
+
   private:
     FuzzedDataProvider* mFuzzedDataProvider = nullptr;
     VehiclePropValue mActualValue = VehiclePropValue{};
@@ -108,6 +115,7 @@
     std::unique_ptr<VehicleHalManager> mManager;
 
     void invokeDebug();
+    void initValue();
     void invokePropConfigs();
     void invokeSubscribe();
     void invokeSetAndGetValues();
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 0bcafa3..c283148 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -439,6 +439,9 @@
 }
 
 void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) {
+  if (session_type_ != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    return;
+  }
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   low_latency_allowed_ = allowed;
   // TODO(b/294498919): Remove this after there is API to update latency mode
@@ -588,15 +591,32 @@
                << " has NO session";
     return std::vector<LatencyMode>();
   }
-  if (low_latency_allowed_) return latency_modes_;
-  std::vector<LatencyMode> modes;
-  for (LatencyMode mode : latency_modes_) {
-    if (mode == LatencyMode::LOW_LATENCY)
-      // ignore those low latency mode if Bluetooth stack doesn't allow
-      continue;
-    modes.push_back(mode);
+
+  std::vector<LatencyMode> supported_latency_modes;
+  if (session_type_ ==
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    for (LatencyMode mode : latency_modes_) {
+      if (mode == LatencyMode::LOW_LATENCY) {
+        // LOW_LATENCY is not supported for LE_HARDWARE_OFFLOAD_ENC sessions
+        continue;
+      }
+      supported_latency_modes.push_back(mode);
+    }
+  } else {
+    for (LatencyMode mode : latency_modes_) {
+      if (!low_latency_allowed_ && mode == LatencyMode::LOW_LATENCY) {
+        // ignore LOW_LATENCY mode if Bluetooth stack doesn't allow
+        continue;
+      }
+      if (mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE ||
+          mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
+        // DSA_SW and DSA_HW only supported for LE_HARDWARE_OFFLOAD_ENC sessions
+        continue;
+      }
+      supported_latency_modes.push_back(mode);
+    }
   }
-  return modes;
+  return supported_latency_modes;
 }
 
 void BluetoothAudioSession::SetLatencyMode(const LatencyMode& latency_mode) {
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
index 4c1b965..0bc39d6 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
@@ -28,19 +28,19 @@
     ? -70003 : int,   ; Timestamp in milliseconds since some starting point (generally
                       ; the most recent device boot) which all of the applications within
                       ; the secure domain must agree upon
-    ? -70004 : bstr .size 16,      ; Nonce used in key exchange methods
+    ? -70004 : bstr .size 16,      ; Nonce (a cryptographic random number of 16 bytes) used in key
+                                   ; exchange methods
     ? -70005 : PayloadType,        ; Payload type, if needed to disambiguate, when processing an arc
     ? -70006 : int,                ; Version of the payload structure (if applicable)
     ? -70007 : int,                ; Sequence number (if needed to prevent replay attacks)
     ? -70008 : Direction           ; Direction of the encryption key (i.e. whether it is used to
                                    ; encrypt incoming messages or outgoing messages)
     ? -70009 : bool,               ; "authentication_completed" - this is used during authenticated
-                                   ; key exchange indicate whether signature verification is done
-    ? -70010 : bstr .size 32       ; "session_id" computed during key exchange protocol
+                                   ; key exchange to indicate whether signature verification is done
+    ? -70010 : bstr .size 32       ; "session_id" computed during the key exchange protocol
 }
 
-; Permissions indicate what an arc can be used with. Permissions are added to an arc during the
-; `create()` primitive operation and are propagated during `mint` and `snap` primitive operations.
+; Permissions indicate what an arc can be used with.
 Permission = &(
     -4770552 : IdentityEncoded,  ; "source_id" - in the operations performed by a source, the
                                  ; source adds its own identity to the permissions of an arc.
@@ -54,12 +54,10 @@
                                      ; biometrics.
 )
 
-; Limitations indicate what restrictions are applied on the usage of an arc. Permissions are added
-; to an arc during the `create` primitive operation and are propagated during `snap` primitive
-; operation.
+; Limitations indicate what restrictions are applied on the usage of an arc.
 Limitation = &(
-    -4770554 : bstr,      ; "challenge" - is added to an arc that transfers an auth key to a channel
-                          ; key, in order to ensure the freshness of the authentication.
+    -4770554 : bstr,      ; "challenge" - is added to an arc that encrypts an auth key from a
+                          ; channel key, in order to ensure the freshness of the authentication.
                           ; A challenge is issued by a sink (e.g. Keymint TA, Biometric TAs).
 )
 
@@ -83,7 +81,7 @@
     ; Any other payload formats should also be defined here
 )
 
-SecretKey = &(                     ; One of the payload types of an Arc is a secret key
+SecretKey = &(
     SymmetricKey,
     ECPrivateKey,    ; Private key of a key pair generated for key exchange
 )
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
index 6ceb09c..a3fb959 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
@@ -41,8 +41,8 @@
 interface IAuthGraphKeyExchange {
     /**
      * This method is invoked on P1 (source).
-     * Create an ephermeral EC key pair on NIST curve P-256 and a nonce (of 16 bytes) for
-     * key exchange.
+     * Create an ephermeral EC key pair on NIST curve P-256 and a nonce (a cryptographic random
+     * number of 16 bytes) for key exchange.
      *
      * @return SessionInitiationInfo including the `Key` containing the public key of the created
      * key pair and an arc from the per-boot key to the private key, the nonce, the persistent
@@ -52,8 +52,8 @@
      * `SessionInitiationInfo` serves two purposes:
      * i. A mapping to correlate `create` and `finish` calls to P1 in a particular instance of the
      *    key exchange protocol.
-     * ii.A way to minimize the in-memory storage (P1 can include the nonce in the protected headers
-     *    of the arc).
+     * ii.A way to minimize the in-memory storage of P1 allocated for key exchange (P1 can include
+     *    the nonce in the protected headers of the arc).
      * However, P1 should maintain some form of in-memory record to be able to verify that the input
      * `Key` sent to `finish` is from an unfinished instance of a key exchange protocol, to prevent
      * any replay attacks in `finish`.
@@ -66,9 +66,9 @@
      *     0. If either `peerPubKey`, `peerId`, `peerNonce` is not in the expected format, return
      *        errors: INVALID_PEER_KE_KEY, INVALID_IDENTITY, INVALID_PEER_NONCE respectively.
      *     1. Create an ephemeral EC key pair on NIST curve P-256.
-     *     2. Create a nonce (of 16 bytes).
-     *     3. Compute the diffie-hellman shared secret: Z.
-     *     4. Compute a salt = bstr .cbor [
+     *     2. Create a nonce (a cryptographic random number of 16 bytes).
+     *     3. Compute the Diffie-Hellman shared secret: Z.
+     *     4. Compute a salt_input = bstr .cbor [
      *            source_version:    int,                    ; from input `peerVersion`
      *            sink_pub_key:      bstr .cbor PlainPubKey, ; from step #1
      *            source_pub_key:    bstr .cbor PlainPubKey, ; from input `peerPubKey`
@@ -77,7 +77,8 @@
      *            sink_cert_chain:   bstr .cbor ExplicitKeyDiceCertChain, ; from own identity
      *            source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from input `peerId`
      *        ]
-     *     5. Extract a cryptographic secret S from Z, using the salt from #4 above.
+     *     5. Extract a cryptographic secret S from Z, using the SHA256 digest of the salt_input
+     *        as the salt.
      *     6. Derive two symmetric encryption keys of 256 bits with:
      *        i. b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK" as context for the key used to encrypt incoming
      *           messages
@@ -96,28 +97,29 @@
      *        part of the party's identity.
      *
      * @param peerPubKey - the public key of the key pair created by the peer (P1) for key exchange
+     *                     in `create`
      *
      * @param peerId - the persistent identity of the peer
      *
-     * @param peerNonce - nonce created by the peer
+     * @param peerNonce - nonce created by the peer in `create`
      *
      * @param peerVersion - an integer representing the latest protocol version (i.e. AIDL version)
      *                      supported by the peer
      *
-     * @return KeInitResult including the `Key` containing the public key of the created key pair,
-     * the nonce, the persistent identity, two shared key arcs from step #7, session id, signature
-     * over the session id and the negotiated protocol version. The negotiated protocol version
-     * should be less than or equal to the peer's version.
+     * @return KeInitResult including the `Key` containing the public key of the key pair created in
+     * step #1, the nonce from step #2, the persistent identity of P2, two shared key arcs
+     * from step #7, session id from step #10, signature over the session id from step #11 and the
+     * negotiated protocol version. The negotiated protocol version should be less than or equal to
+     * the `peerVersion`.
      *
-     * Note: The two shared key arcs in the return type: `KeInitResult` serves two purposes:
+     * Note: The two shared key arcs in the return type: `KeInitResult` serve two purposes:
      * i. A mapping to correlate `init` and `authenticationComplete` calls to P2 in a particular
      *    instance of the key exchange protocol.
      * ii.A way to minimize the in-memory storage of P2 allocated for key exchange.
      * However, P2 should maintain some in-memory record to be able to verify that the input
-     * `sharedkeys` sent to `authenticationComplete` and to any subsequent AuthGraph protocol
-     * methods are valid shared keys agreed with the party identified by `peerId`, to prevent
-     * any replay attacks in `authenticationComplete` and in any subsequent AuthGraph protocol
-     * methods which use the shared keys to encrypt the secret messages.
+     * `sharedkeys` sent to `authenticationComplete` are from an unfinished instance of a key
+     * exchange protocol carried out with the party identified by `peerId`, to prevent any replay
+     * attacks in `authenticationComplete`.
      */
     KeInitResult init(
             in PubKey peerPubKey, in Identity peerId, in byte[] peerNonce, in int peerVersion);
@@ -133,8 +135,8 @@
      *        exchange protocol, return error: INVALID_KE_KEY. Similarly, if the public key or the
      *        arc containing the private key in `ownKey` is invalid, return INVALID_PUB_KEY_IN_KEY
      *        and INVALID_PRIV_KEY_ARC_IN_KEY respectively.
-     *     1. Compute the diffie-hellman shared secret: Z.
-     *     2. Compute a salt = bstr .cbor [
+     *     1. Compute the Diffie-Hellman shared secret: Z.
+     *     2. Compute a salt_input = bstr .cbor [
      *            source_version:    int,                    ; the protocol version used in `create`
      *            sink_pub_key:      bstr .cbor PlainPubKey, ; from input `peerPubKey`
      *            source_pub_key:    bstr .cbor PlainPubKey, ; from the output of `create`
@@ -143,7 +145,8 @@
      *            sink_cert_chain:   bstr .cbor ExplicitKeyDiceCertChain, ; from input `peerId`
      *            source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from own identity
      *        ]
-     *     3. Extract a cryptographic secret S from Z, using the salt from #2 above.
+     *     3. Extract a cryptographic secret S from Z, using the SHA256 digest of the salt_input
+     *        as the salt.
      *     4. Derive two symmetric encryption keys of 256 bits with:
      *        i. b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK" as context for the key used to encrypt outgoing
      *           messages
@@ -164,25 +167,26 @@
      *        part of the party's identity.
      *
      * @param peerPubKey - the public key of the key pair created by the peer (P2) for key exchange
+     *                     in `init`
      *
      * @param peerId - the persistent identity of the peer
      *
      * @param peerSignature - the signature created by the peer over the session id computed by the
-     *                        peer
+     *                        peer in `init`
      *
-     * @param peerNonce - nonce created by the peer
+     * @param peerNonce - nonce created by the peer in `init`
      *
      * @param peerVersion - an integer representing the protocol version (i.e. AIDL version)
      *                      negotiated with the peer
      *
-     * @param ownKey - the key created by P1 (source) in `create()` for key exchange
+     * @param ownKey - the key created by P1 (source) in `create` for key exchange
      *
-     * @return SessionInfo including the two shared key arcs from step #9, session id and the
-     * signature over the session id.
+     * @return SessionInfo including the two shared key arcs from step #9, session id from step #7
+     * and the signature over the session id from step #10.
      *
-     * Note: The two shared key arcs in the return type: `SessionInfo` serves two purposes:
+     * Note: The two shared key arcs in the return type: `SessionInfo` serve two purposes:
      * i. A mapping to correlate the key exchange protocol taken place with a particular peer and
-     *    subsequent AuthGraph protocols execued with the same peer.
+     *    subsequent AuthGraph protocols executed with the same peer.
      * ii.A way to minimize the in-memory storage for shared keys.
      * However, P1 should maintain some in-memory record to be able to verify that the shared key
      * arcs sent to any subsequent AuthGraph protocol methods are valid shared keys agreed with the
@@ -196,21 +200,33 @@
      * This method is invoked on P2 (sink).
      * Perform the following steps:
      *   0. If input `sharedKeys` is invalid (i.e. they cannot be decrypted with P2's per-boot key
-     *      or they are not in P2's in-memory records as valid shared keys agreed with the party
-     *      identified by `peerId`), return error: INVALID_SHARED_KEY_ARCS.
+     *      or they are not in P2's in-memory records for unfinished instances of a key exchange
+     *      protocol carried out with the party identified by the identity included in the
+     *      `source_id` protected header of the shared key arcs),
+     *      return error: INVALID_SHARED_KEY_ARCS.
      *   1. Verify that both shared key arcs have the same session id and peer identity.
-     *   2. Verify the peer's signature over the session id attached to the shared key arcs'
-     *      headers. If successful, proceed, otherwise, return error: INVALID_SIGNATURE.
-     *   3. Mark authentication_complete = true in the shared key arcs' headers
+     *   2. Verify the `peerSignature` over the session id included in the `session_id` protected
+     *      header of the shared key arcs.
+     *      If successful, proceed, otherwise, return error: INVALID_SIGNATURE.
+     *   3. Mark authentication_complete = true in the shared key arcs' headers.
      *
      * @param peerSignature - the signature created by the peer over the session id computed by the
-     *                        peer
+     *                        peer in `finish`
      *
      * @param sharedKeys - two shared key arcs created by P2 in `init`. P2 obtains from the arcs'
      *                     protected headers, the session id and the peer's identity to verify the
      *                     peer's signature over the session id.
      *
      * @return Arc[] - an array of two updated shared key arcs
+     *
+     * Note: The two returned shared key arcs serve two purposes:
+     * i. A mapping to correlate the key exchange protocol taken place with a particular peer and
+     *    subsequent AuthGraph protocols executed with the same peer.
+     * ii.A way to minimize the in-memory storage for shared keys.
+     * However, P2 should maintain some in-memory record to be able to verify that the shared key
+     * arcs sent to any subsequent AuthGraph protocol methods are valid shared keys agreed with the
+     * party identified by the identity included in the `source_id` protected header of the shared
+     * key arcs, to prevent any replay attacks.
      */
     Arc[2] authenticationComplete(in SessionIdSignature peerSignature, in Arc[2] sharedKeys);
 }
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
index ef49a1a..82b8c17 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
@@ -26,8 +26,8 @@
 @RustDerive(Clone=true, Eq=true, PartialEq=true)
 parcelable SessionInfo {
     /**
-     * The arcs that encrypt the two derived symmetric encryption keys (for two-way communication)
-     * from the party's per-boot key.
+     * The arcs that encrypt the two derived symmetric encryption keys (for two-way communication).
+     * The encryption key is the party's per-boot key.
      */
     Arc[2] sharedKeys;
 
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
index c630d91..8179ac2 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
@@ -27,20 +27,22 @@
 @RustDerive(Clone=true, Eq=true, PartialEq=true)
 parcelable SessionInitiationInfo {
     /**
-     * An ephemeral EC key created for the ECDH process.
+     * An ephemeral EC key created for the Elliptic-curve Diffie-Hellman (ECDH) process.
      */
     Key key;
 
     /**
-     * The identity of the party who created the Diffie-Hellman key exchange key.
+     * The identity of the party who creates this `SessionInitiationInfo`.
      */
     Identity identity;
 
     /**
-     * Nonce value specific to this session. The nonce serves three purposes:
+     * Nonce (a cryptographic random number of 16 bytes) specific to this session.
+     * The nonce serves three purposes:
      * 1. freshness of key exchange
      * 2. creating a session id (a publicly known value related to the exchanged keys)
-     * 3. usage as salt into the HKDF-EXTRACT function during key derivation from the shared DH key
+     * 3. usage as salt into the HKDF-EXTRACT function during key derivation from the Diffie-Hellman
+     *    shared secret
      */
     byte[] nonce;
 
diff --git a/security/authgraph/aidl/vts/functional/lib.rs b/security/authgraph/aidl/vts/functional/lib.rs
index 7b9b2b9..da3fa1c 100644
--- a/security/authgraph/aidl/vts/functional/lib.rs
+++ b/security/authgraph/aidl/vts/functional/lib.rs
@@ -24,22 +24,19 @@
     PlainPubKey::PlainPubKey, PubKey::PubKey, SessionIdSignature::SessionIdSignature,
 };
 use authgraph_boringssl as boring;
-use authgraph_core::keyexchange as ke;
-use authgraph_core::{arc, key, traits};
-use authgraph_nonsecure::StdClock;
+use authgraph_core::{error::Error as AgError, keyexchange as ke};
 use coset::CborSerializable;
 
 pub mod sink;
 pub mod source;
 
-/// Return a collection of AuthGraph trait implementations suitable for testing.
-pub fn test_impls() -> traits::TraitImpl {
-    // Note that the local implementation is using a clock with a potentially different epoch than
-    // the implementation under test.
-    boring::trait_impls(
+/// Return an AuthGraphParticipant suitable for testing.
+pub fn test_ag_participant() -> Result<ke::AuthGraphParticipant, AgError> {
+    Ok(ke::AuthGraphParticipant::new(
+        boring::crypto_trait_impls(),
         Box::<boring::test_device::AgDevice>::default(),
-        Some(Box::new(StdClock::default())),
-    )
+        ke::MAX_OPENED_SESSIONS,
+    )?)
 }
 
 fn build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> PubKey {
@@ -56,14 +53,6 @@
     }
 }
 
-fn verification_key_from_identity(impls: &traits::TraitImpl, identity: &[u8]) -> key::EcVerifyKey {
-    let identity = key::Identity::from_slice(identity).expect("invalid identity CBOR");
-    impls
-        .device
-        .process_peer_cert_chain(&identity.cert_chain, &*impls.ecdsa)
-        .expect("failed to extract signing key")
-}
-
 fn vec_to_identity(data: &[u8]) -> Identity {
     Identity {
         identity: data.to_vec(),
@@ -75,26 +64,3 @@
         signature: data.to_vec(),
     }
 }
-
-/// Decrypt a pair of AES-256 keys encrypted with the AuthGraph PBK.
-pub fn decipher_aes_keys(imp: &traits::TraitImpl, arc: &[Vec<u8>; 2]) -> [key::AesKey; 2] {
-    [
-        decipher_aes_key(imp, &arc[0]),
-        decipher_aes_key(imp, &arc[1]),
-    ]
-}
-
-/// Decrypt an AES-256 key encrypted with the AuthGraph PBK.
-pub fn decipher_aes_key(imp: &traits::TraitImpl, arc: &[u8]) -> key::AesKey {
-    let pbk = imp.device.get_per_boot_key().expect("no PBK available");
-    let arc::ArcContent {
-        payload,
-        protected_headers: _,
-        unprotected_headers: _,
-    } = arc::decipher_arc(&pbk, arc, &*imp.aes_gcm).expect("failed to decrypt arc");
-    assert_eq!(payload.0.len(), 32);
-    let mut key = key::AesKey([0; 32]);
-    key.0.copy_from_slice(&payload.0);
-    assert_ne!(key.0, [0; 32], "agreed AES-256 key should be non-zero");
-    key
-}
diff --git a/security/authgraph/aidl/vts/functional/role_test.rs b/security/authgraph/aidl/vts/functional/role_test.rs
index e95361a..71a2fae 100644
--- a/security/authgraph/aidl/vts/functional/role_test.rs
+++ b/security/authgraph/aidl/vts/functional/role_test.rs
@@ -48,31 +48,31 @@
 
 #[test]
 fn test_nonsecure_source_mainline() {
-    let mut impls = vts::test_impls();
-    vts::source::test_mainline(&mut impls, require_nonsecure!());
+    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+    vts::source::test_mainline(&mut sink, require_nonsecure!());
 }
 #[test]
 fn test_nonsecure_source_corrupt_sig() {
-    let mut impls = vts::test_impls();
-    vts::source::test_corrupt_sig(&mut impls, require_nonsecure!());
+    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+    vts::source::test_corrupt_sig(&mut sink, require_nonsecure!());
 }
 #[test]
 fn test_nonsecure_source_corrupt_keys() {
-    let mut impls = vts::test_impls();
-    vts::source::test_corrupt_key(&mut impls, require_nonsecure!());
+    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+    vts::source::test_corrupt_key(&mut sink, require_nonsecure!());
 }
 #[test]
 fn test_nonsecure_sink_mainline() {
-    let mut impls = vts::test_impls();
-    vts::sink::test_mainline(&mut impls, require_nonsecure!());
+    let mut source = vts::test_ag_participant().expect("failed to create a local source");
+    vts::sink::test_mainline(&mut source, require_nonsecure!());
 }
 #[test]
 fn test_nonsecure_sink_corrupt_sig() {
-    let mut impls = vts::test_impls();
-    vts::sink::test_corrupt_sig(&mut impls, require_nonsecure!());
+    let mut source = vts::test_ag_participant().expect("failed to create a local source");
+    vts::sink::test_corrupt_sig(&mut source, require_nonsecure!());
 }
 #[test]
 fn test_nonsecure_sink_corrupt_keys() {
-    let mut impls = vts::test_impls();
-    vts::sink::test_corrupt_keys(&mut impls, require_nonsecure!());
+    let mut source = vts::test_ag_participant().expect("failed to create a local source");
+    vts::sink::test_corrupt_keys(&mut source, require_nonsecure!());
 }
diff --git a/security/authgraph/aidl/vts/functional/sink.rs b/security/authgraph/aidl/vts/functional/sink.rs
index 5c81593..bb357b8 100644
--- a/security/authgraph/aidl/vts/functional/sink.rs
+++ b/security/authgraph/aidl/vts/functional/sink.rs
@@ -16,23 +16,28 @@
 
 //! VTS tests for sinks
 use super::*;
-use authgraph_core::traits;
+use authgraph_core::{key, keyexchange as ke};
 
 /// Run AuthGraph tests against the provided sink, using a local test source implementation.
-pub fn test(impls: &mut traits::TraitImpl, sink: binder::Strong<dyn IAuthGraphKeyExchange>) {
-    test_mainline(impls, sink.clone());
-    test_corrupt_sig(impls, sink.clone());
-    test_corrupt_keys(impls, sink);
+pub fn test(
+    local_source: &mut ke::AuthGraphParticipant,
+    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    test_mainline(local_source, sink.clone());
+    test_corrupt_sig(local_source, sink.clone());
+    test_corrupt_keys(local_source, sink);
 }
 
 /// Perform mainline AuthGraph key exchange with the provided sink and local implementation.
 /// Return the agreed AES keys in plaintext.
 pub fn test_mainline(
-    impls: &mut traits::TraitImpl,
+    local_source: &mut ke::AuthGraphParticipant,
     sink: binder::Strong<dyn IAuthGraphKeyExchange>,
 ) -> [key::AesKey; 2] {
     // Step 1: create an ephemeral ECDH key at the (local) source.
-    let source_init_info = ke::create(impls).expect("failed to create() with local impl");
+    let source_init_info = local_source
+        .create()
+        .expect("failed to create() with local impl");
 
     // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
     let init_result = sink
@@ -50,40 +55,43 @@
     assert!(!sink_info.sessionId.is_empty());
 
     // The AuthGraph core library will verify the session ID signature, but do it here too.
-    let sink_verification_key =
-        verification_key_from_identity(&impls, &sink_init_info.identity.identity);
-    ke::verify_signature_on_session_id(
-        &sink_verification_key,
-        &sink_info.sessionId,
-        &sink_info.signature.signature,
-        &*impls.ecdsa,
-    )
-    .expect("failed verification of signed session ID");
+    let sink_verification_key = local_source
+        .peer_verification_key_from_identity(&sink_init_info.identity.identity)
+        .expect("failed to get peer verification from identity");
+    local_source
+        .verify_signature_on_session_id(
+            &sink_verification_key,
+            &sink_info.sessionId,
+            &sink_info.signature.signature,
+        )
+        .expect("failed verification of signed session ID");
 
     // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
     // can calculate the same pair of symmetric keys.
-    let source_info = ke::finish(
-        impls,
-        &sink_pub_key.plainPubKey,
-        &sink_init_info.identity.identity,
-        &sink_info.signature.signature,
-        &sink_init_info.nonce,
-        sink_init_info.version,
-        source_init_info.ke_key,
-    )
-    .expect("failed to finish() with local impl");
+    let source_info = local_source
+        .finish(
+            &sink_pub_key.plainPubKey,
+            &sink_init_info.identity.identity,
+            &sink_info.signature.signature,
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            source_init_info.ke_key,
+        )
+        .expect("failed to finish() with local impl");
     assert!(!source_info.session_id.is_empty());
 
     // The AuthGraph core library will verify the session ID signature, but do it here too.
-    let source_verification_key =
-        verification_key_from_identity(&impls, &source_init_info.identity);
-    ke::verify_signature_on_session_id(
-        &source_verification_key,
-        &source_info.session_id,
-        &source_info.session_id_signature,
-        &*impls.ecdsa,
-    )
-    .expect("failed verification of signed session ID");
+    let source_verification_key = key::Identity::from_slice(&source_init_info.identity)
+        .expect("invalid identity CBOR")
+        .cert_chain
+        .root_key;
+    local_source
+        .verify_signature_on_session_id(
+            &source_verification_key,
+            &source_info.session_id,
+            &source_info.session_id_signature,
+        )
+        .expect("failed verification of signed session ID");
 
     // Both ends should agree on the session ID.
     assert_eq!(source_info.session_id, sink_info.sessionId);
@@ -96,19 +104,28 @@
             &sink_info.sharedKeys,
         )
         .expect("failed to authenticationComplete() with remote sink");
-
     // Decrypt and return the session keys.
-    decipher_aes_keys(&impls, &source_info.shared_keys)
+    let decrypted_shared_keys = local_source
+        .decipher_shared_keys_from_arcs(&source_info.shared_keys)
+        .expect("failed to decrypt shared key arcs")
+        .try_into();
+    let decrypted_shared_keys_array = match decrypted_shared_keys {
+        Ok(array) => array,
+        Err(_) => panic!("wrong number of decrypted shared key arcs"),
+    };
+    decrypted_shared_keys_array
 }
 
 /// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
 /// session ID signature.
 pub fn test_corrupt_sig(
-    impls: &mut traits::TraitImpl,
+    local_source: &mut ke::AuthGraphParticipant,
     sink: binder::Strong<dyn IAuthGraphKeyExchange>,
 ) {
     // Step 1: create an ephemeral ECDH key at the (local) source.
-    let source_init_info = ke::create(impls).expect("failed to create() with local impl");
+    let source_init_info = local_source
+        .create()
+        .expect("failed to create() with local impl");
 
     // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
     let init_result = sink
@@ -127,16 +144,16 @@
 
     // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
     // can calculate the same pair of symmetric keys.
-    let source_info = ke::finish(
-        impls,
-        &sink_pub_key.plainPubKey,
-        &sink_init_info.identity.identity,
-        &sink_info.signature.signature,
-        &sink_init_info.nonce,
-        sink_init_info.version,
-        source_init_info.ke_key,
-    )
-    .expect("failed to finish() with local impl");
+    let source_info = local_source
+        .finish(
+            &sink_pub_key.plainPubKey,
+            &sink_init_info.identity.identity,
+            &sink_info.signature.signature,
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            source_init_info.ke_key,
+        )
+        .expect("failed to finish() with local impl");
     assert!(!source_info.session_id.is_empty());
 
     // Build a corrupted version of the (local) source's session ID signature.
@@ -158,11 +175,13 @@
 /// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
 /// Arc for the sink's key.
 pub fn test_corrupt_keys(
-    impls: &mut traits::TraitImpl,
+    local_source: &mut ke::AuthGraphParticipant,
     sink: binder::Strong<dyn IAuthGraphKeyExchange>,
 ) {
     // Step 1: create an ephemeral ECDH key at the (local) source.
-    let source_init_info = ke::create(impls).expect("failed to create() with local impl");
+    let source_init_info = local_source
+        .create()
+        .expect("failed to create() with local impl");
 
     // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
     let init_result = sink
@@ -181,16 +200,16 @@
 
     // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
     // can calculate the same pair of symmetric keys.
-    let source_info = ke::finish(
-        impls,
-        &sink_pub_key.plainPubKey,
-        &sink_init_info.identity.identity,
-        &sink_info.signature.signature,
-        &sink_init_info.nonce,
-        sink_init_info.version,
-        source_init_info.ke_key,
-    )
-    .expect("failed to finish() with local impl");
+    let source_info = local_source
+        .finish(
+            &sink_pub_key.plainPubKey,
+            &sink_init_info.identity.identity,
+            &sink_info.signature.signature,
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            source_init_info.ke_key,
+        )
+        .expect("failed to finish() with local impl");
     assert!(!source_info.session_id.is_empty());
 
     // Deliberately corrupt the sink's shared key Arcs before returning them
diff --git a/security/authgraph/aidl/vts/functional/source.rs b/security/authgraph/aidl/vts/functional/source.rs
index 9aaaaee..4178a99 100644
--- a/security/authgraph/aidl/vts/functional/source.rs
+++ b/security/authgraph/aidl/vts/functional/source.rs
@@ -16,19 +16,22 @@
 
 //! VTS tests for sources
 use super::*;
-use authgraph_core::traits;
+use authgraph_core::{key, keyexchange as ke};
 
 /// Run AuthGraph tests against the provided source, using a local test sink implementation.
-pub fn test(impls: &mut traits::TraitImpl, source: binder::Strong<dyn IAuthGraphKeyExchange>) {
-    test_mainline(impls, source.clone());
-    test_corrupt_sig(impls, source.clone());
-    test_corrupt_key(impls, source);
+pub fn test(
+    local_sink: &mut ke::AuthGraphParticipant,
+    source: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    test_mainline(local_sink, source.clone());
+    test_corrupt_sig(local_sink, source.clone());
+    test_corrupt_key(local_sink, source);
 }
 
 /// Perform mainline AuthGraph key exchange with the provided source.
 /// Return the agreed AES keys in plaintext.
 pub fn test_mainline(
-    impls: &mut traits::TraitImpl,
+    local_sink: &mut ke::AuthGraphParticipant,
     source: binder::Strong<dyn IAuthGraphKeyExchange>,
 ) -> [key::AesKey; 2] {
     // Step 1: create an ephemeral ECDH key at the (remote) source.
@@ -40,14 +43,14 @@
     let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
 
     // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
-    let init_result = ke::init(
-        impls,
-        &source_pub_key.plainPubKey,
-        &source_init_info.identity.identity,
-        &source_init_info.nonce,
-        source_init_info.version,
-    )
-    .expect("failed to init() with local impl");
+    let init_result = local_sink
+        .init(
+            &source_pub_key.plainPubKey,
+            &source_init_info.identity.identity,
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with local impl");
     let sink_init_info = init_result.session_init_info;
     let sink_pub_key = sink_init_info
         .ke_key
@@ -58,14 +61,17 @@
     assert!(!sink_info.session_id.is_empty());
 
     // The AuthGraph core library will verify the session ID signature, but do it here too.
-    let sink_verification_key = verification_key_from_identity(&impls, &sink_init_info.identity);
-    ke::verify_signature_on_session_id(
-        &sink_verification_key,
-        &sink_info.session_id,
-        &sink_info.session_id_signature,
-        &*impls.ecdsa,
-    )
-    .expect("failed verification of signed session ID");
+    let sink_verification_key = key::Identity::from_slice(&sink_init_info.identity)
+        .expect("invalid identity CBOR")
+        .cert_chain
+        .root_key;
+    local_sink
+        .verify_signature_on_session_id(
+            &sink_verification_key,
+            &sink_info.session_id,
+            &sink_info.session_id_signature,
+        )
+        .expect("failed verification of signed session ID");
 
     // Step 3: pass the sink's ECDH public key and other session info to the (remote) source, so it
     // can calculate the same pair of symmetric keys.
@@ -86,36 +92,41 @@
     assert!(!source_info.sessionId.is_empty());
 
     // The AuthGraph core library will verify the session ID signature, but do it here too.
-    let source_verification_key =
-        verification_key_from_identity(&impls, &source_init_info.identity.identity);
-    ke::verify_signature_on_session_id(
-        &source_verification_key,
-        &source_info.sessionId,
-        &source_info.signature.signature,
-        &*impls.ecdsa,
-    )
-    .expect("failed verification of signed session ID");
+    let source_verification_key = local_sink
+        .peer_verification_key_from_identity(&source_init_info.identity.identity)
+        .expect("failed to get peer verification from identity");
+    local_sink
+        .verify_signature_on_session_id(
+            &source_verification_key,
+            &source_info.sessionId,
+            &source_info.signature.signature,
+        )
+        .expect("failed verification of signed session ID");
 
     // Both ends should agree on the session ID.
     assert_eq!(source_info.sessionId, sink_info.session_id);
 
     // Step 4: pass the (remote) source's session ID signature back to the sink, so it can check it
     // and update the symmetric keys so they're marked as authentication complete.
-    let sink_arcs = ke::authentication_complete(
-        impls,
-        &source_info.signature.signature,
-        sink_info.shared_keys,
-    )
-    .expect("failed to authenticationComplete() with local sink");
-
+    let sink_arcs = local_sink
+        .authentication_complete(&source_info.signature.signature, sink_info.shared_keys)
+        .expect("failed to authenticationComplete() with local sink");
     // Decrypt and return the session keys.
-    decipher_aes_keys(&impls, &sink_arcs)
+    let decrypted_shared_keys = local_sink
+        .decipher_shared_keys_from_arcs(&sink_arcs)
+        .expect("failed to decrypt shared key arcs")
+        .try_into();
+    let decrypted_shared_keys_array = match decrypted_shared_keys {
+        Ok(array) => array,
+        Err(_) => panic!("wrong number of decrypted shared key arcs"),
+    };
+    decrypted_shared_keys_array
 }
 
 /// Perform mainline AuthGraph key exchange with the provided source, but provide an invalid session
 /// ID signature.
 pub fn test_corrupt_sig(
-    impls: &mut traits::TraitImpl,
+    local_sink: &mut ke::AuthGraphParticipant,
     source: binder::Strong<dyn IAuthGraphKeyExchange>,
 ) {
     // Step 1: create an ephemeral ECDH key at the (remote) source.
@@ -127,14 +138,14 @@
     let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
 
     // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
-    let init_result = ke::init(
-        impls,
-        &source_pub_key.plainPubKey,
-        &source_init_info.identity.identity,
-        &source_init_info.nonce,
-        source_init_info.version,
-    )
-    .expect("failed to init() with local impl");
+    let init_result = local_sink
+        .init(
+            &source_pub_key.plainPubKey,
+            &source_init_info.identity.identity,
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with local impl");
     let sink_init_info = init_result.session_init_info;
     let sink_pub_key = sink_init_info
         .ke_key
@@ -172,7 +183,7 @@
 /// Perform mainline AuthGraph key exchange with the provided source, but give it back
 /// a corrupted key.
 pub fn test_corrupt_key(
-    impls: &mut traits::TraitImpl,
+    local_sink: &mut ke::AuthGraphParticipant,
     source: binder::Strong<dyn IAuthGraphKeyExchange>,
 ) {
     // Step 1: create an ephemeral ECDH key at the (remote) source.
@@ -184,14 +195,14 @@
     let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
 
     // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
-    let init_result = ke::init(
-        impls,
-        &source_pub_key.plainPubKey,
-        &source_init_info.identity.identity,
-        &source_init_info.nonce,
-        source_init_info.version,
-    )
-    .expect("failed to init() with local impl");
+    let init_result = local_sink
+        .init(
+            &source_pub_key.plainPubKey,
+            &source_init_info.identity.identity,
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with local impl");
     let sink_init_info = init_result.session_init_info;
     let sink_pub_key = sink_init_info
         .ke_key
@@ -202,14 +213,17 @@
     assert!(!sink_info.session_id.is_empty());
 
     // The AuthGraph core library will verify the session ID signature, but do it here too.
-    let sink_verification_key = verification_key_from_identity(&impls, &sink_init_info.identity);
-    ke::verify_signature_on_session_id(
-        &sink_verification_key,
-        &sink_info.session_id,
-        &sink_info.session_id_signature,
-        &*impls.ecdsa,
-    )
-    .expect("failed verification of signed session ID");
+    let sink_verification_key = key::Identity::from_slice(&sink_init_info.identity)
+        .expect("invalid identity CBOR")
+        .cert_chain
+        .root_key;
+    local_sink
+        .verify_signature_on_session_id(
+            &sink_verification_key,
+            &sink_info.session_id,
+            &sink_info.session_id_signature,
+        )
+        .expect("failed verification of signed session ID");
 
     // Deliberately corrupt the source's encrypted key.
     let mut corrupt_key = source_init_info.key.clone();
diff --git a/security/authgraph/default/src/fuzzer.rs b/security/authgraph/default/src/fuzzer.rs
index 6a9cfdd..d401777 100644
--- a/security/authgraph/default/src/fuzzer.rs
+++ b/security/authgraph/default/src/fuzzer.rs
@@ -25,7 +25,7 @@
 use std::sync::{Arc, Mutex};
 
 fuzz_target!(|data: &[u8]| {
-    let local_ta = LocalTa::new();
+    let local_ta = LocalTa::new().expect("Failed to create an AuthGraph local TA.");
     let service = AuthGraphService::new_as_binder(Arc::new(Mutex::new(local_ta)));
     fuzz_service(&mut service.as_binder(), data);
 });
diff --git a/security/authgraph/default/src/lib.rs b/security/authgraph/default/src/lib.rs
index 4cd0cb7..43d037c 100644
--- a/security/authgraph/default/src/lib.rs
+++ b/security/authgraph/default/src/lib.rs
@@ -18,7 +18,9 @@
 
 use authgraph_boringssl as boring;
 use authgraph_core::{
+    error,
     key::MillisecondsSinceEpoch,
+    keyexchange,
     ta::{AuthGraphTa, Role},
     traits,
 };
@@ -57,16 +59,17 @@
 
 impl LocalTa {
     /// Create a new instance.
-    pub fn new() -> Self {
-        Self {
+    pub fn new() -> Result<Self, error::Error> {
+        Ok(Self {
             ta: Arc::new(Mutex::new(AuthGraphTa::new(
-                boring::trait_impls(
+                keyexchange::AuthGraphParticipant::new(
+                    boring::crypto_trait_impls(),
                     Box::<boring::test_device::AgDevice>::default(),
-                    Some(Box::new(StdClock::default())),
-                ),
+                    keyexchange::MAX_OPENED_SESSIONS,
+                )?,
                 Role::Both,
             ))),
-        }
+        })
     }
 }
 
diff --git a/security/authgraph/default/src/main.rs b/security/authgraph/default/src/main.rs
index 873eb4e..81f2dd6 100644
--- a/security/authgraph/default/src/main.rs
+++ b/security/authgraph/default/src/main.rs
@@ -65,7 +65,8 @@
     binder::ProcessState::start_thread_pool();
 
     // Register the service
-    let local_ta = LocalTa::new();
+    let local_ta =
+        LocalTa::new().map_err(|e| format!("Failed to create the TA because: {e:?}"))?;
     let service = service::AuthGraphService::new_as_binder(Arc::new(Mutex::new(local_ta)));
     let service_name = format!("{}/{}", SERVICE_NAME, SERVICE_INSTANCE);
     binder::add_service(&service_name, service.as_binder()).map_err(|e| {
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index aa7bf28..be29f59 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -974,8 +974,8 @@
      * time in milliseconds.  This value is used when generating attestation or self signed
      * certificates.  ErrorCode::MISSING_NOT_BEFORE must be returned if this tag is not provided if
      * this tag is not provided to generateKey or importKey.  For importWrappedKey, there is no way
-     * to specify the value of this tag for the wrapped key, so a value of 0 must be used for
-     * certificate generation.
+     * to specify the value of this tag for a wrapped asymmetric key, so a value of 0 is suggested
+     * for certificate generation.
      */
     CERTIFICATE_NOT_BEFORE = TagType.DATE | 1008,
 
@@ -983,8 +983,9 @@
      * Tag::CERTIFICATE_NOT_AFTER the end of the validity of the certificate in UNIX epoch time in
      * milliseconds.  This value is used when generating attestation or self signed certificates.
      * ErrorCode::MISSING_NOT_AFTER must be returned if this tag is not provided to generateKey or
-     * importKey.  For importWrappedKey, there is no way to specify the value of this tag for the
-     * wrapped key, so a value of 253402300799000 is used for certificate generation.
+     * importKey.  For importWrappedKey, there is no way to specify the value of this tag for a
+     * wrapped asymmetric key, so a value of 253402300799000 is suggested for certificate
+     * generation.
      */
     CERTIFICATE_NOT_AFTER = TagType.DATE | 1009,
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index a8f17dd..d4adab5 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -4123,13 +4123,13 @@
  * when the EC_CURVE is not explicitly specified.
  */
 TEST_P(ImportKeyTest, EcdsaSuccessCurveNotSpecified) {
-    if (AidlVersion() < 4) {
+    if (get_vsr_api_level() < __ANDROID_API_V__) {
         /*
-         * The KeyMint spec before V4 was not clear as to whether EC_CURVE was optional on import of
-         * EC keys. However, this was not checked at the time so we can only be strict about
-         * checking this for implementations of KeyMint version 4 and above.
+         * The KeyMint spec was previously not clear as to whether EC_CURVE was optional on import
+         * of EC keys. However, this was not checked at the time so we can only be strict about
+         * checking this for implementations at VSR-V or later.
          */
-        GTEST_SKIP() << "Skipping EC_CURVE on import only strict since KeyMint v4";
+        GTEST_SKIP() << "Skipping EC_CURVE on import only strict >= VSR-V";
     }
 
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()