Merge "Add vts test for TWT" into main
diff --git a/audio/aidl/default/spatializer/SpatializerSw.cpp b/audio/aidl/default/spatializer/SpatializerSw.cpp
index ef86ddb..ab4a53e 100644
--- a/audio/aidl/default/spatializer/SpatializerSw.cpp
+++ b/audio/aidl/default/spatializer/SpatializerSw.cpp
@@ -65,8 +65,6 @@
 const std::string SpatializerSw::kEffectName = "SpatializerSw";
 
 const std::vector<Range::SpatializerRange> SpatializerSw::kRanges = {
-        MAKE_RANGE(Spatializer, supportedChannelLayout, std::vector<AudioChannelLayout>{},
-                   std::vector<AudioChannelLayout>{}),
         MAKE_RANGE(Spatializer, spatializationLevel, Spatialization::Level::NONE,
                    Spatialization::Level::BED_PLUS_OBJECTS),
         MAKE_RANGE(Spatializer, spatializationMode, Spatialization::Mode::BINAURAL,
@@ -175,11 +173,19 @@
     if (mParamsMap.find(tag) != mParamsMap.end()) {
         return mParamsMap.at(tag);
     }
+    if (tag == Spatializer::supportedChannelLayout) {
+        return Spatializer::make<Spatializer::supportedChannelLayout>(
+                {AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                        AudioChannelLayout::LAYOUT_5POINT1)});
+    }
     return std::nullopt;
 }
 
 template <typename TAG>
 ndk::ScopedAStatus SpatializerSwContext::setParam(TAG tag, Spatializer spatializer) {
+    RETURN_IF(tag == Spatializer::supportedChannelLayout, EX_ILLEGAL_ARGUMENT,
+              "supportedChannelLayoutGetOnly");
+
     mParamsMap[tag] = spatializer;
     return ndk::ScopedAStatus::ok();
 }
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 888b1e1..ccc0f3f 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -37,6 +37,7 @@
 
 #include <chrono>
 #include <mutex>
+#include <thread>
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
@@ -63,6 +64,7 @@
 using ::android::frameworks::automotive::vhal::IHalPropValue;
 using ::android::frameworks::automotive::vhal::ISubscriptionCallback;
 using ::android::frameworks::automotive::vhal::IVhalClient;
+using ::android::frameworks::automotive::vhal::SubscribeOptionsBuilder;
 using ::android::frameworks::automotive::vhal::VhalClientResult;
 using ::android::hardware::getAllHalInstanceNames;
 using ::android::hardware::Sanitize;
@@ -83,8 +85,8 @@
 class VtsVehicleCallback final : public ISubscriptionCallback {
   private:
     std::mutex mLock;
-    std::unordered_map<int32_t, size_t> mEventsCount GUARDED_BY(mLock);
-    std::unordered_map<int32_t, std::vector<int64_t>> mEventTimestamps GUARDED_BY(mLock);
+    std::unordered_map<int32_t, std::vector<std::unique_ptr<IHalPropValue>>> mEvents
+            GUARDED_BY(mLock);
     std::condition_variable mEventCond;
 
   public:
@@ -93,8 +95,7 @@
             std::lock_guard<std::mutex> lockGuard(mLock);
             for (auto& value : values) {
                 int32_t propId = value->getPropId();
-                mEventsCount[propId] += 1;
-                mEventTimestamps[propId].push_back(value->getTimestamp());
+                mEvents[propId].push_back(std::move(value->clone()));
             }
         }
         mEventCond.notify_one();
@@ -110,20 +111,37 @@
         std::unique_lock<std::mutex> uniqueLock(mLock);
         return mEventCond.wait_for(uniqueLock, timeout, [this, propId, expectedEvents] {
             ScopedLockAssertion lockAssertion(mLock);
-            return mEventsCount[propId] >= expectedEvents;
+            return mEvents[propId].size() >= expectedEvents;
         });
     }
 
-    std::vector<int64_t> getEventTimestamps(int32_t propId) {
-        {
-            std::lock_guard<std::mutex> lockGuard(mLock);
-            return mEventTimestamps[propId];
+    std::vector<std::unique_ptr<IHalPropValue>> getEvents(int32_t propId) {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        std::vector<std::unique_ptr<IHalPropValue>> events;
+        if (mEvents.find(propId) == mEvents.end()) {
+            return events;
         }
+        for (const auto& eventPtr : mEvents[propId]) {
+            events.push_back(std::move(eventPtr->clone()));
+        }
+        return events;
+    }
+
+    std::vector<int64_t> getEventTimestamps(int32_t propId) {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        std::vector<int64_t> timestamps;
+        if (mEvents.find(propId) == mEvents.end()) {
+            return timestamps;
+        }
+        for (const auto& valuePtr : mEvents[propId]) {
+            timestamps.push_back(valuePtr->getTimestamp());
+        }
+        return timestamps;
     }
 
     void reset() {
         std::lock_guard<std::mutex> lockGuard(mLock);
-        mEventsCount.clear();
+        mEvents.clear();
     }
 };
 
@@ -545,6 +563,93 @@
             << "Expect not to get events after unsubscription";
 }
 
+bool isVariableUpdateRateSupported(const std::unique_ptr<IHalPropConfig>& config, int32_t areaId) {
+    for (const auto& areaConfigPtr : config->getAreaConfigs()) {
+        if (areaConfigPtr->getAreaId() == areaId &&
+            areaConfigPtr->isVariableUpdateRateSupported()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+// Test subscribe with variable update rate enabled if supported.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, subscribe_enableVurIfSupported) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::subscribe_enableVurIfSupported");
+
+    int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+    if (!checkIsSupported(propId)) {
+        GTEST_SKIP() << "Property: " << propId << " is not supported, skip the test";
+    }
+    if (!mVhalClient->isAidlVhal()) {
+        GTEST_SKIP() << "Variable update rate is only supported by AIDL VHAL";
+    }
+
+    auto propConfigsResult = mVhalClient->getPropConfigs({propId});
+
+    ASSERT_TRUE(propConfigsResult.ok()) << "Failed to get property config for PERF_VEHICLE_SPEED: "
+                                        << "error: " << propConfigsResult.error().message();
+    ASSERT_EQ(propConfigsResult.value().size(), 1u)
+            << "Expect to return 1 config for PERF_VEHICLE_SPEED";
+    auto& propConfig = propConfigsResult.value()[0];
+    float maxSampleRate = propConfig->getMaxSampleRate();
+    if (maxSampleRate < 1) {
+        GTEST_SKIP() << "Sample rate for vehicle speed < 1 times/sec, skip test since it would "
+                        "take too long";
+    }
+    // PERF_VEHICLE_SPEED is a global property, so areaId is 0.
+    if (!isVariableUpdateRateSupported(propConfig, /* areaId= */ 0)) {
+        GTEST_SKIP() << "Variable update rate is not supported for PERF_VEHICLE_SPEED, "
+                     << "skip testing";
+    }
+
+    auto client = mVhalClient->getSubscriptionClient(mCallback);
+    ASSERT_NE(client, nullptr) << "Failed to get subscription client";
+    SubscribeOptionsBuilder builder(propId);
+    // By default variable update rate is true.
+    builder.setSampleRate(maxSampleRate);
+    auto option = builder.build();
+
+    auto result = client->subscribe({option});
+
+    ASSERT_TRUE(result.ok()) << StringPrintf("Failed to subscribe to property: %" PRId32
+                                             ", error: %s",
+                                             propId, result.error().message().c_str());
+
+    ASSERT_TRUE(mCallback->waitForExpectedEvents(propId, 1, std::chrono::seconds(2)))
+            << "Must get at least 1 events within 2 seconds after subscription for rate: "
+            << maxSampleRate;
+
+    // Sleep for 1 seconds to wait for more possible events to arrive.
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    client->unsubscribe({propId});
+
+    auto events = mCallback->getEvents(propId);
+    if (events.size() == 1) {
+        // We only received one event, the value is not changing so nothing to check here.
+        return;
+    }
+
+    // Sort the values by the timestamp.
+    std::map<int64_t, float> valuesByTimestamp;
+    for (size_t i = 0; i < events.size(); i++) {
+        valuesByTimestamp[events[i]->getTimestamp()] = events[i]->getFloatValues()[0];
+    }
+
+    size_t i = 0;
+    float previousValue;
+    for (const auto& [_, value] : valuesByTimestamp) {
+        if (i == 0) {
+            previousValue = value;
+        } else {
+            ASSERT_FALSE(value != previousValue) << "received duplicate value: " << value
+                                                 << " when variable update rate is true";
+            previousValue = value;
+        }
+    }
+}
+
 // Test subscribe() with an invalid property.
 TEST_P(VtsHalAutomotiveVehicleTargetTest, subscribeInvalidProp) {
     ALOGD("VtsHalAutomotiveVehicleTargetTest::subscribeInvalidProp");
diff --git a/graphics/composer/aidl/vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp
index c72ec69..283b8ce 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/vts/ReadbackVts.cpp
@@ -67,8 +67,9 @@
         case ColorMode::DISPLAY_P3:
             return Dataspace::DISPLAY_P3;
         case ColorMode::SRGB:
+            return Dataspace::SRGB;
         default:
-            return common::Dataspace::UNKNOWN;
+            return Dataspace::UNKNOWN;
     }
 }
 
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 3f82925..d4ce3ba 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -522,6 +522,83 @@
     }
 }
 
+TEST_P(GraphicsCompositionTest, MixedColorSpaces) {
+    ASSERT_TRUE(
+            mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kClientTargetSlotCount)
+                    .isOk());
+    const auto& [status, properties] = mComposerClient->getOverlaySupport();
+    if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
+        status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
+        GTEST_SUCCEED() << "getOverlaySupport is not supported";
+        return;
+    }
+
+    if (properties.supportMixedColorSpaces == false) {
+        GTEST_SUCCEED() << "supportMixedColorSpaces is not supported";
+        return;
+    }
+
+    for (ColorMode mode : mTestColorModes) {
+        EXPECT_TRUE(mComposerClient
+                            ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
+        if (!isSupported) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        // sRGB layer
+        auto srgbLayer = std::make_shared<TestBufferLayer>(
+                mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
+                getDisplayHeight() / 2, PixelFormat::RGBA_8888, *mWriter);
+        std::vector<Color> sRgbDeviceColors(srgbLayer->getWidth() * srgbLayer->getHeight());
+        ReadbackHelper::fillColorsArea(sRgbDeviceColors, getDisplayWidth(),
+                                       {0, 0, static_cast<int32_t>(srgbLayer->getWidth()),
+                                        static_cast<int32_t>(srgbLayer->getHeight())},
+                                       GREEN);
+        srgbLayer->setDisplayFrame({0, 0, static_cast<int32_t>(srgbLayer->getWidth()),
+                                    static_cast<int32_t>(srgbLayer->getHeight())});
+        srgbLayer->setZOrder(10);
+        srgbLayer->setDataspace(Dataspace::SRGB);
+        ASSERT_NO_FATAL_FAILURE(srgbLayer->setBuffer(sRgbDeviceColors));
+
+        // display P3 layer
+        auto displayP3Layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
+                getDisplayHeight() / 2, PixelFormat::RGBA_8888, *mWriter);
+        std::vector<Color> displayP3DeviceColors(
+                static_cast<size_t>(displayP3Layer->getWidth() * displayP3Layer->getHeight()));
+        ReadbackHelper::fillColorsArea(displayP3DeviceColors, getDisplayWidth(),
+                                       {0, 0, static_cast<int32_t>(displayP3Layer->getWidth()),
+                                        static_cast<int32_t>(displayP3Layer->getHeight())},
+                                       RED);
+        displayP3Layer->setDisplayFrame(
+                {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()});
+        displayP3Layer->setZOrder(10);
+        displayP3Layer->setDataspace(Dataspace::DISPLAY_P3);
+        ASSERT_NO_FATAL_FAILURE(displayP3Layer->setBuffer(displayP3DeviceColors));
+
+        writeLayers({srgbLayer, displayP3Layer});
+
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
+        execute();
+
+        auto changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
+        ASSERT_TRUE(changedCompositionTypes.empty());
+
+        mWriter->presentDisplay(getPrimaryDisplayId());
+        execute();
+
+        changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
+        ASSERT_TRUE(changedCompositionTypes.empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+    }
+}
+
 TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) {
     ASSERT_TRUE(
             mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kClientTargetSlotCount)
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index a8f41c3..9575183 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1086,6 +1086,7 @@
     };
     for (auto notBefore : test_vector_not_before_millis) {
         uint64_t notAfter = notBefore + 378691200000 /* 12 years milliseconds*/;
+        SCOPED_TRACE(testing::Message() << "notBefore: " << notBefore << " notAfter: " << notAfter);
         ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .RsaSigningKey(2048, 65537)
@@ -1101,14 +1102,14 @@
 
         const ASN1_TIME* not_before = X509_get0_notBefore(cert.get());
         ASSERT_NE(not_before, nullptr);
-        time_t not_before_time;
-        ASSERT_EQ(ASN1_TIME_to_time_t(not_before, &not_before_time), 1);
+        int64_t not_before_time;
+        ASSERT_EQ(ASN1_TIME_to_posix(not_before, &not_before_time), 1);
         EXPECT_EQ(not_before_time, (notBefore / 1000));
 
         const ASN1_TIME* not_after = X509_get0_notAfter(cert.get());
         ASSERT_NE(not_after, nullptr);
-        time_t not_after_time;
-        ASSERT_EQ(ASN1_TIME_to_time_t(not_after, &not_after_time), 1);
+        int64_t not_after_time;
+        ASSERT_EQ(ASN1_TIME_to_posix(not_after, &not_after_time), 1);
         EXPECT_EQ(not_after_time, (notAfter / 1000));
     }
 }
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
index e6521ae..b9ce5ce 100644
--- a/security/secretkeeper/aidl/vts/Android.bp
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -47,6 +47,7 @@
         "android.hardware.security.secretkeeper-V1-rust",
         "libauthgraph_boringssl",
         "libauthgraph_core",
+        "libauthgraph_wire",
         "libauthgraph_vts_test",
         "libbinder_rs",
         "libciborium",
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_cli.rs b/security/secretkeeper/aidl/vts/secretkeeper_cli.rs
index d02bfe6..377ed37 100644
--- a/security/secretkeeper/aidl/vts/secretkeeper_cli.rs
+++ b/security/secretkeeper/aidl/vts/secretkeeper_cli.rs
@@ -120,7 +120,7 @@
     fn new(instance: &str, dice_artifacts: OwnedDiceArtifactsWithExplicitKey) -> Self {
         let sk: binder::Strong<dyn ISecretkeeper> =
             binder::get_interface(&format!("{SECRETKEEPER_SERVICE}/{instance}")).unwrap();
-        let session = SkSession::new(sk.clone(), &dice_artifacts).unwrap();
+        let session = SkSession::new(sk.clone(), &dice_artifacts, None).unwrap();
         Self { sk, session, dice_artifacts }
     }
 
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
index 72d3e57..7c00aa9 100644
--- a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -19,11 +19,11 @@
 use authgraph_vts_test as ag_vts;
 use authgraph_boringssl as boring;
 use authgraph_core::key;
-use coset::{CborSerializable, CoseEncrypt0};
+use coset::{CborOrdering, CborSerializable, CoseEncrypt0, CoseKey};
 use dice_policy_builder::{CertIndex, ConstraintSpec, ConstraintType, MissingAction, WILDCARD_FULL_ARRAY, policy_for_dice_chain};
 use rdroidtest::{ignore_if, rdroidtest};
 use secretkeeper_client::dice::OwnedDiceArtifactsWithExplicitKey;
-use secretkeeper_client::SkSession;
+use secretkeeper_client::{SkSession, Error as SkClientError};
 use secretkeeper_core::cipher;
 use secretkeeper_comm::data_types::error::SecretkeeperError;
 use secretkeeper_comm::data_types::request::Request;
@@ -38,9 +38,14 @@
     SUBCOMPONENT_DESCRIPTORS, SUBCOMPONENT_SECURITY_VERSION,
     dice_sample::make_explicit_owned_dice
 };
+use std::fs;
+use std::path::Path;
 
 const SECRETKEEPER_SERVICE: &str = "android.hardware.security.secretkeeper.ISecretkeeper";
 const CURRENT_VERSION: u64 = 1;
+const SECRETKEEPER_KEY_HOST_DT: &str =
+    "/proc/device-tree/avf/reference/avf/secretkeeper_public_key";
+
 // Random bytes (of ID_SIZE/SECRET_SIZE) generated for tests.
 const ID_EXAMPLE: Id = Id([
     0xF1, 0xB2, 0xED, 0x3B, 0xD1, 0xBD, 0xF0, 0x7D, 0xE1, 0xF0, 0x01, 0xFC, 0x61, 0x71, 0xD3, 0x42,
@@ -65,6 +70,22 @@
     0x06, 0xAC, 0x36, 0x8B, 0x3C, 0x95, 0x50, 0x16, 0x67, 0x71, 0x65, 0x26, 0xEB, 0xD0, 0xC3, 0x98,
 ]);
 
+// Android expects the public key of Secretkeeper instance to be present in the Linux device tree.
+// This allows clients to (cryptographically) verify that they are indeed talking to the real
+// secretkeeper.
+// Note that this is the identity of the `default` instance (and not `nonsecure`)!
+fn get_secretkeeper_identity() -> Option<CoseKey> {
+    let path = Path::new(SECRETKEEPER_KEY_HOST_DT);
+    if path.exists() {
+        let key = fs::read(path).unwrap();
+        let mut key = CoseKey::from_slice(&key).unwrap();
+        key.canonicalize(CborOrdering::Lexicographic);
+        Some(key)
+    } else {
+        None
+    }
+}
+
 fn get_instances() -> Vec<(String, String)> {
     // Determine which instances are available.
     binder::get_declared_instances(SECRETKEEPER_SERVICE)
@@ -80,6 +101,7 @@
 }
 
 /// Secretkeeper client information.
+#[derive(Debug)]
 struct SkClient {
     sk: binder::Strong<dyn ISecretkeeper>,
     session: SkSession,
@@ -95,19 +117,40 @@
 
 impl SkClient {
     /// Create an `SkClient` using the default `OwnedDiceArtifactsWithExplicitKey` for identity.
-    fn new(instance: &str) -> Self {
+    fn new(instance: &str) -> Result<Self, SkClientError> {
         let default_dice = make_explicit_owned_dice(/*Security version in a node */ 5);
-        Self::with_identity(instance, default_dice)
+        Self::create(instance, default_dice, None)
     }
 
-    /// Create an `SkClient` using the given `OwnedDiceArtifactsWithExplicitKey` for identity.
-    fn with_identity(instance: &str, dice_artifacts: OwnedDiceArtifactsWithExplicitKey) -> Self {
+    /// Create an `SkClient` using given `OwnedDiceArtifactsWithExplicitKey` as client identity.
+    fn with_identity(
+        instance: &str,
+        dice_artifacts: OwnedDiceArtifactsWithExplicitKey,
+    ) -> Result<Self, SkClientError> {
+        Self::create(instance, dice_artifacts, None)
+    }
+
+    /// Create an `SkClient` with default client identity, requiring Secretkeeper's identity to be
+    /// matched against given `expected_sk_key`.
+    fn with_expected_sk_identity(
+        instance: &str,
+        expected_sk_key: coset::CoseKey,
+    ) -> Result<Self, SkClientError> {
+        let default_dice = make_explicit_owned_dice(/*Security version in a node */ 5);
+        Self::create(instance, default_dice, Some(expected_sk_key))
+    }
+
+    fn create(
+        instance: &str,
+        dice_artifacts: OwnedDiceArtifactsWithExplicitKey,
+        expected_sk_key: Option<coset::CoseKey>,
+    ) -> Result<Self, SkClientError> {
         let sk = get_connection(instance);
-        Self {
+        Ok(Self {
             sk: sk.clone(),
-            session: SkSession::new(sk, &dice_artifacts).unwrap(),
+            session: SkSession::new(sk, &dice_artifacts, expected_sk_key)?,
             dice_artifacts,
-        }
+        })
     }
 
     /// This method is wrapper that use `SkSession::secret_management_request` which handles
@@ -347,7 +390,7 @@
 
 #[rdroidtest(get_instances())]
 fn secret_management_get_version(instance: String) {
-    let mut sk_client = SkClient::new(&instance);
+    let mut sk_client = SkClient::new(&instance).unwrap();
 
     let request = GetVersionRequest {};
     let request_packet = request.serialize_to_packet();
@@ -364,7 +407,7 @@
 
 #[rdroidtest(get_instances())]
 fn secret_management_malformed_request(instance: String) {
-    let mut sk_client = SkClient::new(&instance);
+    let mut sk_client = SkClient::new(&instance).unwrap();
 
     let request = GetVersionRequest {};
     let request_packet = request.serialize_to_packet();
@@ -383,7 +426,7 @@
 
 #[rdroidtest(get_instances())]
 fn secret_management_store_get_secret_found(instance: String) {
-    let mut sk_client = SkClient::new(&instance);
+    let mut sk_client = SkClient::new(&instance).unwrap();
 
     sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
 
@@ -393,7 +436,7 @@
 
 #[rdroidtest(get_instances())]
 fn secret_management_store_get_secret_not_found(instance: String) {
-    let mut sk_client = SkClient::new(&instance);
+    let mut sk_client = SkClient::new(&instance).unwrap();
 
     // Store a secret (corresponding to an id).
     sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
@@ -404,7 +447,7 @@
 
 #[rdroidtest(get_instances())]
 fn secretkeeper_store_delete_ids(instance: String) {
-    let mut sk_client = SkClient::new(&instance);
+    let mut sk_client = SkClient::new(&instance).unwrap();
 
     sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
     sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
@@ -420,7 +463,7 @@
 
 #[rdroidtest(get_instances())]
 fn secretkeeper_store_delete_multiple_ids(instance: String) {
-    let mut sk_client = SkClient::new(&instance);
+    let mut sk_client = SkClient::new(&instance).unwrap();
 
     sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
     sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
@@ -431,7 +474,7 @@
 }
 #[rdroidtest(get_instances())]
 fn secretkeeper_store_delete_duplicate_ids(instance: String) {
-    let mut sk_client = SkClient::new(&instance);
+    let mut sk_client = SkClient::new(&instance).unwrap();
 
     sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
     sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
@@ -444,7 +487,7 @@
 
 #[rdroidtest(get_instances())]
 fn secretkeeper_store_delete_nonexistent(instance: String) {
-    let mut sk_client = SkClient::new(&instance);
+    let mut sk_client = SkClient::new(&instance).unwrap();
 
     sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
     sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
@@ -459,7 +502,7 @@
 #[rdroidtest(get_instances())]
 #[ignore_if(|p| p != "nonsecure")]
 fn secretkeeper_store_delete_all(instance: String) {
-    let mut sk_client = SkClient::new(&instance);
+    let mut sk_client = SkClient::new(&instance).unwrap();
 
     sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
     sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
@@ -486,7 +529,7 @@
 fn secret_management_replay_protection_seq_num(instance: String) {
     let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 5);
     let sealing_policy = sealing_policy(dice_chain.explicit_key_dice_chain().unwrap());
-    let sk_client = SkClient::with_identity(&instance, dice_chain);
+    let sk_client = SkClient::with_identity(&instance, dice_chain).unwrap();
     // Construct encoded request packets for the test
     let (req_1, req_2, req_3) = construct_secret_management_requests(sealing_policy);
 
@@ -522,7 +565,7 @@
 fn secret_management_replay_protection_seq_num_per_session(instance: String) {
     let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 5);
     let sealing_policy = sealing_policy(dice_chain.explicit_key_dice_chain().unwrap());
-    let sk_client = SkClient::with_identity(&instance, dice_chain);
+    let sk_client = SkClient::with_identity(&instance, dice_chain).unwrap();
 
     // Construct encoded request packets for the test
     let (req_1, _, _) = construct_secret_management_requests(sealing_policy);
@@ -538,7 +581,7 @@
     assert_eq!(res.response_type().unwrap(), ResponseType::Success);
 
     // Start another session
-    let sk_client_diff = SkClient::new(&instance);
+    let sk_client_diff = SkClient::new(&instance).unwrap();
     // Check first request/response is with seq_0 is successful
     let res = ResponsePacket::from_slice(
         &sk_client_diff.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0).unwrap(),
@@ -553,7 +596,7 @@
 fn secret_management_replay_protection_out_of_seq_req_not_accepted(instance: String) {
     let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 5);
     let sealing_policy = sealing_policy(dice_chain.explicit_key_dice_chain().unwrap());
-    let sk_client = SkClient::with_identity(&instance, dice_chain);
+    let sk_client = SkClient::with_identity(&instance, dice_chain).unwrap();
 
     // Construct encoded request packets for the test
     let (req_1, req_2, _) = construct_secret_management_requests(sealing_policy);
@@ -578,18 +621,19 @@
 #[rdroidtest(get_instances())]
 fn secret_management_policy_gate(instance: String) {
     let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 100);
-    let mut sk_client_original = SkClient::with_identity(&instance, dice_chain);
+    let mut sk_client_original = SkClient::with_identity(&instance, dice_chain).unwrap();
     sk_client_original.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
     assert_eq!(sk_client_original.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
 
     // Start a session with higher security_version & get the stored secret.
     let dice_chain_upgraded = make_explicit_owned_dice(/*Security version in a node */ 101);
-    let mut sk_client_upgraded = SkClient::with_identity(&instance, dice_chain_upgraded);
+    let mut sk_client_upgraded = SkClient::with_identity(&instance, dice_chain_upgraded).unwrap();
     assert_eq!(sk_client_upgraded.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
 
     // Start a session with lower security_version (This should be denied access to the secret).
     let dice_chain_downgraded = make_explicit_owned_dice(/*Security version in a node */ 99);
-    let mut sk_client_downgraded = SkClient::with_identity(&instance, dice_chain_downgraded);
+    let mut sk_client_downgraded =
+        SkClient::with_identity(&instance, dice_chain_downgraded).unwrap();
     assert!(matches!(
         sk_client_downgraded.get(&ID_EXAMPLE).unwrap_err(),
         Error::SecretkeeperError(SecretkeeperError::DicePolicyError)
@@ -610,6 +654,30 @@
     ));
 }
 
+// This test checks that the identity of Secretkeeper (in context of AuthGraph key exchange) is
+// same as the one advertized in Linux device tree. This is only expected from `default` instance.
+#[rdroidtest(get_instances())]
+#[ignore_if(|p| p != "default")]
+fn secretkeeper_check_identity(instance: String) {
+    let sk_key = get_secretkeeper_identity()
+        .expect("Failed to extract identity of default instance from device tree");
+    // Create a session with this expected identity. This succeeds only if the identity used by
+    // Secretkeeper is sk_key.
+    let _ = SkClient::with_expected_sk_identity(&instance, sk_key).unwrap();
+    // Create a session using any other expected sk identity, this should fail. Note that the
+    // failure arises from validation which happens at the local participant.
+    let mut any_other_key = CoseKey::default();
+    any_other_key.canonicalize(CborOrdering::Lexicographic);
+    let err = SkClient::with_expected_sk_identity(&instance, any_other_key).unwrap_err();
+    assert!(matches!(
+        err,
+        SkClientError::AuthgraphError(authgraph_core::error::Error(
+            authgraph_wire::ErrorCode::InvalidPeerKeKey,
+            _
+        ))
+    ));
+}
+
 // Helper method that constructs 3 SecretManagement requests. Callers would usually not care about
 // what each of the request concretely is.
 fn construct_secret_management_requests(sealing_policy: Vec<u8>) -> (Vec<u8>, Vec<u8>, Vec<u8>) {