Merge "[rkp_factory_extraction_tool] adding requireUdsCerts flag" into main
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 88b674e..4da0b6a 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_android_hardware_backed_security",
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
     // all of the 'license_kinds' from "system_security_license"
@@ -59,6 +60,7 @@
         "liblibc",
         "liblog_rust",
         "libmessage_macro",
+        "libpostprocessor_client",
         "librand",
         "librkpd_client",
         "librustutils",
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index ae3fb18..afc2743 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -123,6 +123,26 @@
 }
 
 aidl_interface {
+    name: "android.security.postprocessor",
+    srcs: ["android/security/postprocessor/*.aidl"],
+    unstable: true,
+    backend: {
+        java: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+        ndk: {
+            enabled: false,
+        },
+        rust: {
+            enabled: true,
+        },
+    },
+}
+
+aidl_interface {
     name: "android.security.metrics",
     srcs: ["android/security/metrics/*.aidl"],
     imports: [
diff --git a/keystore2/aidl/android/security/postprocessor/CertificateChain.aidl b/keystore2/aidl/android/security/postprocessor/CertificateChain.aidl
new file mode 100644
index 0000000..8d9daad
--- /dev/null
+++ b/keystore2/aidl/android/security/postprocessor/CertificateChain.aidl
@@ -0,0 +1,34 @@
+// Copyright 2024, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android.security.postprocessor;
+
+/**
+ * General parcelable for holding the encoded certificates to be used in Keystore. This parcelable
+ * is returned by `IKeystoreCertificatePostProcessor::processKeystoreCertificates`.
+ * @hide
+ */
+@RustDerive(Clone=true)
+parcelable CertificateChain {
+    /**
+     * Holds the DER-encoded representation of the leaf certificate.
+     */
+    byte[] leafCertificate;
+    /**
+     * Holds a byte array containing the concatenation of all the remaining elements of the
+     * certificate chain with root certificate as the last with each certificate represented in
+     * DER-encoded format.
+     */
+    byte[] remainingChain;
+}
diff --git a/keystore2/aidl/android/security/postprocessor/IKeystoreCertificatePostProcessor.aidl b/keystore2/aidl/android/security/postprocessor/IKeystoreCertificatePostProcessor.aidl
new file mode 100644
index 0000000..0ceaacb
--- /dev/null
+++ b/keystore2/aidl/android/security/postprocessor/IKeystoreCertificatePostProcessor.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.postprocessor;
+
+import android.security.postprocessor.CertificateChain;
+
+interface IKeystoreCertificatePostProcessor {
+    /**
+     * Allows implementing services to process the keystore certificates after the certificate
+     * chain has been generated.
+     *
+     * certificateChain holds the chain associated with a newly generated Keystore asymmetric
+     * keypair, where the leafCertificate is the certificate for the public key of generated key.
+     * The remaining attestation certificates are stored as a concatenated byte array of the
+     * encoded certificates with root certificate as the last element.
+     *
+     * Successful calls would get the processed certificate chain which then replaces the original
+     * certificate chain. In case of any failures/exceptions, keystore would fallback to the
+     * original certificate chain.
+     *
+     * @hide
+     */
+    CertificateChain processKeystoreCertificates(in CertificateChain certificateChain);
+}
diff --git a/keystore2/postprocessor_client/Android.bp b/keystore2/postprocessor_client/Android.bp
new file mode 100644
index 0000000..7f0194a
--- /dev/null
+++ b/keystore2/postprocessor_client/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright 2024, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_security_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_security_license"],
+}
+
+rust_defaults {
+    name: "libpostprocessor_client_defaults",
+    crate_name: "postprocessor_client",
+    srcs: ["src/lib.rs"],
+    rustlibs: [
+        "android.security.postprocessor-rust",
+        "libanyhow",
+        "libbinder_rs",
+        "liblog_rust",
+        "libmessage_macro",
+        "libthiserror",
+    ],
+    defaults: [
+        "keymint_use_latest_hal_aidl_rust",
+    ],
+}
+
+rust_library {
+    name: "libpostprocessor_client",
+    defaults: [
+        "libpostprocessor_client_defaults",
+    ],
+}
diff --git a/keystore2/postprocessor_client/src/lib.rs b/keystore2/postprocessor_client/src/lib.rs
new file mode 100644
index 0000000..8b347f9
--- /dev/null
+++ b/keystore2/postprocessor_client/src/lib.rs
@@ -0,0 +1,109 @@
+// Copyright 2024, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Helper wrapper around PostProcessor interface.
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::Certificate::Certificate;
+use android_security_postprocessor::aidl::android::security::postprocessor::{
+    CertificateChain::CertificateChain,
+    IKeystoreCertificatePostProcessor::IKeystoreCertificatePostProcessor,
+};
+use anyhow::{Context, Result};
+use binder::{StatusCode, Strong};
+use log::{error, info, warn};
+use message_macro::source_location_msg;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::mpsc;
+use std::thread;
+use std::time::Duration;
+
+/// Errors occurred during the interaction with Certificate Processor
+#[derive(Debug, Clone, Copy, thiserror::Error, PartialEq, Eq)]
+#[error("Binder transaction error {0:?}")]
+pub struct Error(pub StatusCode);
+
+static CERT_PROCESSOR_FAILURE: AtomicBool = AtomicBool::new(false);
+
+fn send_certificate_chain_to_processor(
+    attestation_chain: CertificateChain,
+) -> Result<CertificateChain> {
+    let cert_processing_server: Strong<dyn IKeystoreCertificatePostProcessor> = wait_for_interface(
+        "rkp_cert_processor.service".to_string(),
+    )
+    .context(source_location_msg!("While trying to connect to the post processor service."))?;
+    cert_processing_server
+        .processKeystoreCertificates(&attestation_chain)
+        .context(source_location_msg!("While trying to post process certificates."))
+}
+
+/// Processes the keystore certificates after the certificate chain has been generated by Keystore.
+/// More details about this function provided in IKeystoreCertificatePostProcessor.aidl
+pub fn process_certificate_chain(
+    mut certificates: Vec<Certificate>,
+    attestation_certs: Vec<u8>,
+) -> Vec<Certificate> {
+    // If no certificates are provided from keymint, return the original chain.
+    if certificates.is_empty() {
+        error!("No leaf certificate provided.");
+        return vec![Certificate { encodedCertificate: attestation_certs }];
+    }
+
+    if certificates.len() > 1 {
+        warn!("dropping {} unexpected extra certificates after the leaf", certificates.len() - 1);
+    }
+
+    let attestation_chain = CertificateChain {
+        leafCertificate: certificates[0].encodedCertificate.clone(),
+        remainingChain: attestation_certs.clone(),
+    };
+    let result = send_certificate_chain_to_processor(attestation_chain);
+    match result {
+        Ok(certificate_chain) => {
+            info!("Post processing successful. Replacing certificates.");
+            vec![
+                Certificate { encodedCertificate: certificate_chain.leafCertificate },
+                Certificate { encodedCertificate: certificate_chain.remainingChain },
+            ]
+        }
+        Err(err) => {
+            error!("Failed to replace certificates ({err:#?}), falling back to original chain.");
+            certificates.push(Certificate { encodedCertificate: attestation_certs });
+            certificates
+        }
+    }
+}
+
+fn wait_for_interface(
+    service_name: String,
+) -> Result<Strong<dyn IKeystoreCertificatePostProcessor>> {
+    if CERT_PROCESSOR_FAILURE.load(Ordering::Relaxed) {
+        return Err(Error(StatusCode::INVALID_OPERATION).into());
+    }
+    let (sender, receiver) = mpsc::channel();
+    let _t = thread::spawn(move || {
+        if let Err(e) = sender.send(binder::wait_for_interface(&service_name)) {
+            error!("failed to send result of wait_for_interface({service_name}), likely due to timeout: {e:?}");
+        }
+    });
+
+    match receiver.recv_timeout(Duration::from_secs(5)) {
+        Ok(service_binder) => Ok(service_binder?),
+        Err(e) => {
+            error!("Timed out while connecting to post processor service: {e:#?}");
+            // Cert processor has failed. Retry only after reboot.
+            CERT_PROCESSOR_FAILURE.store(true, Ordering::Relaxed);
+            Err(e.into())
+        }
+    }
+}
diff --git a/keystore2/src/error.rs b/keystore2/src/error.rs
index 5e80266..d57ba0c 100644
--- a/keystore2/src/error.rs
+++ b/keystore2/src/error.rs
@@ -34,6 +34,7 @@
     ExceptionCode, Result as BinderResult, Status as BinderStatus, StatusCode,
 };
 use keystore2_selinux as selinux;
+use postprocessor_client::Error as PostProcessorError;
 use rkpd_client::Error as RkpdError;
 use std::cmp::PartialEq;
 use std::ffi::CString;
@@ -103,6 +104,14 @@
     }
 }
 
+impl From<PostProcessorError> for Error {
+    fn from(e: PostProcessorError) -> Self {
+        match e {
+            PostProcessorError(s) => Error::BinderTransaction(s),
+        }
+    }
+}
+
 /// Maps an `rkpd_client::Error` that is wrapped with an `anyhow::Error` to a keystore2 `Error`.
 pub fn wrapped_rkpd_error_to_ks_error(e: &anyhow::Error) -> Error {
     match e.downcast_ref::<RkpdError>() {
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 89c0e97..233f2ae 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -64,7 +64,9 @@
     KeyMetadata::KeyMetadata, KeyParameters::KeyParameters, ResponseCode::ResponseCode,
 };
 use anyhow::{anyhow, Context, Result};
+use postprocessor_client::process_certificate_chain;
 use rkpd_client::store_rkpd_attestation_key;
+use rustutils::system_properties::read_bool;
 use std::convert::TryInto;
 use std::time::SystemTime;
 
@@ -632,14 +634,30 @@
                     log_security_safe_params(&params)
                 ))
                 .map(|(mut result, _)| {
-                    // The `certificateChain` in a `KeyCreationResult` should normally have one
-                    // `Certificate` for each certificate in the chain. To avoid having to
-                    // unnecessarily parse the RKP chain (which is concatenated DER-encoded certs),
-                    // stuff the whole concatenated chain into a single `Certificate`.
-                    // This is untangled by `store_new_key()`.
-                    result
-                        .certificateChain
-                        .push(Certificate { encodedCertificate: attestation_certs });
+                    if read_bool("remote_provisioning.use_cert_processor", false).unwrap_or(false) {
+                        let _wp = self.watch_millis(
+                            concat!(
+                                "KeystoreSecurityLevel::generate_key (RkpdProvisioned): ",
+                                "calling KeystorePostProcessor::process_certificate_chain",
+                            ),
+                            1000, // Post processing may take a little while due to network call.
+                        );
+                        // process_certificate_chain would either replace the certificate chain if
+                        // post-processing is successful or it would fallback to the original chain
+                        // on failure. In either case, we should get back the certificate chain
+                        // that is fit for storing with the newly generated key.
+                        result.certificateChain =
+                            process_certificate_chain(result.certificateChain, attestation_certs);
+                    } else {
+                        // The `certificateChain` in a `KeyCreationResult` should normally have one
+                        // `Certificate` for each certificate in the chain. To avoid having to
+                        // unnecessarily parse the RKP chain (which is concatenated DER-encoded
+                        // certs), stuff the whole concatenated chain into a single `Certificate`.
+                        // This is untangled by `store_new_key()`.
+                        result
+                            .certificateChain
+                            .push(Certificate { encodedCertificate: attestation_certs });
+                    }
                     result
                 })
             }
diff --git a/keystore2/test_utils/run_as.rs b/keystore2/test_utils/run_as.rs
index 14a72be..d4fd06c 100644
--- a/keystore2/test_utils/run_as.rs
+++ b/keystore2/test_utils/run_as.rs
@@ -422,6 +422,50 @@
     }
 }
 
+/// Run the given closure in a new process running with the root identity.
+///
+/// # Safety
+/// run_as runs the given closure in the client branch of fork. And it uses non
+/// async signal safe API. This means that calling this function in a multi threaded program
+/// yields undefined behavior in the child. As of this writing, it is safe to call this function
+/// from a Rust device test, because every test itself is spawned as a separate process.
+///
+/// # Safety Binder
+/// It is okay for the closure to use binder services, however, this does not work
+/// if the parent initialized libbinder already. So do not use binder outside of the closure
+/// in your test.
+pub unsafe fn run_as_root<F, R>(f: F) -> R
+where
+    R: Serialize + DeserializeOwned,
+    F: 'static + Send + FnOnce() -> R,
+{
+    // SAFETY: Our caller guarantees that the process only has a single thread.
+    unsafe { run_as("u:r:su:s0", Uid::from_raw(0), Gid::from_raw(0), f) }
+}
+
+/// Run the given closure in a new `untrusted_app` process running with the given `uid` and `gid`.
+///
+/// # Safety
+/// run_as runs the given closure in the client branch of fork. And it uses non
+/// async signal safe API. This means that calling this function in a multi threaded program
+/// yields undefined behavior in the child. As of this writing, it is safe to call this function
+/// from a Rust device test, because every test itself is spawned as a separate process.
+///
+/// # Safety Binder
+/// It is okay for the closure to use binder services, however, this does not work
+/// if the parent initialized libbinder already. So do not use binder outside of the closure
+/// in your test.
+pub unsafe fn run_as_app<F, R>(uid: u32, gid: u32, f: F) -> R
+where
+    R: Serialize + DeserializeOwned,
+    F: 'static + Send + FnOnce() -> R,
+{
+    // SAFETY: Our caller guarantees that the process only has a single thread.
+    unsafe {
+        run_as("u:r:untrusted_app:s0:c91,c256,c10,c20", Uid::from_raw(uid), Gid::from_raw(gid), f)
+    }
+}
+
 /// Run the given closure in a new process running with the new identity given as
 /// `uid`, `gid`, and `se_context`.
 ///
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
index 033036b..02dfd3f 100644
--- a/keystore2/tests/keystore2_client_attest_key_tests.rs
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -33,7 +33,7 @@
 use keystore2_test_utils::{
     authorizations, key_generations, key_generations::Error, run_as, SecLevel,
 };
-use nix::unistd::{getuid, Gid, Uid};
+use nix::unistd::getuid;
 use rustutils::users::AID_USER_OFFSET;
 
 /// Generate RSA and EC attestation keys and use them for signing RSA-signing keys.
@@ -655,47 +655,47 @@
 /// should return error response code - `GET_ATTESTATION_APPLICATION_ID_FAILED`.
 #[test]
 fn keystore2_generate_attested_key_fail_to_get_aaid() {
-    static APP_USER_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 19901;
     static APP_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static APP_GID: u32 = APP_UID;
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(APP_USER_CTX, Uid::from_raw(APP_UID), Gid::from_raw(APP_GID), || {
-            skip_test_if_no_app_attest_key_feature!();
-            let sl = SecLevel::tee();
-            if sl.keystore2.getInterfaceVersion().unwrap() < 4 {
-                // `GET_ATTESTATION_APPLICATION_ID_FAILED` is supported on devices with
-                // `IKeystoreService` version >= 4.
-                return;
-            }
-            let att_challenge: &[u8] = b"foo";
-            let alias = format!("ks_attest_rsa_encrypt_key_aaid_fail{}", getuid());
+    let gen_key_fn = || {
+        skip_test_if_no_app_attest_key_feature!();
+        let sl = SecLevel::tee();
+        if sl.keystore2.getInterfaceVersion().unwrap() < 4 {
+            // `GET_ATTESTATION_APPLICATION_ID_FAILED` is supported on devices with
+            // `IKeystoreService` version >= 4.
+            return;
+        }
+        let att_challenge: &[u8] = b"foo";
+        let alias = format!("ks_attest_rsa_encrypt_key_aaid_fail{}", getuid());
 
-            let result = key_generations::map_ks_error(key_generations::generate_rsa_key(
-                &sl,
-                Domain::APP,
-                -1,
-                Some(alias),
-                &key_generations::KeyParams {
-                    key_size: 2048,
-                    purpose: vec![KeyPurpose::ATTEST_KEY],
-                    padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
-                    digest: Some(Digest::SHA_2_256),
-                    mgf_digest: None,
-                    block_mode: None,
-                    att_challenge: Some(att_challenge.to_vec()),
-                },
-                None,
-            ));
+        let result = key_generations::map_ks_error(key_generations::generate_rsa_key(
+            &sl,
+            Domain::APP,
+            -1,
+            Some(alias),
+            &key_generations::KeyParams {
+                key_size: 2048,
+                purpose: vec![KeyPurpose::ATTEST_KEY],
+                padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+                digest: Some(Digest::SHA_2_256),
+                mgf_digest: None,
+                block_mode: None,
+                att_challenge: Some(att_challenge.to_vec()),
+            },
+            None,
+        ));
 
-            assert!(result.is_err());
-            assert_eq!(
-                result.unwrap_err(),
-                Error::Rc(ResponseCode::GET_ATTESTATION_APPLICATION_ID_FAILED)
-            );
-        })
+        assert!(result.is_err());
+        assert_eq!(
+            result.unwrap_err(),
+            Error::Rc(ResponseCode::GET_ATTESTATION_APPLICATION_ID_FAILED)
+        );
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(APP_UID, APP_GID, gen_key_fn) };
 }
diff --git a/keystore2/tests/keystore2_client_authorizations_tests.rs b/keystore2/tests/keystore2_client_authorizations_tests.rs
index 4e83f73..bd9dab9 100644
--- a/keystore2/tests/keystore2_client_authorizations_tests.rs
+++ b/keystore2/tests/keystore2_client_authorizations_tests.rs
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 use crate::keystore2_client_test_utils::{
-    app_attest_key_feature_exists, delete_app_key,
+    app_attest_key_feature_exists, delete_app_key, get_vsr_api_level,
     perform_sample_asym_sign_verify_op, perform_sample_hmac_sign_verify_op,
     perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op,
     verify_certificate_serial_num, verify_certificate_subject_name, SAMPLE_PLAIN_TEXT,
@@ -638,6 +638,11 @@
 #[test]
 fn keystore2_gen_key_auth_app_data_app_id_test_success() {
     let sl = SecLevel::tee();
+    if sl.is_keymaster() && get_vsr_api_level() < 35 {
+        // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+        // test to run on older devices.
+        return;
+    }
 
     let gen_params = authorizations::AuthSetBuilder::new()
         .no_auth_required()
@@ -669,6 +674,11 @@
 #[test]
 fn keystore2_op_auth_invalid_app_data_app_id_test_fail() {
     let sl = SecLevel::tee();
+    if sl.is_keymaster() && get_vsr_api_level() < 35 {
+        // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+        // test to run on older devices.
+        return;
+    }
 
     let gen_params = authorizations::AuthSetBuilder::new()
         .no_auth_required()
@@ -701,6 +711,11 @@
 #[test]
 fn keystore2_op_auth_missing_app_data_test_fail() {
     let sl = SecLevel::tee();
+    if sl.is_keymaster() && get_vsr_api_level() < 35 {
+        // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+        // test to run on older devices.
+        return;
+    }
 
     let gen_params = authorizations::AuthSetBuilder::new()
         .no_auth_required()
@@ -733,6 +748,11 @@
 #[test]
 fn keystore2_op_auth_missing_app_id_test_fail() {
     let sl = SecLevel::tee();
+    if sl.is_keymaster() && get_vsr_api_level() < 35 {
+        // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+        // test to run on older devices.
+        return;
+    }
 
     let gen_params = authorizations::AuthSetBuilder::new()
         .no_auth_required()
@@ -766,6 +786,11 @@
 fn keystore2_gen_attested_key_auth_app_id_app_data_test_success() {
     skip_test_if_no_app_attest_key_feature!();
     let sl = SecLevel::tee();
+    if sl.is_keymaster() && get_vsr_api_level() < 35 {
+        // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+        // test to run on older devices.
+        return;
+    }
 
     // Generate attestation key.
     let attest_gen_params = authorizations::AuthSetBuilder::new()
@@ -822,6 +847,11 @@
 fn keystore2_gen_attestation_key_with_auth_app_id_app_data_test_fail() {
     skip_test_if_no_app_attest_key_feature!();
     let sl = SecLevel::tee();
+    if sl.is_keymaster() && get_vsr_api_level() < 35 {
+        // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+        // test to run on older devices.
+        return;
+    }
 
     // Generate attestation key.
     let attest_gen_params = authorizations::AuthSetBuilder::new()
diff --git a/keystore2/tests/keystore2_client_ec_key_tests.rs b/keystore2/tests/keystore2_client_ec_key_tests.rs
index 8aa9bc4..526a339 100644
--- a/keystore2/tests/keystore2_client_ec_key_tests.rs
+++ b/keystore2/tests/keystore2_client_ec_key_tests.rs
@@ -425,7 +425,9 @@
     // Client#1: Generate a key and create an operation using generated key.
     // Wait until the parent notifies to continue. Once the parent notifies, this operation
     // is expected to be completed successfully.
-    // SAFETY: The test is run in a separate process with no other threads.
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
     let mut child_handle = unsafe {
         execute_op_run_as_child(
             TARGET_CTX,
@@ -446,20 +448,23 @@
     const APPLICATION_ID_2: u32 = 10602;
     let uid2 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_2;
     let gid2 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_2;
-    // SAFETY: The test is run in a separate process with no other threads.
+
+    let get_key_fn = move || {
+        let keystore2_inst = get_keystore_service();
+        let result = key_generations::map_ks_error(keystore2_inst.getKeyEntry(&KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(alias.to_string()),
+            blob: None,
+        }));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+    };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
     unsafe {
-        run_as::run_as(TARGET_CTX, Uid::from_raw(uid2), Gid::from_raw(gid2), move || {
-            let keystore2_inst = get_keystore_service();
-            let result =
-                key_generations::map_ks_error(keystore2_inst.getKeyEntry(&KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(alias.to_string()),
-                    blob: None,
-                }));
-            assert!(result.is_err());
-            assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
-        });
+        run_as::run_as_app(uid2, gid2, get_key_fn);
     };
 
     // Notify the child process (client#1) to resume and finish.
diff --git a/keystore2/tests/keystore2_client_grant_key_tests.rs b/keystore2/tests/keystore2_client_grant_key_tests.rs
index 89569f5..5391d20 100644
--- a/keystore2/tests/keystore2_client_grant_key_tests.rs
+++ b/keystore2/tests/keystore2_client_grant_key_tests.rs
@@ -25,7 +25,7 @@
 use keystore2_test_utils::{
     authorizations, get_keystore_service, key_generations, key_generations::Error, run_as, SecLevel,
 };
-use nix::unistd::{getuid, Gid, Uid};
+use nix::unistd::getuid;
 use rustutils::users::AID_USER_OFFSET;
 
 /// Generate an EC signing key and grant it to the user with given access vector.
@@ -100,53 +100,47 @@
 /// should fail to load the key with permission denied error.
 #[test]
 fn keystore2_grant_key_with_perm_none() {
-    static TARGET_SU_CTX: &str = "u:r:su:s0";
-
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static GRANTEE_GID: u32 = GRANTEE_UID;
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    let grant_key_nspace = unsafe {
-        run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let empty_access_vector = KeyPermission::NONE.0;
+    let grantor_fn = || {
+        let empty_access_vector = KeyPermission::NONE.0;
 
-            let grant_key = key_generations::map_ks_error(generate_ec_key_and_grant_to_user(
-                GRANTEE_UID.try_into().unwrap(),
-                empty_access_vector,
-            ))
-            .unwrap();
+        let grant_key = key_generations::map_ks_error(generate_ec_key_and_grant_to_user(
+            GRANTEE_UID.try_into().unwrap(),
+            empty_access_vector,
+        ))
+        .unwrap();
 
-            assert_eq!(grant_key.domain, Domain::GRANT);
+        assert_eq!(grant_key.domain, Domain::GRANT);
 
-            grant_key.nspace
-        })
+        grant_key.nspace
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
     // In grantee context try to load the key, it should fail to load the granted key as it is
     // granted with empty access vector.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_UID),
-            Gid::from_raw(GRANTEE_GID),
-            move || {
-                let keystore2 = get_keystore_service();
+    let grantee_fn = move || {
+        let keystore2 = get_keystore_service();
 
-                let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
-                    domain: Domain::GRANT,
-                    nspace: grant_key_nspace,
-                    alias: None,
-                    blob: None,
-                }));
-                assert!(result.is_err());
-                assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
-            },
-        )
+        let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+            domain: Domain::GRANT,
+            nspace: grant_key_nspace,
+            alias: None,
+            blob: None,
+        }));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
 }
 
 /// Grant a key to the user (grantee) with `GET_INFO|USE` key permissions. Verify whether grantee
@@ -156,84 +150,77 @@
 /// delete it as `DELETE` permission is not granted.
 #[test]
 fn keystore2_grant_get_info_use_key_perm() {
-    static TARGET_SU_CTX: &str = "u:r:su:s0";
-
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static GRANTEE_GID: u32 = GRANTEE_UID;
 
     // Generate a key and grant it to a user with GET_INFO|USE key permissions.
-    // SAFETY: The test is run in a separate process with no other threads.
-    let grant_key_nspace = unsafe {
-        run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::USE.0;
-            let grant_key = key_generations::map_ks_error(generate_ec_key_and_grant_to_user(
-                GRANTEE_UID.try_into().unwrap(),
-                access_vector,
-            ))
-            .unwrap();
+    let grantor_fn = || {
+        let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::USE.0;
+        let grant_key = key_generations::map_ks_error(generate_ec_key_and_grant_to_user(
+            GRANTEE_UID.try_into().unwrap(),
+            access_vector,
+        ))
+        .unwrap();
 
-            assert_eq!(grant_key.domain, Domain::GRANT);
+        assert_eq!(grant_key.domain, Domain::GRANT);
 
-            grant_key.nspace
-        })
+        grant_key.nspace
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
     // In grantee context load the key and try to perform crypto operation.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_UID),
-            Gid::from_raw(GRANTEE_GID),
-            move || {
-                let sl = SecLevel::tee();
+    let grantee_fn = move || {
+        let sl = SecLevel::tee();
 
-                // Load the granted key.
-                let key_entry_response = sl
-                    .keystore2
-                    .getKeyEntry(&KeyDescriptor {
-                        domain: Domain::GRANT,
-                        nspace: grant_key_nspace,
-                        alias: None,
-                        blob: None,
-                    })
-                    .unwrap();
+        // Load the granted key.
+        let key_entry_response = sl
+            .keystore2
+            .getKeyEntry(&KeyDescriptor {
+                domain: Domain::GRANT,
+                nspace: grant_key_nspace,
+                alias: None,
+                blob: None,
+            })
+            .unwrap();
 
-                // Perform sample crypto operation using granted key.
-                let op_response = sl
-                    .binder
-                    .createOperation(
-                        &key_entry_response.metadata.key,
-                        &authorizations::AuthSetBuilder::new()
-                            .purpose(KeyPurpose::SIGN)
-                            .digest(Digest::SHA_2_256),
-                        false,
-                    )
-                    .unwrap();
-                assert!(op_response.iOperation.is_some());
-                assert_eq!(
-                    Ok(()),
-                    key_generations::map_ks_error(perform_sample_sign_operation(
-                        &op_response.iOperation.unwrap()
-                    ))
-                );
+        // Perform sample crypto operation using granted key.
+        let op_response = sl
+            .binder
+            .createOperation(
+                &key_entry_response.metadata.key,
+                &authorizations::AuthSetBuilder::new()
+                    .purpose(KeyPurpose::SIGN)
+                    .digest(Digest::SHA_2_256),
+                false,
+            )
+            .unwrap();
+        assert!(op_response.iOperation.is_some());
+        assert_eq!(
+            Ok(()),
+            key_generations::map_ks_error(perform_sample_sign_operation(
+                &op_response.iOperation.unwrap()
+            ))
+        );
 
-                // Try to delete the key, it is expected to be fail with permission denied error.
-                let result =
-                    key_generations::map_ks_error(sl.keystore2.deleteKey(&KeyDescriptor {
-                        domain: Domain::GRANT,
-                        nspace: grant_key_nspace,
-                        alias: None,
-                        blob: None,
-                    }));
-                assert!(result.is_err());
-                assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
-            },
-        )
+        // Try to delete the key, it is expected to be fail with permission denied error.
+        let result = key_generations::map_ks_error(sl.keystore2.deleteKey(&KeyDescriptor {
+            domain: Domain::GRANT,
+            nspace: grant_key_nspace,
+            alias: None,
+            blob: None,
+        }));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
 }
 
 /// Grant a key to the user with DELETE access. In grantee context load the key and delete it.
@@ -241,8 +228,6 @@
 /// should fail to find the key with error response `KEY_NOT_FOUND`.
 #[test]
 fn keystore2_grant_delete_key_success() {
-    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -250,60 +235,57 @@
     static ALIAS: &str = "ks_grant_key_delete_success";
 
     // Generate a key and grant it to a user with DELETE permission.
-    // SAFETY: The test is run in a separate process with no other threads.
-    let grant_key_nspace = unsafe {
-        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
-            let access_vector = KeyPermission::DELETE.0;
-            let mut grant_keys = generate_ec_key_and_grant_to_users(
-                &sl,
-                Some(ALIAS.to_string()),
-                vec![GRANTEE_UID.try_into().unwrap()],
-                access_vector,
-            )
-            .unwrap();
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let access_vector = KeyPermission::DELETE.0;
+        let mut grant_keys = generate_ec_key_and_grant_to_users(
+            &sl,
+            Some(ALIAS.to_string()),
+            vec![GRANTEE_UID.try_into().unwrap()],
+            access_vector,
+        )
+        .unwrap();
 
-            grant_keys.remove(0)
-        })
+        grant_keys.remove(0)
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
     // Grantee context, delete the key.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_UID),
-            Gid::from_raw(GRANTEE_GID),
-            move || {
-                let keystore2 = get_keystore_service();
-                keystore2
-                    .deleteKey(&KeyDescriptor {
-                        domain: Domain::GRANT,
-                        nspace: grant_key_nspace,
-                        alias: None,
-                        blob: None,
-                    })
-                    .unwrap();
-            },
-        )
+    let grantee_fn = move || {
+        let keystore2 = get_keystore_service();
+        keystore2
+            .deleteKey(&KeyDescriptor {
+                domain: Domain::GRANT,
+                nspace: grant_key_nspace,
+                alias: None,
+                blob: None,
+            })
+            .unwrap();
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
+
     // Verify whether key got deleted in grantor's context.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), move || {
-            let keystore2_inst = get_keystore_service();
-            let result =
-                key_generations::map_ks_error(keystore2_inst.getKeyEntry(&KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(ALIAS.to_string()),
-                    blob: None,
-                }));
-            assert!(result.is_err());
-            assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
-        })
+    let grantor_fn = move || {
+        let keystore2_inst = get_keystore_service();
+        let result = key_generations::map_ks_error(keystore2_inst.getKeyEntry(&KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(ALIAS.to_string()),
+            blob: None,
+        }));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_root(grantor_fn) };
 }
 
 /// Grant a key to the user. In grantee context load the granted key and try to grant it to second
@@ -313,8 +295,6 @@
 #[test]
 #[ignore]
 fn keystore2_grant_key_fails_with_permission_denied() {
-    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -326,77 +306,69 @@
     static SEC_GRANTEE_GID: u32 = SEC_GRANTEE_UID;
 
     // Generate a key and grant it to a user with GET_INFO permission.
-    // SAFETY: The test is run in a separate process with no other threads.
-    let grant_key_nspace = unsafe {
-        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
-            let access_vector = KeyPermission::GET_INFO.0;
-            let alias = format!("ks_grant_perm_denied_key_{}", getuid());
-            let mut grant_keys = generate_ec_key_and_grant_to_users(
-                &sl,
-                Some(alias),
-                vec![GRANTEE_UID.try_into().unwrap()],
-                access_vector,
-            )
-            .unwrap();
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let access_vector = KeyPermission::GET_INFO.0;
+        let alias = format!("ks_grant_perm_denied_key_{}", getuid());
+        let mut grant_keys = generate_ec_key_and_grant_to_users(
+            &sl,
+            Some(alias),
+            vec![GRANTEE_UID.try_into().unwrap()],
+            access_vector,
+        )
+        .unwrap();
 
-            grant_keys.remove(0)
-        })
+        grant_keys.remove(0)
     };
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
 
     // Grantee context, load the granted key and try to grant it to `SEC_GRANTEE_UID` grantee.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_UID),
-            Gid::from_raw(GRANTEE_GID),
-            move || {
-                let keystore2 = get_keystore_service();
-                let access_vector = KeyPermission::GET_INFO.0;
+    let grantee_fn = move || {
+        let keystore2 = get_keystore_service();
+        let access_vector = KeyPermission::GET_INFO.0;
 
-                let key_entry_response = keystore2
-                    .getKeyEntry(&KeyDescriptor {
-                        domain: Domain::GRANT,
-                        nspace: grant_key_nspace,
-                        alias: None,
-                        blob: None,
-                    })
-                    .unwrap();
+        let key_entry_response = keystore2
+            .getKeyEntry(&KeyDescriptor {
+                domain: Domain::GRANT,
+                nspace: grant_key_nspace,
+                alias: None,
+                blob: None,
+            })
+            .unwrap();
 
-                let result = key_generations::map_ks_error(keystore2.grant(
-                    &key_entry_response.metadata.key,
-                    SEC_GRANTEE_UID.try_into().unwrap(),
-                    access_vector,
-                ));
-                assert!(result.is_err());
-                assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
-            },
-        )
+        let result = key_generations::map_ks_error(keystore2.grant(
+            &key_entry_response.metadata.key,
+            SEC_GRANTEE_UID.try_into().unwrap(),
+            access_vector,
+        ));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
+
     // Make sure second grantee shouldn't have access to the above granted key.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(SEC_GRANTEE_UID),
-            Gid::from_raw(SEC_GRANTEE_GID),
-            move || {
-                let keystore2 = get_keystore_service();
+    let grantee2_fn = move || {
+        let keystore2 = get_keystore_service();
 
-                let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
-                    domain: Domain::GRANT,
-                    nspace: grant_key_nspace,
-                    alias: None,
-                    blob: None,
-                }));
+        let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+            domain: Domain::GRANT,
+            nspace: grant_key_nspace,
+            alias: None,
+            blob: None,
+        }));
 
-                assert!(result.is_err());
-                assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
-            },
-        )
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(SEC_GRANTEE_UID, SEC_GRANTEE_GID, grantee2_fn) };
 }
 
 /// Try to grant a key with `GRANT` access. Keystore2 system shouldn't allow to grant a key with
@@ -449,67 +421,57 @@
 /// the key. Grantee should fail to load the ungranted key with `KEY_NOT_FOUND` error response.
 #[test]
 fn keystore2_ungrant_key_success() {
-    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static GRANTEE_GID: u32 = GRANTEE_UID;
 
     // Generate a key and grant it to a user with GET_INFO permission.
-    // SAFETY: The test is run in a separate process with no other threads.
-    let grant_key_nspace = unsafe {
-        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
-            let alias = format!("ks_ungrant_test_key_1{}", getuid());
-            let access_vector = KeyPermission::GET_INFO.0;
-            let mut grant_keys = generate_ec_key_and_grant_to_users(
-                &sl,
-                Some(alias.to_string()),
-                vec![GRANTEE_UID.try_into().unwrap()],
-                access_vector,
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let alias = format!("ks_ungrant_test_key_1{}", getuid());
+        let access_vector = KeyPermission::GET_INFO.0;
+        let mut grant_keys = generate_ec_key_and_grant_to_users(
+            &sl,
+            Some(alias.to_string()),
+            vec![GRANTEE_UID.try_into().unwrap()],
+            access_vector,
+        )
+        .unwrap();
+
+        let grant_key_nspace = grant_keys.remove(0);
+
+        // Ungrant above granted key.
+        sl.keystore2
+            .ungrant(
+                &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: Some(alias), blob: None },
+                GRANTEE_UID.try_into().unwrap(),
             )
             .unwrap();
 
-            let grant_key_nspace = grant_keys.remove(0);
-
-            // Ungrant above granted key.
-            sl.keystore2
-                .ungrant(
-                    &KeyDescriptor {
-                        domain: Domain::APP,
-                        nspace: -1,
-                        alias: Some(alias),
-                        blob: None,
-                    },
-                    GRANTEE_UID.try_into().unwrap(),
-                )
-                .unwrap();
-
-            grant_key_nspace
-        })
+        grant_key_nspace
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
     // Grantee context, try to load the ungranted key.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_UID),
-            Gid::from_raw(GRANTEE_GID),
-            move || {
-                let keystore2 = get_keystore_service();
-                let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
-                    domain: Domain::GRANT,
-                    nspace: grant_key_nspace,
-                    alias: None,
-                    blob: None,
-                }));
-                assert!(result.is_err());
-                assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
-            },
-        )
+    let grantee_fn = move || {
+        let keystore2 = get_keystore_service();
+        let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+            domain: Domain::GRANT,
+            nspace: grant_key_nspace,
+            alias: None,
+            blob: None,
+        }));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
 }
 
 /// Generate a key, grant it to the user and then delete the granted key. Try to ungrant
@@ -519,93 +481,84 @@
 /// associated key is deleted from grantor context.
 #[test]
 fn keystore2_ungrant_fails_with_non_existing_key_expect_key_not_found_error() {
-    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
     const APPLICATION_ID: u32 = 10001;
     const USER_ID: u32 = 99;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static GRANTEE_GID: u32 = GRANTEE_UID;
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    let grant_key_nspace = unsafe {
-        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
-            let alias = format!("{}{}", "ks_grant_delete_ungrant_test_key_1", getuid());
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let alias = format!("{}{}", "ks_grant_delete_ungrant_test_key_1", getuid());
 
-            let key_metadata = key_generations::generate_ec_p256_signing_key(
-                &sl,
-                Domain::SELINUX,
-                key_generations::SELINUX_SHELL_NAMESPACE,
-                Some(alias.to_string()),
-                None,
-            )
+        let key_metadata = key_generations::generate_ec_p256_signing_key(
+            &sl,
+            Domain::SELINUX,
+            key_generations::SELINUX_SHELL_NAMESPACE,
+            Some(alias.to_string()),
+            None,
+        )
+        .unwrap();
+
+        let access_vector = KeyPermission::GET_INFO.0;
+        let grant_key = sl
+            .keystore2
+            .grant(&key_metadata.key, GRANTEE_UID.try_into().unwrap(), access_vector)
             .unwrap();
+        assert_eq!(grant_key.domain, Domain::GRANT);
 
-            let access_vector = KeyPermission::GET_INFO.0;
-            let grant_key = sl
-                .keystore2
-                .grant(&key_metadata.key, GRANTEE_UID.try_into().unwrap(), access_vector)
-                .unwrap();
-            assert_eq!(grant_key.domain, Domain::GRANT);
+        // Delete above granted key.
+        sl.keystore2.deleteKey(&key_metadata.key).unwrap();
 
-            // Delete above granted key.
-            sl.keystore2.deleteKey(&key_metadata.key).unwrap();
+        // Try to ungrant above granted key.
+        let result = key_generations::map_ks_error(
+            sl.keystore2.ungrant(&key_metadata.key, GRANTEE_UID.try_into().unwrap()),
+        );
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
 
-            // Try to ungrant above granted key.
-            let result = key_generations::map_ks_error(
-                sl.keystore2.ungrant(&key_metadata.key, GRANTEE_UID.try_into().unwrap()),
-            );
-            assert!(result.is_err());
-            assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+        // Generate a new key with the same alias and try to access the earlier granted key
+        // in grantee context.
+        let result = key_generations::generate_ec_p256_signing_key(
+            &sl,
+            Domain::SELINUX,
+            key_generations::SELINUX_SHELL_NAMESPACE,
+            Some(alias),
+            None,
+        );
+        assert!(result.is_ok());
 
-            // Generate a new key with the same alias and try to access the earlier granted key
-            // in grantee context.
-            let result = key_generations::generate_ec_p256_signing_key(
-                &sl,
-                Domain::SELINUX,
-                key_generations::SELINUX_SHELL_NAMESPACE,
-                Some(alias),
-                None,
-            );
-            assert!(result.is_ok());
-
-            grant_key.nspace
-        })
+        grant_key.nspace
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
     // Make sure grant did not persist, try to access the earlier granted key in grantee context.
     // Grantee context should fail to load the granted key as its associated key is deleted in
     // grantor context.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_UID),
-            Gid::from_raw(GRANTEE_GID),
-            move || {
-                let keystore2 = get_keystore_service();
+    let grantee_fn = move || {
+        let keystore2 = get_keystore_service();
 
-                let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
-                    domain: Domain::GRANT,
-                    nspace: grant_key_nspace,
-                    alias: None,
-                    blob: None,
-                }));
-                assert!(result.is_err());
-                assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
-            },
-        )
+        let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+            domain: Domain::GRANT,
+            nspace: grant_key_nspace,
+            alias: None,
+            blob: None,
+        }));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
 }
 
 /// Grant a key to multiple users. Verify that all grantees should succeed in loading the key and
 /// use it for performing an operation successfully.
 #[test]
 fn keystore2_grant_key_to_multi_users_success() {
-    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
     const APPLICATION_ID: u32 = 10001;
     const USER_ID_1: u32 = 99;
     static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
@@ -616,46 +569,42 @@
     static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
 
     // Generate a key and grant it to multiple users with GET_INFO|USE permissions.
-    // SAFETY: The test is run in a separate process with no other threads.
-    let mut grant_keys = unsafe {
-        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
-            let alias = format!("ks_grant_test_key_2{}", getuid());
-            let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::USE.0;
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let alias = format!("ks_grant_test_key_2{}", getuid());
+        let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::USE.0;
 
-            generate_ec_key_and_grant_to_users(
-                &sl,
-                Some(alias),
-                vec![GRANTEE_1_UID.try_into().unwrap(), GRANTEE_2_UID.try_into().unwrap()],
-                access_vector,
-            )
-            .unwrap()
-        })
+        generate_ec_key_and_grant_to_users(
+            &sl,
+            Some(alias),
+            vec![GRANTEE_1_UID.try_into().unwrap(), GRANTEE_2_UID.try_into().unwrap()],
+            access_vector,
+        )
+        .unwrap()
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let mut grant_keys = unsafe { run_as::run_as_root(grantor_fn) };
+
     for (grantee_uid, grantee_gid) in
         &[(GRANTEE_1_UID, GRANTEE_1_GID), (GRANTEE_2_UID, GRANTEE_2_GID)]
     {
         let grant_key_nspace = grant_keys.remove(0);
-        // SAFETY: The test is run in a separate process with no other threads.
-        unsafe {
-            run_as::run_as(
-                GRANTEE_CTX,
-                Uid::from_raw(*grantee_uid),
-                Gid::from_raw(*grantee_gid),
-                move || {
-                    let sl = SecLevel::tee();
+        let grantee_fn = move || {
+            let sl = SecLevel::tee();
 
-                    assert_eq!(
-                        Ok(()),
-                        key_generations::map_ks_error(load_grant_key_and_perform_sign_operation(
-                            &sl,
-                            grant_key_nspace
-                        ))
-                    );
-                },
-            )
+            assert_eq!(
+                Ok(()),
+                key_generations::map_ks_error(load_grant_key_and_perform_sign_operation(
+                    &sl,
+                    grant_key_nspace
+                ))
+            );
         };
+        // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+        // `--test-threads=1`), and nothing yet done with binder.
+        unsafe { run_as::run_as_app(*grantee_uid, *grantee_gid, grantee_fn) };
     }
 }
 
@@ -664,9 +613,6 @@
 /// fail to load the granted key with `KEY_NOT_FOUND` error response.
 #[test]
 fn keystore2_grant_key_to_multi_users_delete_fails_with_key_not_found_error() {
-    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
     const USER_ID_1: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
@@ -677,76 +623,69 @@
     static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
 
     // Generate a key and grant it to multiple users with GET_INFO permission.
-    // SAFETY: The test is run in a separate process with no other threads.
-    let mut grant_keys = unsafe {
-        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
-            let alias = format!("ks_grant_test_key_2{}", getuid());
-            let access_vector =
-                KeyPermission::GET_INFO.0 | KeyPermission::USE.0 | KeyPermission::DELETE.0;
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let alias = format!("ks_grant_test_key_2{}", getuid());
+        let access_vector =
+            KeyPermission::GET_INFO.0 | KeyPermission::USE.0 | KeyPermission::DELETE.0;
 
-            generate_ec_key_and_grant_to_users(
-                &sl,
-                Some(alias),
-                vec![GRANTEE_1_UID.try_into().unwrap(), GRANTEE_2_UID.try_into().unwrap()],
-                access_vector,
-            )
-            .unwrap()
-        })
+        generate_ec_key_and_grant_to_users(
+            &sl,
+            Some(alias),
+            vec![GRANTEE_1_UID.try_into().unwrap(), GRANTEE_2_UID.try_into().unwrap()],
+            access_vector,
+        )
+        .unwrap()
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let mut grant_keys = unsafe { run_as::run_as_root(grantor_fn) };
+
     // Grantee #1 context
     let grant_key1_nspace = grant_keys.remove(0);
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_1_UID),
-            Gid::from_raw(GRANTEE_1_GID),
-            move || {
-                let sl = SecLevel::tee();
+    let grantee1_fn = move || {
+        let sl = SecLevel::tee();
 
-                assert_eq!(
-                    Ok(()),
-                    key_generations::map_ks_error(load_grant_key_and_perform_sign_operation(
-                        &sl,
-                        grant_key1_nspace
-                    ))
-                );
+        assert_eq!(
+            Ok(()),
+            key_generations::map_ks_error(load_grant_key_and_perform_sign_operation(
+                &sl,
+                grant_key1_nspace
+            ))
+        );
 
-                // Delete the granted key.
-                sl.keystore2
-                    .deleteKey(&KeyDescriptor {
-                        domain: Domain::GRANT,
-                        nspace: grant_key1_nspace,
-                        alias: None,
-                        blob: None,
-                    })
-                    .unwrap();
-            },
-        )
+        // Delete the granted key.
+        sl.keystore2
+            .deleteKey(&KeyDescriptor {
+                domain: Domain::GRANT,
+                nspace: grant_key1_nspace,
+                alias: None,
+                blob: None,
+            })
+            .unwrap();
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_1_UID, GRANTEE_1_GID, grantee1_fn) };
+
     // Grantee #2 context
     let grant_key2_nspace = grant_keys.remove(0);
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_2_UID),
-            Gid::from_raw(GRANTEE_2_GID),
-            move || {
-                let keystore2 = get_keystore_service();
+    let grantee2_fn = move || {
+        let keystore2 = get_keystore_service();
 
-                let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
-                    domain: Domain::GRANT,
-                    nspace: grant_key2_nspace,
-                    alias: None,
-                    blob: None,
-                }));
-                assert!(result.is_err());
-                assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
-            },
-        )
+        let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+            domain: Domain::GRANT,
+            nspace: grant_key2_nspace,
+            alias: None,
+            blob: None,
+        }));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_2_UID, GRANTEE_2_GID, grantee2_fn) };
 }
diff --git a/keystore2/tests/keystore2_client_keystore_engine_tests.rs b/keystore2/tests/keystore2_client_keystore_engine_tests.rs
index 01f8917..a4d7f2c 100644
--- a/keystore2/tests/keystore2_client_keystore_engine_tests.rs
+++ b/keystore2/tests/keystore2_client_keystore_engine_tests.rs
@@ -24,7 +24,6 @@
 use keystore2_test_utils::{
     authorizations::AuthSetBuilder, get_keystore_service, run_as, SecLevel,
 };
-use nix::unistd::{Gid, Uid};
 use openssl::x509::X509;
 use rustutils::users::AID_USER_OFFSET;
 
@@ -152,80 +151,65 @@
 }
 
 #[test]
-fn keystore2_perofrm_crypto_op_using_keystore2_engine_rsa_key_success() {
-    static TARGET_SU_CTX: &str = "u:r:su:s0";
-
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+fn keystore2_perform_crypto_op_using_keystore2_engine_rsa_key_success() {
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static GRANTEE_GID: u32 = GRANTEE_UID;
 
     // Generate a key and grant it to a user with GET_INFO|USE|DELETE key permissions.
-    // SAFETY: The test is run in a separate process with no other threads.
-    let grant_key_nspace = unsafe {
-        run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
-            let alias = "keystore2_engine_rsa_key";
-            generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::RSA).unwrap()
-        })
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let alias = "keystore2_engine_rsa_key";
+        generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::RSA).unwrap()
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
     // In grantee context load the key and try to perform crypto operation.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_UID),
-            Gid::from_raw(GRANTEE_GID),
-            move || {
-                let keystore2 = get_keystore_service();
-                perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
-            },
-        )
+    let grantee_fn = move || {
+        let keystore2 = get_keystore_service();
+        perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
 }
 
 #[test]
-fn keystore2_perofrm_crypto_op_using_keystore2_engine_ec_key_success() {
-    static TARGET_SU_CTX: &str = "u:r:su:s0";
-
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+fn keystore2_perform_crypto_op_using_keystore2_engine_ec_key_success() {
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static GRANTEE_GID: u32 = GRANTEE_UID;
 
     // Generate a key and grant it to a user with GET_INFO|USE|DELETE key permissions.
-    // SAFETY: The test is run in a separate process with no other threads.
-    let grant_key_nspace = unsafe {
-        run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
-            let alias = "keystore2_engine_ec_test_key";
-            generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::EC).unwrap()
-        })
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let alias = "keystore2_engine_ec_test_key";
+        generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::EC).unwrap()
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
     // In grantee context load the key and try to perform crypto operation.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_UID),
-            Gid::from_raw(GRANTEE_GID),
-            move || {
-                let keystore2 = get_keystore_service();
-                perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
-            },
-        )
+    let grantee_fn = move || {
+        let keystore2 = get_keystore_service();
+        perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
 }
 
 #[test]
-fn keystore2_perofrm_crypto_op_using_keystore2_engine_pem_pub_key_success() {
-    static TARGET_SU_CTX: &str = "u:r:su:s0";
-
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+fn keystore2_perform_crypto_op_using_keystore2_engine_pem_pub_key_success() {
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -233,46 +217,43 @@
 
     // Generate a key and re-encode it's certificate as PEM and update it and
     // grant it to a user with GET_INFO|USE|DELETE key permissions.
-    // SAFETY: The test is run in a separate process with no other threads.
-    let grant_key_nspace = unsafe {
-        run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
-            let alias = "keystore2_engine_rsa_pem_pub_key";
-            let grant_key_nspace =
-                generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::RSA).unwrap();
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let alias = "keystore2_engine_rsa_pem_pub_key";
+        let grant_key_nspace =
+            generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::RSA).unwrap();
 
-            // Update certificate with encodeed PEM data.
-            let key_entry_response = sl
-                .keystore2
-                .getKeyEntry(&KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(alias.to_string()),
-                    blob: None,
-                })
-                .unwrap();
-            let cert_bytes = key_entry_response.metadata.certificate.as_ref().unwrap();
-            let cert = X509::from_der(cert_bytes.as_ref()).unwrap();
-            let cert_pem = cert.to_pem().unwrap();
-            sl.keystore2
-                .updateSubcomponent(&key_entry_response.metadata.key, Some(&cert_pem), None)
-                .expect("updateSubcomponent failed.");
+        // Update certificate with encodeed PEM data.
+        let key_entry_response = sl
+            .keystore2
+            .getKeyEntry(&KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(alias.to_string()),
+                blob: None,
+            })
+            .unwrap();
+        let cert_bytes = key_entry_response.metadata.certificate.as_ref().unwrap();
+        let cert = X509::from_der(cert_bytes.as_ref()).unwrap();
+        let cert_pem = cert.to_pem().unwrap();
+        sl.keystore2
+            .updateSubcomponent(&key_entry_response.metadata.key, Some(&cert_pem), None)
+            .expect("updateSubcomponent failed.");
 
-            grant_key_nspace
-        })
+        grant_key_nspace
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
     // In grantee context load the key and try to perform crypto operation.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_UID),
-            Gid::from_raw(GRANTEE_GID),
-            move || {
-                let keystore2 = get_keystore_service();
-                perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
-            },
-        )
+    let grantee_fn = move || {
+        let keystore2 = get_keystore_service();
+        perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
 }
diff --git a/keystore2/tests/keystore2_client_list_entries_tests.rs b/keystore2/tests/keystore2_client_list_entries_tests.rs
index 539dac2..bb1d6cf 100644
--- a/keystore2/tests/keystore2_client_list_entries_tests.rs
+++ b/keystore2/tests/keystore2_client_list_entries_tests.rs
@@ -20,7 +20,7 @@
 use keystore2_test_utils::{
     get_keystore_service, key_generations, key_generations::Error, run_as, SecLevel,
 };
-use nix::unistd::{getuid, Gid, Uid};
+use nix::unistd::getuid;
 use rustutils::users::AID_USER_OFFSET;
 use std::collections::HashSet;
 use std::fmt::Write;
@@ -51,103 +51,97 @@
 ///    context. GRANT keys shouldn't be part of this list.
 #[test]
 fn keystore2_list_entries_success() {
-    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
     const USER_ID: u32 = 91;
     const APPLICATION_ID: u32 = 10006;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static GRANTEE_GID: u32 = GRANTEE_UID;
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
+    let gen_key_fn = || {
+        let sl = SecLevel::tee();
 
-            let alias = format!("list_entries_grant_key1_{}", getuid());
+        let alias = format!("list_entries_grant_key1_{}", getuid());
 
-            // Make sure there is no key exist with this `alias` in `SELINUX` domain and
-            // `SELINUX_SHELL_NAMESPACE` namespace.
-            if key_alias_exists(
-                &sl.keystore2,
-                Domain::SELINUX,
-                key_generations::SELINUX_SHELL_NAMESPACE,
-                alias.to_string(),
-            ) {
-                sl.keystore2
-                    .deleteKey(&KeyDescriptor {
-                        domain: Domain::SELINUX,
-                        nspace: key_generations::SELINUX_SHELL_NAMESPACE,
-                        alias: Some(alias.to_string()),
-                        blob: None,
-                    })
-                    .unwrap();
-            }
-
-            // Generate a key with above defined `alias`.
-            let key_metadata = key_generations::generate_ec_p256_signing_key(
-                &sl,
-                Domain::SELINUX,
-                key_generations::SELINUX_SHELL_NAMESPACE,
-                Some(alias.to_string()),
-                None,
-            )
-            .unwrap();
-
-            // Verify that above generated key entry is listed with domain SELINUX and
-            // namespace SELINUX_SHELL_NAMESPACE
-            assert!(key_alias_exists(
-                &sl.keystore2,
-                Domain::SELINUX,
-                key_generations::SELINUX_SHELL_NAMESPACE,
-                alias,
-            ));
-
-            // Grant a key with GET_INFO permission.
-            let access_vector = KeyPermission::GET_INFO.0;
+        // Make sure there is no key exist with this `alias` in `SELINUX` domain and
+        // `SELINUX_SHELL_NAMESPACE` namespace.
+        if key_alias_exists(
+            &sl.keystore2,
+            Domain::SELINUX,
+            key_generations::SELINUX_SHELL_NAMESPACE,
+            alias.to_string(),
+        ) {
             sl.keystore2
-                .grant(&key_metadata.key, GRANTEE_UID.try_into().unwrap(), access_vector)
+                .deleteKey(&KeyDescriptor {
+                    domain: Domain::SELINUX,
+                    nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+                    alias: Some(alias.to_string()),
+                    blob: None,
+                })
                 .unwrap();
-        })
+        }
+
+        // Generate a key with above defined `alias`.
+        let key_metadata = key_generations::generate_ec_p256_signing_key(
+            &sl,
+            Domain::SELINUX,
+            key_generations::SELINUX_SHELL_NAMESPACE,
+            Some(alias.to_string()),
+            None,
+        )
+        .unwrap();
+
+        // Verify that above generated key entry is listed with domain SELINUX and
+        // namespace SELINUX_SHELL_NAMESPACE
+        assert!(key_alias_exists(
+            &sl.keystore2,
+            Domain::SELINUX,
+            key_generations::SELINUX_SHELL_NAMESPACE,
+            alias,
+        ));
+
+        // Grant a key with GET_INFO permission.
+        let access_vector = KeyPermission::GET_INFO.0;
+        sl.keystore2
+            .grant(&key_metadata.key, GRANTEE_UID.try_into().unwrap(), access_vector)
+            .unwrap();
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_root(gen_key_fn) };
+
     // In user context validate list of key entries associated with it.
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_UID),
-            Gid::from_raw(GRANTEE_GID),
-            move || {
-                let sl = SecLevel::tee();
-                let alias = format!("list_entries_success_key{}", getuid());
+    let list_keys_fn = move || {
+        let sl = SecLevel::tee();
+        let alias = format!("list_entries_success_key{}", getuid());
 
-                let key_metadata = key_generations::generate_ec_p256_signing_key(
-                    &sl,
-                    Domain::APP,
-                    -1,
-                    Some(alias.to_string()),
-                    None,
-                )
-                .unwrap();
-
-                // Make sure there is only one key entry exist and that should be the same key
-                // generated in this user context. Granted key shouldn't be included in this list.
-                let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
-                assert_eq!(1, key_descriptors.len());
-
-                let key = key_descriptors.first().unwrap();
-                assert_eq!(key.alias, Some(alias));
-                assert_eq!(key.nspace, GRANTEE_UID.try_into().unwrap());
-                assert_eq!(key.domain, Domain::APP);
-
-                sl.keystore2.deleteKey(&key_metadata.key).unwrap();
-
-                let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
-                assert_eq!(0, key_descriptors.len());
-            },
+        let key_metadata = key_generations::generate_ec_p256_signing_key(
+            &sl,
+            Domain::APP,
+            -1,
+            Some(alias.to_string()),
+            None,
         )
+        .unwrap();
+
+        // Make sure there is only one existing key entry and that should be the same key
+        // generated in this user context. Granted key shouldn't be included in this list.
+        let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
+        assert_eq!(1, key_descriptors.len());
+
+        let key = key_descriptors.first().unwrap();
+        assert_eq!(key.alias, Some(alias));
+        assert_eq!(key.nspace, GRANTEE_UID.try_into().unwrap());
+        assert_eq!(key.domain, Domain::APP);
+
+        sl.keystore2.deleteKey(&key_metadata.key).unwrap();
+
+        let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
+        assert_eq!(0, key_descriptors.len());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, list_keys_fn) };
 }
 
 /// Try to list the key entries with domain SELINUX from user context where user doesn't possesses
@@ -157,20 +151,19 @@
 fn keystore2_list_entries_fails_perm_denied() {
     let auid = 91 * AID_USER_OFFSET + 10001;
     let agid = 91 * AID_USER_OFFSET + 10001;
-    static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+    let list_keys_fn = move || {
+        let keystore2 = get_keystore_service();
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
-            let keystore2 = get_keystore_service();
-
-            let result = key_generations::map_ks_error(
-                keystore2.listEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE),
-            );
-            assert!(result.is_err());
-            assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
-        })
+        let result = key_generations::map_ks_error(
+            keystore2.listEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE),
+        );
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(auid, agid, list_keys_fn) };
 }
 
 /// Try to list key entries with domain BLOB. Test should fail with error repose code
@@ -190,64 +183,63 @@
 /// of all the entries in the keystore.
 #[test]
 fn keystore2_list_entries_with_long_aliases_success() {
-    static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
     const USER_ID: u32 = 92;
     const APPLICATION_ID: u32 = 10002;
     static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static CLIENT_GID: u32 = CLIENT_UID;
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
-            let sl = SecLevel::tee();
+    let import_keys_fn = || {
+        let sl = SecLevel::tee();
 
-            // Make sure there are no keystore entries exist before adding new entries.
+        // Make sure there are no keystore entries exist before adding new entries.
+        let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
+        if !key_descriptors.is_empty() {
+            key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
+                delete_app_key(&sl.keystore2, &alias).unwrap();
+            });
+        }
+
+        let mut imported_key_aliases = HashSet::new();
+
+        // Import 100 keys with aliases of length 6000.
+        for count in 1..101 {
+            let mut alias = String::new();
+            write!(alias, "{}_{}", "X".repeat(6000), count).unwrap();
+            imported_key_aliases.insert(alias.clone());
+
+            let result = key_generations::import_aes_key(&sl, Domain::APP, -1, Some(alias));
+            assert!(result.is_ok());
+        }
+
+        // b/222287335 Limiting Keystore `listEntries` API to return subset of the Keystore
+        // entries to avoid running out of binder buffer space.
+        // To verify that all the imported key aliases are present in Keystore,
+        //  - get the list of entries from Keystore
+        //  - check whether the retrieved key entries list is a subset of imported key aliases
+        //  - delete this subset of keystore entries from Keystore as well as from imported
+        //    list of key aliases
+        //  - continue above steps till it cleanup all the imported keystore entries.
+        while !imported_key_aliases.is_empty() {
             let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
-            if !key_descriptors.is_empty() {
-                key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
-                    delete_app_key(&sl.keystore2, &alias).unwrap();
-                });
-            }
 
-            let mut imported_key_aliases = HashSet::new();
+            // Check retrieved key entries list is a subset of imported keys list.
+            assert!(key_descriptors
+                .iter()
+                .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
 
-            // Import 100 keys with aliases of length 6000.
-            for count in 1..101 {
-                let mut alias = String::new();
-                write!(alias, "{}_{}", "X".repeat(6000), count).unwrap();
-                imported_key_aliases.insert(alias.clone());
+            // Delete the listed key entries from Keystore as well as from imported keys list.
+            key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
+                delete_app_key(&sl.keystore2, &alias).unwrap();
+                assert!(imported_key_aliases.remove(&alias));
+            });
+        }
 
-                let result = key_generations::import_aes_key(&sl, Domain::APP, -1, Some(alias));
-                assert!(result.is_ok());
-            }
-
-            // b/222287335 Limiting Keystore `listEntries` API to return subset of the Keystore
-            // entries to avoid running out of binder buffer space.
-            // To verify that all the imported key aliases are present in Keystore,
-            //  - get the list of entries from Keystore
-            //  - check whether the retrieved key entries list is a subset of imported key aliases
-            //  - delete this subset of keystore entries from Keystore as well as from imported
-            //    list of key aliases
-            //  - continue above steps till it cleanup all the imported keystore entries.
-            while !imported_key_aliases.is_empty() {
-                let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
-
-                // Check retrieved key entries list is a subset of imported keys list.
-                assert!(key_descriptors
-                    .iter()
-                    .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
-
-                // Delete the listed key entries from Keystore as well as from imported keys list.
-                key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
-                    delete_app_key(&sl.keystore2, &alias).unwrap();
-                    assert!(imported_key_aliases.remove(&alias));
-                });
-            }
-
-            assert!(imported_key_aliases.is_empty());
-        })
+        assert!(imported_key_aliases.is_empty());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, import_keys_fn) };
 }
 
 /// Import large number of Keystore entries with long aliases such that the
@@ -255,58 +247,57 @@
 /// Try to list aliases of all the entries in the keystore using `listEntriesBatched` API.
 #[test]
 fn keystore2_list_entries_batched_with_long_aliases_success() {
-    static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
     const USER_ID: u32 = 92;
     const APPLICATION_ID: u32 = 10002;
     static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static CLIENT_GID: u32 = CLIENT_UID;
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
-            let sl = SecLevel::tee();
+    let import_keys_fn = || {
+        let sl = SecLevel::tee();
 
-            // Make sure there are no keystore entries exist before adding new entries.
-            delete_all_entries(&sl.keystore2);
+        // Make sure there are no keystore entries exist before adding new entries.
+        delete_all_entries(&sl.keystore2);
 
-            // Import 100 keys with aliases of length 6000.
-            let mut imported_key_aliases =
-                key_generations::import_aes_keys(&sl, "X".repeat(6000), 1..101).unwrap();
-            assert_eq!(
-                sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
-                100,
-                "Error while importing keys"
-            );
+        // Import 100 keys with aliases of length 6000.
+        let mut imported_key_aliases =
+            key_generations::import_aes_keys(&sl, "X".repeat(6000), 1..101).unwrap();
+        assert_eq!(
+            sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+            100,
+            "Error while importing keys"
+        );
 
-            let mut start_past_alias = None;
-            let mut alias;
-            while !imported_key_aliases.is_empty() {
-                let key_descriptors =
-                    sl.keystore2.listEntriesBatched(Domain::APP, -1, start_past_alias).unwrap();
+        let mut start_past_alias = None;
+        let mut alias;
+        while !imported_key_aliases.is_empty() {
+            let key_descriptors =
+                sl.keystore2.listEntriesBatched(Domain::APP, -1, start_past_alias).unwrap();
 
-                // Check retrieved key entries list is a subset of imported keys list.
-                assert!(key_descriptors
-                    .iter()
-                    .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+            // Check retrieved key entries list is a subset of imported keys list.
+            assert!(key_descriptors
+                .iter()
+                .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
 
-                alias = key_descriptors.last().unwrap().alias.clone().unwrap();
-                start_past_alias = Some(alias.as_ref());
-                // Delete the listed key entries from imported keys list.
-                key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
-                    assert!(imported_key_aliases.remove(&alias));
-                });
-            }
+            alias = key_descriptors.last().unwrap().alias.clone().unwrap();
+            start_past_alias = Some(alias.as_ref());
+            // Delete the listed key entries from imported keys list.
+            key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
+                assert!(imported_key_aliases.remove(&alias));
+            });
+        }
 
-            assert!(imported_key_aliases.is_empty());
-            delete_all_entries(&sl.keystore2);
-            assert_eq!(
-                sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
-                0,
-                "Error while doing cleanup"
-            );
-        })
+        assert!(imported_key_aliases.is_empty());
+        delete_all_entries(&sl.keystore2);
+        assert_eq!(
+            sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+            0,
+            "Error while doing cleanup"
+        );
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, import_keys_fn) };
 }
 
 /// Import keys from multiple processes with same user context and try to list the keystore entries
@@ -321,128 +312,127 @@
 ///    `startingPastAlias` as None. It should list all the keys imported in process-1 and process-2.
 #[test]
 fn keystore2_list_entries_batched_with_multi_procs_success() {
-    static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
     const USER_ID: u32 = 92;
     const APPLICATION_ID: u32 = 10002;
     static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static CLIENT_GID: u32 = CLIENT_UID;
     static ALIAS_PREFIX: &str = "key_test_batch_list";
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
-            let sl = SecLevel::tee();
+    let import_keys_fn = || {
+        let sl = SecLevel::tee();
 
-            // Make sure there are no keystore entries exist before adding new entries.
-            delete_all_entries(&sl.keystore2);
+        // Make sure there are no keystore entries exist before adding new entries.
+        delete_all_entries(&sl.keystore2);
 
-            // Import 3 keys with below aliases -
-            // [key_test_batch_list_1, key_test_batch_list_2, key_test_batch_list_3]
-            let imported_key_aliases =
-                key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 1..4).unwrap();
-            assert_eq!(
-                sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
-                3,
-                "Error while importing keys"
-            );
+        // Import 3 keys with below aliases -
+        // [key_test_batch_list_1, key_test_batch_list_2, key_test_batch_list_3]
+        let imported_key_aliases =
+            key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 1..4).unwrap();
+        assert_eq!(
+            sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+            3,
+            "Error while importing keys"
+        );
 
-            // List all entries in keystore for this user-id.
-            let key_descriptors = sl.keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
-            assert_eq!(key_descriptors.len(), 3);
+        // List all entries in keystore for this user-id.
+        let key_descriptors = sl.keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
+        assert_eq!(key_descriptors.len(), 3);
 
-            // Makes sure all listed aliases are matching with imported keys aliases.
-            assert!(key_descriptors
-                .iter()
-                .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
-        })
+        // Makes sure all listed aliases are matching with imported keys aliases.
+        assert!(key_descriptors
+            .iter()
+            .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
     };
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
-            let sl = SecLevel::tee();
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, import_keys_fn) };
 
-            // Import another 5 keys with below aliases -
-            // [ key_test_batch_list_4, key_test_batch_list_5, key_test_batch_list_6,
-            //   key_test_batch_list_7, key_test_batch_list_8 ]
-            let mut imported_key_aliases =
-                key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 4..9).unwrap();
+    let import_more_fn = || {
+        let sl = SecLevel::tee();
 
-            // Above context already 3 keys are imported, in this context 5 keys are imported,
-            // total 8 keystore entries are expected to be present in Keystore for this user-id.
-            assert_eq!(
-                sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
-                8,
-                "Error while importing keys"
-            );
+        // Import another 5 keys with below aliases -
+        // [ key_test_batch_list_4, key_test_batch_list_5, key_test_batch_list_6,
+        //   key_test_batch_list_7, key_test_batch_list_8 ]
+        let mut imported_key_aliases =
+            key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 4..9).unwrap();
 
-            // List keystore entries with `start_past_alias` as "key_test_batch_list_3".
-            // `listEntriesBatched` should list all the keystore entries with
-            // alias > "key_test_batch_list_3".
-            let key_descriptors = sl
-                .keystore2
-                .listEntriesBatched(Domain::APP, -1, Some("key_test_batch_list_3"))
-                .unwrap();
-            assert_eq!(key_descriptors.len(), 5);
+        // Above context already 3 keys are imported, in this context 5 keys are imported,
+        // total 8 keystore entries are expected to be present in Keystore for this user-id.
+        assert_eq!(
+            sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+            8,
+            "Error while importing keys"
+        );
 
-            // Make sure above listed aliases are matching with imported keys aliases.
-            assert!(key_descriptors
-                .iter()
-                .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+        // List keystore entries with `start_past_alias` as "key_test_batch_list_3".
+        // `listEntriesBatched` should list all the keystore entries with
+        // alias > "key_test_batch_list_3".
+        let key_descriptors = sl
+            .keystore2
+            .listEntriesBatched(Domain::APP, -1, Some("key_test_batch_list_3"))
+            .unwrap();
+        assert_eq!(key_descriptors.len(), 5);
 
-            // List all keystore entries with `start_past_alias` as `None`.
-            // `listEntriesBatched` should list all the keystore entries.
-            let key_descriptors = sl.keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
-            assert_eq!(key_descriptors.len(), 8);
+        // Make sure above listed aliases are matching with imported keys aliases.
+        assert!(key_descriptors
+            .iter()
+            .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
 
-            // Include previously imported keys aliases as well
-            imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_1");
-            imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_2");
-            imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_3");
+        // List all keystore entries with `start_past_alias` as `None`.
+        // `listEntriesBatched` should list all the keystore entries.
+        let key_descriptors = sl.keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
+        assert_eq!(key_descriptors.len(), 8);
 
-            // Make sure all the above listed aliases are matching with imported keys aliases.
-            assert!(key_descriptors
-                .iter()
-                .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+        // Include previously imported keys aliases as well
+        imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_1");
+        imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_2");
+        imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_3");
 
-            delete_all_entries(&sl.keystore2);
-            assert_eq!(
-                sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
-                0,
-                "Error while doing cleanup"
-            );
-        })
+        // Make sure all the above listed aliases are matching with imported keys aliases.
+        assert!(key_descriptors
+            .iter()
+            .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+
+        delete_all_entries(&sl.keystore2);
+        assert_eq!(
+            sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+            0,
+            "Error while doing cleanup"
+        );
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, import_more_fn) };
 }
 
 #[test]
 fn keystore2_list_entries_batched_with_empty_keystore_success() {
-    static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
     const USER_ID: u32 = 92;
     const APPLICATION_ID: u32 = 10002;
     static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static CLIENT_GID: u32 = CLIENT_UID;
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
-            let keystore2 = get_keystore_service();
+    let list_keys_fn = || {
+        let keystore2 = get_keystore_service();
 
-            // Make sure there are no keystore entries exist before adding new entries.
-            delete_all_entries(&keystore2);
+        // Make sure there are no keystore entries exist before adding new entries.
+        delete_all_entries(&keystore2);
 
-            // List all entries in keystore for this user-id, pass startingPastAlias = None
-            let key_descriptors = keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
-            assert_eq!(key_descriptors.len(), 0);
+        // List all entries in keystore for this user-id, pass startingPastAlias = None
+        let key_descriptors = keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
+        assert_eq!(key_descriptors.len(), 0);
 
-            // List all entries in keystore for this user-id, pass startingPastAlias = <random value>
-            let key_descriptors =
-                keystore2.listEntriesBatched(Domain::APP, -1, Some("startingPastAlias")).unwrap();
-            assert_eq!(key_descriptors.len(), 0);
-        })
+        // List all entries in keystore for this user-id, pass startingPastAlias = <random value>
+        let key_descriptors =
+            keystore2.listEntriesBatched(Domain::APP, -1, Some("startingPastAlias")).unwrap();
+        assert_eq!(key_descriptors.len(), 0);
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, list_keys_fn) };
 }
 
 /// Import a key with SELINUX as domain, list aliases using `listEntriesBatched`.
@@ -502,140 +492,135 @@
 
 #[test]
 fn keystore2_list_entries_batched_validate_count_and_order_success() {
-    static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
     const USER_ID: u32 = 92;
     const APPLICATION_ID: u32 = 10002;
     static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     static CLIENT_GID: u32 = CLIENT_UID;
     static ALIAS_PREFIX: &str = "key_test_batch_list";
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
-            let sl = SecLevel::tee();
+    let list_keys_fn = || {
+        let sl = SecLevel::tee();
 
-            // Make sure there are no keystore entries exist before adding new entries.
-            delete_all_entries(&sl.keystore2);
+        // Make sure there are no keystore entries exist before adding new entries.
+        delete_all_entries(&sl.keystore2);
 
-            // Import keys with below mentioned aliases -
-            // [
-            //   key_test_batch_list_1,
-            //   key_test_batch_list_2,
-            //   key_test_batch_list_3,
-            //   key_test_batch_list_4,
-            //   key_test_batch_list_5,
-            //   key_test_batch_list_10,
-            //   key_test_batch_list_11,
-            //   key_test_batch_list_12,
-            //   key_test_batch_list_21,
-            //   key_test_batch_list_22,
-            // ]
-            let _imported_key_aliases =
-                key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 1..6).unwrap();
-            assert_eq!(
-                sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
-                5,
-                "Error while importing keys"
-            );
-            let _imported_key_aliases =
-                key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 10..13).unwrap();
-            assert_eq!(
-                sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
-                8,
-                "Error while importing keys"
-            );
-            let _imported_key_aliases =
-                key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 21..23).unwrap();
-            assert_eq!(
-                sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
-                10,
-                "Error while importing keys"
-            );
+        // Import keys with below mentioned aliases -
+        // [
+        //   key_test_batch_list_1,
+        //   key_test_batch_list_2,
+        //   key_test_batch_list_3,
+        //   key_test_batch_list_4,
+        //   key_test_batch_list_5,
+        //   key_test_batch_list_10,
+        //   key_test_batch_list_11,
+        //   key_test_batch_list_12,
+        //   key_test_batch_list_21,
+        //   key_test_batch_list_22,
+        // ]
+        let _imported_key_aliases =
+            key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 1..6).unwrap();
+        assert_eq!(
+            sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+            5,
+            "Error while importing keys"
+        );
+        let _imported_key_aliases =
+            key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 10..13).unwrap();
+        assert_eq!(
+            sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+            8,
+            "Error while importing keys"
+        );
+        let _imported_key_aliases =
+            key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 21..23).unwrap();
+        assert_eq!(
+            sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+            10,
+            "Error while importing keys"
+        );
 
-            // List the aliases using given `startingPastAlias` and verify the listed
-            // aliases with the expected list of aliases.
-            verify_aliases(
-                &sl.keystore2,
-                Some(format!("{}{}", ALIAS_PREFIX, "_5").as_str()),
-                vec![],
-            );
+        // List the aliases using given `startingPastAlias` and verify the listed
+        // aliases with the expected list of aliases.
+        verify_aliases(&sl.keystore2, Some(format!("{}{}", ALIAS_PREFIX, "_5").as_str()), vec![]);
 
-            verify_aliases(
-                &sl.keystore2,
-                Some(format!("{}{}", ALIAS_PREFIX, "_4").as_str()),
-                vec![ALIAS_PREFIX.to_owned() + "_5"],
-            );
+        verify_aliases(
+            &sl.keystore2,
+            Some(format!("{}{}", ALIAS_PREFIX, "_4").as_str()),
+            vec![ALIAS_PREFIX.to_owned() + "_5"],
+        );
 
-            verify_aliases(
-                &sl.keystore2,
-                Some(format!("{}{}", ALIAS_PREFIX, "_3").as_str()),
-                vec![ALIAS_PREFIX.to_owned() + "_4", ALIAS_PREFIX.to_owned() + "_5"],
-            );
+        verify_aliases(
+            &sl.keystore2,
+            Some(format!("{}{}", ALIAS_PREFIX, "_3").as_str()),
+            vec![ALIAS_PREFIX.to_owned() + "_4", ALIAS_PREFIX.to_owned() + "_5"],
+        );
 
-            verify_aliases(
-                &sl.keystore2,
-                Some(format!("{}{}", ALIAS_PREFIX, "_2").as_str()),
-                vec![
-                    ALIAS_PREFIX.to_owned() + "_21",
-                    ALIAS_PREFIX.to_owned() + "_22",
-                    ALIAS_PREFIX.to_owned() + "_3",
-                    ALIAS_PREFIX.to_owned() + "_4",
-                    ALIAS_PREFIX.to_owned() + "_5",
-                ],
-            );
+        verify_aliases(
+            &sl.keystore2,
+            Some(format!("{}{}", ALIAS_PREFIX, "_2").as_str()),
+            vec![
+                ALIAS_PREFIX.to_owned() + "_21",
+                ALIAS_PREFIX.to_owned() + "_22",
+                ALIAS_PREFIX.to_owned() + "_3",
+                ALIAS_PREFIX.to_owned() + "_4",
+                ALIAS_PREFIX.to_owned() + "_5",
+            ],
+        );
 
-            verify_aliases(
-                &sl.keystore2,
-                Some(format!("{}{}", ALIAS_PREFIX, "_1").as_str()),
-                vec![
-                    ALIAS_PREFIX.to_owned() + "_10",
-                    ALIAS_PREFIX.to_owned() + "_11",
-                    ALIAS_PREFIX.to_owned() + "_12",
-                    ALIAS_PREFIX.to_owned() + "_2",
-                    ALIAS_PREFIX.to_owned() + "_21",
-                    ALIAS_PREFIX.to_owned() + "_22",
-                    ALIAS_PREFIX.to_owned() + "_3",
-                    ALIAS_PREFIX.to_owned() + "_4",
-                    ALIAS_PREFIX.to_owned() + "_5",
-                ],
-            );
+        verify_aliases(
+            &sl.keystore2,
+            Some(format!("{}{}", ALIAS_PREFIX, "_1").as_str()),
+            vec![
+                ALIAS_PREFIX.to_owned() + "_10",
+                ALIAS_PREFIX.to_owned() + "_11",
+                ALIAS_PREFIX.to_owned() + "_12",
+                ALIAS_PREFIX.to_owned() + "_2",
+                ALIAS_PREFIX.to_owned() + "_21",
+                ALIAS_PREFIX.to_owned() + "_22",
+                ALIAS_PREFIX.to_owned() + "_3",
+                ALIAS_PREFIX.to_owned() + "_4",
+                ALIAS_PREFIX.to_owned() + "_5",
+            ],
+        );
 
-            verify_aliases(
-                &sl.keystore2,
-                Some(ALIAS_PREFIX),
-                vec![
-                    ALIAS_PREFIX.to_owned() + "_1",
-                    ALIAS_PREFIX.to_owned() + "_10",
-                    ALIAS_PREFIX.to_owned() + "_11",
-                    ALIAS_PREFIX.to_owned() + "_12",
-                    ALIAS_PREFIX.to_owned() + "_2",
-                    ALIAS_PREFIX.to_owned() + "_21",
-                    ALIAS_PREFIX.to_owned() + "_22",
-                    ALIAS_PREFIX.to_owned() + "_3",
-                    ALIAS_PREFIX.to_owned() + "_4",
-                    ALIAS_PREFIX.to_owned() + "_5",
-                ],
-            );
+        verify_aliases(
+            &sl.keystore2,
+            Some(ALIAS_PREFIX),
+            vec![
+                ALIAS_PREFIX.to_owned() + "_1",
+                ALIAS_PREFIX.to_owned() + "_10",
+                ALIAS_PREFIX.to_owned() + "_11",
+                ALIAS_PREFIX.to_owned() + "_12",
+                ALIAS_PREFIX.to_owned() + "_2",
+                ALIAS_PREFIX.to_owned() + "_21",
+                ALIAS_PREFIX.to_owned() + "_22",
+                ALIAS_PREFIX.to_owned() + "_3",
+                ALIAS_PREFIX.to_owned() + "_4",
+                ALIAS_PREFIX.to_owned() + "_5",
+            ],
+        );
 
-            verify_aliases(
-                &sl.keystore2,
-                None,
-                vec![
-                    ALIAS_PREFIX.to_owned() + "_1",
-                    ALIAS_PREFIX.to_owned() + "_10",
-                    ALIAS_PREFIX.to_owned() + "_11",
-                    ALIAS_PREFIX.to_owned() + "_12",
-                    ALIAS_PREFIX.to_owned() + "_2",
-                    ALIAS_PREFIX.to_owned() + "_21",
-                    ALIAS_PREFIX.to_owned() + "_22",
-                    ALIAS_PREFIX.to_owned() + "_3",
-                    ALIAS_PREFIX.to_owned() + "_4",
-                    ALIAS_PREFIX.to_owned() + "_5",
-                ],
-            );
-        })
+        verify_aliases(
+            &sl.keystore2,
+            None,
+            vec![
+                ALIAS_PREFIX.to_owned() + "_1",
+                ALIAS_PREFIX.to_owned() + "_10",
+                ALIAS_PREFIX.to_owned() + "_11",
+                ALIAS_PREFIX.to_owned() + "_12",
+                ALIAS_PREFIX.to_owned() + "_2",
+                ALIAS_PREFIX.to_owned() + "_21",
+                ALIAS_PREFIX.to_owned() + "_22",
+                ALIAS_PREFIX.to_owned() + "_3",
+                ALIAS_PREFIX.to_owned() + "_4",
+                ALIAS_PREFIX.to_owned() + "_5",
+            ],
+        );
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, list_keys_fn) };
 }
 
 /// Try to list the key entries with domain SELINUX from user context where user doesn't possesses
@@ -645,22 +630,21 @@
 fn keystore2_list_entries_batched_fails_perm_denied() {
     let auid = 91 * AID_USER_OFFSET + 10001;
     let agid = 91 * AID_USER_OFFSET + 10001;
-    static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+    let list_keys_fn = move || {
+        let keystore2 = get_keystore_service();
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
-            let keystore2 = get_keystore_service();
-
-            let result = key_generations::map_ks_error(keystore2.listEntriesBatched(
-                Domain::SELINUX,
-                key_generations::SELINUX_SHELL_NAMESPACE,
-                None,
-            ));
-            assert!(result.is_err());
-            assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
-        })
+        let result = key_generations::map_ks_error(keystore2.listEntriesBatched(
+            Domain::SELINUX,
+            key_generations::SELINUX_SHELL_NAMESPACE,
+            None,
+        ));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(auid, agid, list_keys_fn) };
 }
 
 /// Try to list key entries with domain BLOB. Test should fail with error response code
@@ -685,21 +669,19 @@
 fn keystore2_get_number_of_entries_fails_perm_denied() {
     let auid = 91 * AID_USER_OFFSET + 10001;
     let agid = 91 * AID_USER_OFFSET + 10001;
-    static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+    let get_num_fn = move || {
+        let keystore2 = get_keystore_service();
 
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
-            let keystore2 = get_keystore_service();
-
-            let result = key_generations::map_ks_error(
-                keystore2
-                    .getNumberOfEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE),
-            );
-            assert!(result.is_err());
-            assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
-        })
+        let result = key_generations::map_ks_error(
+            keystore2.getNumberOfEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE),
+        );
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(auid, agid, get_num_fn) };
 }
 
 /// Try to get number of key entries with domain BLOB. Test should fail with error response code
diff --git a/keystore2/tests/keystore2_client_operation_tests.rs b/keystore2/tests/keystore2_client_operation_tests.rs
index 5f640ef..1f8396e 100644
--- a/keystore2/tests/keystore2_client_operation_tests.rs
+++ b/keystore2/tests/keystore2_client_operation_tests.rs
@@ -40,7 +40,8 @@
 ///
 /// # Safety
 ///
-/// Must be called from a process with no other threads.
+/// Must only be called from a single-threaded process (e.g. as enforced by `AndroidTest.xml`
+/// setting `--test-threads=1`).
 pub unsafe fn create_operations(
     target_ctx: &'static str,
     forced_op: ForcedOp,
@@ -50,7 +51,7 @@
     let base_gid = 99 * AID_USER_OFFSET + 10001;
     let base_uid = 99 * AID_USER_OFFSET + 10001;
     (0..max_ops)
-        // SAFETY: The caller guarantees that there are no other threads.
+        // Safety: The caller guarantees that there are no other threads.
         .map(|i| unsafe {
             execute_op_run_as_child(
                 target_ctx,
@@ -93,7 +94,8 @@
     const MAX_OPS: i32 = 100;
     static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
 
-    // SAFETY: The test is run in a separate process with no other threads.
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
     let mut child_handles = unsafe { create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS) };
 
     // Wait until all child procs notifies us to continue,
@@ -127,7 +129,8 @@
     static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
 
     // Create regular operations.
-    // SAFETY: The test is run in a separate process with no other threads.
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
     let mut child_handles = unsafe { create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS) };
 
     // Wait until all child procs notifies us to continue, so that there are enough
@@ -139,28 +142,31 @@
     // Create a forced operation.
     let auid = 99 * AID_USER_OFFSET + 10604;
     let agid = 99 * AID_USER_OFFSET + 10604;
-    // SAFETY: The test is run in a separate process with no other threads.
+    let force_op_fn = move || {
+        let alias = format!("ks_prune_forced_op_key_{}", getuid());
+
+        // To make room for this forced op, system should be able to prune one of the
+        // above created regular operations and create a slot for this forced operation
+        // successfully.
+        create_signing_operation(
+            ForcedOp(true),
+            KeyPurpose::SIGN,
+            Digest::SHA_2_256,
+            Domain::SELINUX,
+            100,
+            Some(alias),
+        )
+        .expect("Client failed to create forced operation after BACKEND_BUSY state.");
+    };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
     unsafe {
         run_as::run_as(
             key_generations::TARGET_VOLD_CTX,
             Uid::from_raw(auid),
             Gid::from_raw(agid),
-            move || {
-                let alias = format!("ks_prune_forced_op_key_{}", getuid());
-
-                // To make room for this forced op, system should be able to prune one of the
-                // above created regular operations and create a slot for this forced operation
-                // successfully.
-                create_signing_operation(
-                    ForcedOp(true),
-                    KeyPurpose::SIGN,
-                    Digest::SHA_2_256,
-                    Domain::SELINUX,
-                    100,
-                    Some(alias),
-                )
-                .expect("Client failed to create forced operation after BACKEND_BUSY state.");
-            },
+            force_op_fn,
         );
     };
 
@@ -212,7 +218,9 @@
     // Create initial forced operation in a child process
     // and wait for the parent to notify to perform operation.
     let alias = format!("ks_forced_op_key_{}", getuid());
-    // SAFETY: The test is run in a separate process with no other threads.
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
     let mut first_op_handle = unsafe {
         execute_op_run_as_child(
             key_generations::TARGET_SU_CTX,
@@ -231,7 +239,8 @@
 
     // Create MAX_OPS number of forced operations.
     let mut child_handles =
-    // SAFETY: The test is run in a separate process with no other threads.
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
         unsafe { create_operations(key_generations::TARGET_SU_CTX, ForcedOp(true), MAX_OPS) };
 
     // Wait until all child procs notifies us to continue, so that  there are enough operations
@@ -295,7 +304,9 @@
     // Create an operation in an untrusted_app context. Wait until the parent notifies to continue.
     // Once the parent notifies, this operation is expected to be completed successfully.
     let alias = format!("ks_reg_op_key_{}", getuid());
-    // SAFETY: The test is run in a separate process with no other threads.
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
     let mut child_handle = unsafe {
         execute_op_run_as_child(
             TARGET_CTX,
@@ -393,21 +404,24 @@
     let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
 
     for context in TARGET_CTXS.iter() {
-        // SAFETY: The test is run in a separate process with no other threads.
+        let forced_op_fn = move || {
+            let alias = format!("ks_app_forced_op_test_key_{}", getuid());
+            let result = key_generations::map_ks_error(create_signing_operation(
+                ForcedOp(true),
+                KeyPurpose::SIGN,
+                Digest::SHA_2_256,
+                Domain::APP,
+                -1,
+                Some(alias),
+            ));
+            assert!(result.is_err());
+            assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+        };
+
+        // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+        // `--test-threads=1`), and nothing yet done with binder.
         unsafe {
-            run_as::run_as(context, Uid::from_raw(uid), Gid::from_raw(gid), move || {
-                let alias = format!("ks_app_forced_op_test_key_{}", getuid());
-                let result = key_generations::map_ks_error(create_signing_operation(
-                    ForcedOp(true),
-                    KeyPurpose::SIGN,
-                    Digest::SHA_2_256,
-                    Domain::APP,
-                    -1,
-                    Some(alias),
-                ));
-                assert!(result.is_err());
-                assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
-            });
+            run_as::run_as(context, Uid::from_raw(uid), Gid::from_raw(gid), forced_op_fn);
         }
     }
 }
@@ -416,27 +430,29 @@
 /// Should be able to create forced operation with `vold` context successfully.
 #[test]
 fn keystore2_forced_op_success_test() {
-    static TARGET_CTX: &str = "u:r:vold:s0";
+    static TARGET_VOLD_CTX: &str = "u:r:vold:s0";
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10601;
 
     let uid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
     let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+    let forced_op_fn = move || {
+        let alias = format!("ks_vold_forced_op_key_{}", getuid());
+        create_signing_operation(
+            ForcedOp(true),
+            KeyPurpose::SIGN,
+            Digest::SHA_2_256,
+            Domain::SELINUX,
+            key_generations::SELINUX_VOLD_NAMESPACE,
+            Some(alias),
+        )
+        .expect("Client with vold context failed to create forced operation.");
+    };
 
-    // SAFETY: The test is run in a separate process with no other threads.
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
     unsafe {
-        run_as::run_as(TARGET_CTX, Uid::from_raw(uid), Gid::from_raw(gid), move || {
-            let alias = format!("ks_vold_forced_op_key_{}", getuid());
-            create_signing_operation(
-                ForcedOp(true),
-                KeyPurpose::SIGN,
-                Digest::SHA_2_256,
-                Domain::SELINUX,
-                key_generations::SELINUX_VOLD_NAMESPACE,
-                Some(alias),
-            )
-            .expect("Client with vold context failed to create forced operation.");
-        });
+        run_as::run_as(TARGET_VOLD_CTX, Uid::from_raw(uid), Gid::from_raw(gid), forced_op_fn);
     }
 }
 
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index 9029b97..831fc85 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -25,7 +25,11 @@
 };
 use binder::wait_for_interface;
 use keystore2_test_utils::{
-    authorizations, key_generations, key_generations::Error, run_as, SecLevel,
+    authorizations, key_generations,
+    key_generations::Error,
+    run_as,
+    run_as::{ChannelReader, ChannelWriter},
+    SecLevel,
 };
 use nix::unistd::{Gid, Uid};
 use openssl::bn::BigNum;
@@ -305,7 +309,8 @@
 ///
 /// # Safety
 ///
-/// Must only be called from a single-threaded process.
+/// Must only be called from a single-threaded process (e.g. as enforced by `AndroidTest.xml`
+/// setting `--test-threads=1`).
 pub unsafe fn execute_op_run_as_child(
     target_ctx: &'static str,
     domain: Domain,
@@ -315,41 +320,44 @@
     agid: Gid,
     forced_op: ForcedOp,
 ) -> run_as::ChildHandle<TestOutcome, BarrierReached> {
-    // SAFETY: The caller guarantees that there are no other threads.
-    unsafe {
-        run_as::run_as_child(target_ctx, auid, agid, move |reader, writer| {
-            let result = key_generations::map_ks_error(create_signing_operation(
-                forced_op,
-                KeyPurpose::SIGN,
-                Digest::SHA_2_256,
-                domain,
-                nspace,
-                alias,
-            ));
+    let child_fn = move |reader: &mut ChannelReader<BarrierReached>,
+                         writer: &mut ChannelWriter<BarrierReached>| {
+        let result = key_generations::map_ks_error(create_signing_operation(
+            forced_op,
+            KeyPurpose::SIGN,
+            Digest::SHA_2_256,
+            domain,
+            nspace,
+            alias,
+        ));
 
-            // Let the parent know that an operation has been started, then
-            // wait until the parent notifies us to continue, so the operation
-            // remains open.
-            writer.send(&BarrierReached {});
-            reader.recv();
+        // Let the parent know that an operation has been started, then
+        // wait until the parent notifies us to continue, so the operation
+        // remains open.
+        writer.send(&BarrierReached {});
+        reader.recv();
 
-            // Continue performing the operation after parent notifies.
-            match &result {
-                Ok(CreateOperationResponse { iOperation: Some(op), .. }) => {
-                    match key_generations::map_ks_error(perform_sample_sign_operation(op)) {
-                        Ok(()) => TestOutcome::Ok,
-                        Err(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE)) => {
-                            TestOutcome::InvalidHandle
-                        }
-                        Err(e) => panic!("Error in performing op: {:#?}", e),
+        // Continue performing the operation after parent notifies.
+        match &result {
+            Ok(CreateOperationResponse { iOperation: Some(op), .. }) => {
+                match key_generations::map_ks_error(perform_sample_sign_operation(op)) {
+                    Ok(()) => TestOutcome::Ok,
+                    Err(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE)) => {
+                        TestOutcome::InvalidHandle
                     }
+                    Err(e) => panic!("Error in performing op: {:#?}", e),
                 }
-                Ok(_) => TestOutcome::OtherErr,
-                Err(Error::Rc(ResponseCode::BACKEND_BUSY)) => TestOutcome::BackendBusy,
-                _ => TestOutcome::OtherErr,
             }
-        })
-        .expect("Failed to create an operation.")
+            Ok(_) => TestOutcome::OtherErr,
+            Err(Error::Rc(ResponseCode::BACKEND_BUSY)) => TestOutcome::BackendBusy,
+            _ => TestOutcome::OtherErr,
+        }
+    };
+
+    // Safety: The caller guarantees that there are no other threads.
+    unsafe {
+        run_as::run_as_child(target_ctx, auid, agid, child_fn)
+            .expect("Failed to create an operation.")
     }
 }
 
diff --git a/keystore2/tests/keystore2_client_update_subcomponent_tests.rs b/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
index e25e52a..0e38298 100644
--- a/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
+++ b/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
@@ -22,7 +22,7 @@
 use keystore2_test_utils::{
     get_keystore_service, key_generations, key_generations::Error, run_as, SecLevel,
 };
-use nix::unistd::{getuid, Gid, Uid};
+use nix::unistd::getuid;
 use rustutils::users::AID_USER_OFFSET;
 
 /// Generate a key and update its public certificate and certificate chain. Test should be able to
@@ -153,9 +153,6 @@
 /// permissions, test should be able to update public certificate and cert-chain successfully.
 #[test]
 fn keystore2_update_subcomponent_fails_permission_denied() {
-    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
-    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
     const USER_ID_1: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
@@ -166,117 +163,102 @@
     static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
 
     // Generate a key and grant it to multiple users with different access permissions.
-    // SAFETY: The test is run in a separate process with no other threads.
-    let mut granted_keys = unsafe {
-        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            let sl = SecLevel::tee();
-            let alias = format!("ks_update_subcompo_test_1_{}", getuid());
-            let mut granted_keys = Vec::new();
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let alias = format!("ks_update_subcompo_test_1_{}", getuid());
+        let mut granted_keys = Vec::new();
 
-            let key_metadata = key_generations::generate_ec_p256_signing_key(
-                &sl,
-                Domain::APP,
-                -1,
-                Some(alias),
-                None,
-            )
+        let key_metadata =
+            key_generations::generate_ec_p256_signing_key(&sl, Domain::APP, -1, Some(alias), None)
+                .unwrap();
+
+        // Grant a key without update permission.
+        let access_vector = KeyPermission::GET_INFO.0;
+        let granted_key = sl
+            .keystore2
+            .grant(&key_metadata.key, GRANTEE_1_UID.try_into().unwrap(), access_vector)
             .unwrap();
+        assert_eq!(granted_key.domain, Domain::GRANT);
+        granted_keys.push(granted_key.nspace);
 
-            // Grant a key without update permission.
-            let access_vector = KeyPermission::GET_INFO.0;
-            let granted_key = sl
-                .keystore2
-                .grant(&key_metadata.key, GRANTEE_1_UID.try_into().unwrap(), access_vector)
-                .unwrap();
-            assert_eq!(granted_key.domain, Domain::GRANT);
-            granted_keys.push(granted_key.nspace);
+        // Grant a key with update permission.
+        let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::UPDATE.0;
+        let granted_key = sl
+            .keystore2
+            .grant(&key_metadata.key, GRANTEE_2_UID.try_into().unwrap(), access_vector)
+            .unwrap();
+        assert_eq!(granted_key.domain, Domain::GRANT);
+        granted_keys.push(granted_key.nspace);
 
-            // Grant a key with update permission.
-            let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::UPDATE.0;
-            let granted_key = sl
-                .keystore2
-                .grant(&key_metadata.key, GRANTEE_2_UID.try_into().unwrap(), access_vector)
-                .unwrap();
-            assert_eq!(granted_key.domain, Domain::GRANT);
-            granted_keys.push(granted_key.nspace);
-
-            granted_keys
-        })
+        granted_keys
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let mut granted_keys = unsafe { run_as::run_as_root(grantor_fn) };
+
     // Grantee context, try to update the key public certs, permission denied error is expected.
     let granted_key1_nspace = granted_keys.remove(0);
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_1_UID),
-            Gid::from_raw(GRANTEE_1_GID),
-            move || {
-                let keystore2 = get_keystore_service();
+    let grantee1_fn = move || {
+        let keystore2 = get_keystore_service();
 
-                let other_cert: [u8; 32] = [123; 32];
-                let other_cert_chain: [u8; 32] = [12; 32];
+        let other_cert: [u8; 32] = [123; 32];
+        let other_cert_chain: [u8; 32] = [12; 32];
 
-                let result = key_generations::map_ks_error(keystore2.updateSubcomponent(
-                    &KeyDescriptor {
-                        domain: Domain::GRANT,
-                        nspace: granted_key1_nspace,
-                        alias: None,
-                        blob: None,
-                    },
-                    Some(&other_cert),
-                    Some(&other_cert_chain),
-                ));
-                assert!(result.is_err());
-                assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+        let result = key_generations::map_ks_error(keystore2.updateSubcomponent(
+            &KeyDescriptor {
+                domain: Domain::GRANT,
+                nspace: granted_key1_nspace,
+                alias: None,
+                blob: None,
             },
-        )
+            Some(&other_cert),
+            Some(&other_cert_chain),
+        ));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_1_UID, GRANTEE_1_GID, grantee1_fn) };
+
     // Grantee context, update granted key public certs. Update should happen successfully.
     let granted_key2_nspace = granted_keys.remove(0);
-    // SAFETY: The test is run in a separate process with no other threads.
-    unsafe {
-        run_as::run_as(
-            GRANTEE_CTX,
-            Uid::from_raw(GRANTEE_2_UID),
-            Gid::from_raw(GRANTEE_2_GID),
-            move || {
-                let keystore2 = get_keystore_service();
+    let grantee2_fn = move || {
+        let keystore2 = get_keystore_service();
 
-                let other_cert: [u8; 32] = [124; 32];
-                let other_cert_chain: [u8; 32] = [13; 32];
+        let other_cert: [u8; 32] = [124; 32];
+        let other_cert_chain: [u8; 32] = [13; 32];
 
-                keystore2
-                    .updateSubcomponent(
-                        &KeyDescriptor {
-                            domain: Domain::GRANT,
-                            nspace: granted_key2_nspace,
-                            alias: None,
-                            blob: None,
-                        },
-                        Some(&other_cert),
-                        Some(&other_cert_chain),
-                    )
-                    .expect("updateSubcomponent should have succeeded.");
+        keystore2
+            .updateSubcomponent(
+                &KeyDescriptor {
+                    domain: Domain::GRANT,
+                    nspace: granted_key2_nspace,
+                    alias: None,
+                    blob: None,
+                },
+                Some(&other_cert),
+                Some(&other_cert_chain),
+            )
+            .expect("updateSubcomponent should have succeeded.");
 
-                let key_entry_response = keystore2
-                    .getKeyEntry(&KeyDescriptor {
-                        domain: Domain::GRANT,
-                        nspace: granted_key2_nspace,
-                        alias: None,
-                        blob: None,
-                    })
-                    .unwrap();
-                assert_eq!(Some(other_cert.to_vec()), key_entry_response.metadata.certificate);
-                assert_eq!(
-                    Some(other_cert_chain.to_vec()),
-                    key_entry_response.metadata.certificateChain
-                );
-            },
-        )
+        let key_entry_response = keystore2
+            .getKeyEntry(&KeyDescriptor {
+                domain: Domain::GRANT,
+                nspace: granted_key2_nspace,
+                alias: None,
+                blob: None,
+            })
+            .unwrap();
+        assert_eq!(Some(other_cert.to_vec()), key_entry_response.metadata.certificate);
+        assert_eq!(Some(other_cert_chain.to_vec()), key_entry_response.metadata.certificateChain);
     };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(GRANTEE_2_UID, GRANTEE_2_GID, grantee2_fn) };
 }
 
 #[test]
diff --git a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
index 11a4c0b..d71f463 100644
--- a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
+++ b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
@@ -27,7 +27,7 @@
 use keystore2::utils::AesGcm;
 use keystore2_crypto::{Password, ZVec};
 use keystore2_test_utils::{get_keystore_service, key_generations, run_as, SecLevel};
-use nix::unistd::{getuid, Gid, Uid};
+use nix::unistd::getuid;
 use rustutils::users::AID_USER_OFFSET;
 use serde::{Deserialize, Serialize};
 use std::ops::Deref;
@@ -128,8 +128,6 @@
 fn keystore2_encrypted_characteristics() -> anyhow::Result<()> {
     let auid = 99 * AID_USER_OFFSET + 10001;
     let agid = 99 * AID_USER_OFFSET + 10001;
-    static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-    static TARGET_SU_CTX: &str = "u:r:su:s0";
 
     // Cleanup user directory if it exists
     let path_buf = PathBuf::from("/data/misc/keystore/user_99");
@@ -137,205 +135,202 @@
         std::fs::remove_dir_all(path_buf.as_path()).unwrap();
     }
 
-    // Safety: run_as must be called from a single threaded process.
-    // This device test is run as a separate single threaded process.
-    let mut gen_key_result = unsafe {
-        run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            // Remove user if already exist.
-            let maint_service = get_maintenance();
-            match maint_service.onUserRemoved(99) {
-                Ok(_) => {
-                    println!("User was existed, deleted successfully");
-                }
-                Err(e) => {
-                    println!("onUserRemoved error: {:#?}", e);
-                }
+    let gen_key_fn = || {
+        // Remove user if already exist.
+        let maint_service = get_maintenance();
+        match maint_service.onUserRemoved(99) {
+            Ok(_) => {
+                println!("User did exist, deleted successfully");
             }
-            let sl = SecLevel::tee();
+            Err(e) => {
+                println!("onUserRemoved error: {:#?}", e);
+            }
+        }
+        let sl = SecLevel::tee();
 
-            // Generate Key BLOB and prepare legacy keystore blob files.
-            let att_challenge: Option<&[u8]> = if rkp_only() { None } else { Some(b"foo") };
-            let key_metadata = key_generations::generate_ec_p256_signing_key(
-                &sl,
-                Domain::BLOB,
-                SELINUX_SHELL_NAMESPACE,
-                None,
-                att_challenge,
+        // Generate Key BLOB and prepare legacy keystore blob files.
+        let att_challenge: Option<&[u8]> = if rkp_only() { None } else { Some(b"foo") };
+        let key_metadata = key_generations::generate_ec_p256_signing_key(
+            &sl,
+            Domain::BLOB,
+            SELINUX_SHELL_NAMESPACE,
+            None,
+            att_challenge,
+        )
+        .expect("Failed to generate key blob");
+
+        // Create keystore file layout for user_99.
+        let pw: Password = PASSWORD.into();
+        let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
+        let super_key =
+            TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap());
+
+        let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+        if !path_buf.as_path().is_dir() {
+            std::fs::create_dir(path_buf.as_path()).unwrap();
+        }
+        path_buf.push(".masterkey");
+        if !path_buf.as_path().is_file() {
+            std::fs::write(path_buf.as_path(), SUPERKEY).unwrap();
+        }
+
+        let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+        path_buf.push("9910001_USRPKEY_authbound");
+        if !path_buf.as_path().is_file() {
+            make_encrypted_key_file(
+                path_buf.as_path(),
+                &super_key,
+                &key_metadata.key.blob.unwrap(),
             )
-            .expect("Failed to generate key blob");
+            .unwrap();
+        }
 
-            // Create keystore file layout for user_99.
-            let pw: Password = PASSWORD.into();
-            let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
-            let super_key =
-                TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap());
-
-            let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
-            if !path_buf.as_path().is_dir() {
-                std::fs::create_dir(path_buf.as_path()).unwrap();
-            }
-            path_buf.push(".masterkey");
-            if !path_buf.as_path().is_file() {
-                std::fs::write(path_buf.as_path(), SUPERKEY).unwrap();
-            }
-
-            let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
-            path_buf.push("9910001_USRPKEY_authbound");
-            if !path_buf.as_path().is_file() {
-                make_encrypted_key_file(
-                    path_buf.as_path(),
-                    &super_key,
-                    &key_metadata.key.blob.unwrap(),
-                )
+        let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+        path_buf.push(".9910001_chr_USRPKEY_authbound");
+        if !path_buf.as_path().is_file() {
+            make_encrypted_characteristics_file(path_buf.as_path(), &super_key, KEY_PARAMETERS)
                 .unwrap();
-            }
+        }
 
+        let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+        path_buf.push("9910001_USRCERT_authbound");
+        if !path_buf.as_path().is_file() {
+            make_cert_blob_file(path_buf.as_path(), key_metadata.certificate.as_ref().unwrap())
+                .unwrap();
+        }
+
+        if let Some(chain) = key_metadata.certificateChain.as_ref() {
             let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
-            path_buf.push(".9910001_chr_USRPKEY_authbound");
+            path_buf.push("9910001_CACERT_authbound");
             if !path_buf.as_path().is_file() {
-                make_encrypted_characteristics_file(path_buf.as_path(), &super_key, KEY_PARAMETERS)
-                    .unwrap();
+                make_cert_blob_file(path_buf.as_path(), chain).unwrap();
             }
+        }
 
-            let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
-            path_buf.push("9910001_USRCERT_authbound");
-            if !path_buf.as_path().is_file() {
-                make_cert_blob_file(path_buf.as_path(), key_metadata.certificate.as_ref().unwrap())
-                    .unwrap();
+        // Keystore2 disables the legacy importer when it finds the legacy database empty.
+        // However, if the device boots with an empty legacy database, the optimization kicks in
+        // and keystore2 never checks the legacy file system layout.
+        // So, restart keystore2 service to detect populated legacy database.
+        keystore2_restart_service();
+
+        let auth_service = get_authorization();
+        match auth_service.onDeviceUnlocked(99, Some(PASSWORD)) {
+            Ok(result) => {
+                println!("Unlock Result: {:?}", result);
             }
-
-            if let Some(chain) = key_metadata.certificateChain.as_ref() {
-                let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
-                path_buf.push("9910001_CACERT_authbound");
-                if !path_buf.as_path().is_file() {
-                    make_cert_blob_file(path_buf.as_path(), chain).unwrap();
-                }
+            Err(e) => {
+                panic!("Unlock should have succeeded: {:?}", e);
             }
+        }
 
-            // Keystore2 disables the legacy importer when it finds the legacy database empty.
-            // However, if the device boots with an empty legacy database, the optimization kicks in
-            // and keystore2 never checks the legacy file system layout.
-            // So, restart keystore2 service to detect populated legacy database.
-            keystore2_restart_service();
+        let mut key_params: Vec<KsKeyparameter> = Vec::new();
+        for param in key_metadata.authorizations {
+            let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+            key_params.push(key_param);
+        }
 
-            let auth_service = get_authorization();
-            match auth_service.onDeviceUnlocked(99, Some(PASSWORD)) {
-                Ok(result) => {
-                    println!("Unlock Result: {:?}", result);
-                }
-                Err(e) => {
-                    panic!("Unlock should have succeeded: {:?}", e);
-                }
-            }
-
-            let mut key_params: Vec<KsKeyparameter> = Vec::new();
-            for param in key_metadata.authorizations {
-                let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
-                key_params.push(key_param);
-            }
-
-            KeygenResult {
-                cert: key_metadata.certificate.unwrap(),
-                cert_chain: key_metadata.certificateChain.unwrap_or_default(),
-                key_parameters: key_params,
-            }
-        })
+        KeygenResult {
+            cert: key_metadata.certificate.unwrap(),
+            cert_chain: key_metadata.certificateChain.unwrap_or_default(),
+            key_parameters: key_params,
+        }
     };
 
-    // Safety: run_as must be called from a single threaded process.
-    // This device test is run as a separate single threaded process.
-    unsafe {
-        run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
-            println!("UID: {}", getuid());
-            println!("Android User ID: {}", rustutils::users::multiuser_get_user_id(9910001));
-            println!("Android app ID: {}", rustutils::users::multiuser_get_app_id(9910001));
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let mut gen_key_result = unsafe { run_as::run_as_root(gen_key_fn) };
 
-            let test_alias = "authbound";
-            let keystore2 = get_keystore_service();
+    let use_key_fn = move || {
+        println!("UID: {}", getuid());
+        println!("Android User ID: {}", rustutils::users::multiuser_get_user_id(9910001));
+        println!("Android app ID: {}", rustutils::users::multiuser_get_app_id(9910001));
 
-            match keystore2.getKeyEntry(&KeyDescriptor {
-                domain: Domain::APP,
-                nspace: SELINUX_SHELL_NAMESPACE,
-                alias: Some(test_alias.to_string()),
-                blob: None,
-            }) {
-                Ok(key_entry_response) => {
-                    assert_eq!(
-                        key_entry_response.metadata.certificate.unwrap(),
-                        gen_key_result.cert
-                    );
-                    assert_eq!(
-                        key_entry_response.metadata.certificateChain.unwrap_or_default(),
-                        gen_key_result.cert_chain
-                    );
-                    assert_eq!(key_entry_response.metadata.key.domain, Domain::KEY_ID);
-                    assert_ne!(key_entry_response.metadata.key.nspace, 0);
-                    assert_eq!(
-                        key_entry_response.metadata.keySecurityLevel,
-                        SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT
-                    );
+        let test_alias = "authbound";
+        let keystore2 = get_keystore_service();
 
-                    // Preapare KsKeyParameter list from getKeEntry response Authorizations.
-                    let mut key_params: Vec<KsKeyparameter> = Vec::new();
-                    for param in key_entry_response.metadata.authorizations {
-                        let key_param =
-                            KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
-                        key_params.push(key_param);
-                    }
+        match keystore2.getKeyEntry(&KeyDescriptor {
+            domain: Domain::APP,
+            nspace: SELINUX_SHELL_NAMESPACE,
+            alias: Some(test_alias.to_string()),
+            blob: None,
+        }) {
+            Ok(key_entry_response) => {
+                assert_eq!(key_entry_response.metadata.certificate.unwrap(), gen_key_result.cert);
+                assert_eq!(
+                    key_entry_response.metadata.certificateChain.unwrap_or_default(),
+                    gen_key_result.cert_chain
+                );
+                assert_eq!(key_entry_response.metadata.key.domain, Domain::KEY_ID);
+                assert_ne!(key_entry_response.metadata.key.nspace, 0);
+                assert_eq!(
+                    key_entry_response.metadata.keySecurityLevel,
+                    SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT
+                );
 
-                    // Combine keyparameters from gen_key_result and keyparameters
-                    // from legacy key-char file.
-                    let mut legacy_file_key_params: Vec<KsKeyparameter> = Vec::new();
-                    match structured_test_params() {
-                        LegacyKeyCharacteristics::File(legacy_key_params) => {
-                            for param in &legacy_key_params {
-                                let mut present_in_gen_params = false;
-                                for gen_param in &gen_key_result.key_parameters {
-                                    if param.get_tag() == gen_param.get_tag() {
-                                        present_in_gen_params = true;
-                                    }
-                                }
-                                if !present_in_gen_params {
-                                    legacy_file_key_params.push(param.clone());
+                // Preapare KsKeyParameter list from getKeEntry response Authorizations.
+                let mut key_params: Vec<KsKeyparameter> = Vec::new();
+                for param in key_entry_response.metadata.authorizations {
+                    let key_param =
+                        KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+                    key_params.push(key_param);
+                }
+
+                // Combine keyparameters from gen_key_result and keyparameters
+                // from legacy key-char file.
+                let mut legacy_file_key_params: Vec<KsKeyparameter> = Vec::new();
+                match structured_test_params() {
+                    LegacyKeyCharacteristics::File(legacy_key_params) => {
+                        for param in &legacy_key_params {
+                            let mut present_in_gen_params = false;
+                            for gen_param in &gen_key_result.key_parameters {
+                                if param.get_tag() == gen_param.get_tag() {
+                                    present_in_gen_params = true;
                                 }
                             }
-                        }
-                        _ => {
-                            panic!("Expecting file characteristics");
+                            if !present_in_gen_params {
+                                legacy_file_key_params.push(param.clone());
+                            }
                         }
                     }
-
-                    // Remove Key-Params which have security levels other than TRUSTED_ENVIRONMENT
-                    gen_key_result.key_parameters.retain(|in_element| {
-                        *in_element.security_level()
-                            == SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT
-                    });
-
-                    println!("GetKeyEntry response key params: {:#?}", key_params);
-                    println!("Generated key params: {:#?}", gen_key_result.key_parameters);
-
-                    gen_key_result.key_parameters.append(&mut legacy_file_key_params);
-
-                    println!("Combined key params: {:#?}", gen_key_result.key_parameters);
-
-                    // Validate all keyparameters present in getKeyEntry response.
-                    for param in &key_params {
-                        gen_key_result.key_parameters.retain(|in_element| *in_element != *param);
+                    _ => {
+                        panic!("Expecting file characteristics");
                     }
+                }
 
-                    println!(
-                        "GetKeyEntry response unmatched key params: {:#?}",
-                        gen_key_result.key_parameters
-                    );
-                    assert_eq!(gen_key_result.key_parameters.len(), 0);
+                // Remove Key-Params which have security levels other than TRUSTED_ENVIRONMENT
+                gen_key_result.key_parameters.retain(|in_element| {
+                    *in_element.security_level()
+                        == SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT
+                });
+
+                println!("GetKeyEntry response key params: {:#?}", key_params);
+                println!("Generated key params: {:#?}", gen_key_result.key_parameters);
+
+                gen_key_result.key_parameters.append(&mut legacy_file_key_params);
+
+                println!("Combined key params: {:#?}", gen_key_result.key_parameters);
+
+                // Validate all keyparameters present in getKeyEntry response.
+                for param in &key_params {
+                    gen_key_result.key_parameters.retain(|in_element| *in_element != *param);
                 }
-                Err(s) => {
-                    panic!("getKeyEntry should have succeeded. {:?}", s);
-                }
-            };
-        })
+
+                println!(
+                    "GetKeyEntry response unmatched key params: {:#?}",
+                    gen_key_result.key_parameters
+                );
+                assert_eq!(gen_key_result.key_parameters.len(), 0);
+            }
+            Err(s) => {
+                panic!("getKeyEntry should have succeeded. {:?}", s);
+            }
+        };
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(auid, agid, use_key_fn) };
+
     // Make sure keystore2 clean up imported legacy db.
     let path_buf = PathBuf::from("/data/misc/keystore/user_99");
     if path_buf.as_path().is_dir() {
@@ -367,7 +362,7 @@
 ///     6. To load and import the legacy key using its alias.
 ///     7. After successful key import validate the user cert and cert-chain with initially
 ///        generated blobs.
-///     8. Validate imported key perameters. Imported key parameters list should be the combination
+///     8. Validate imported key parameters. Imported key parameters list should be the combination
 ///        of the key-parameters in characteristics file and the characteristics according to
 ///        the augmentation rules. There might be duplicate entries with different values for the
 ///        parameters like OS_VERSION, OS_VERSION, BOOT_PATCHLEVEL, VENDOR_PATCHLEVEL etc.
@@ -376,8 +371,6 @@
 fn keystore2_encrypted_certificates() -> anyhow::Result<()> {
     let auid = 98 * AID_USER_OFFSET + 10001;
     let agid = 98 * AID_USER_OFFSET + 10001;
-    static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-    static TARGET_SU_CTX: &str = "u:r:su:s0";
 
     // Cleanup user directory if it exists
     let path_buf = PathBuf::from("/data/misc/keystore/user_98");
@@ -385,177 +378,171 @@
         std::fs::remove_dir_all(path_buf.as_path()).unwrap();
     }
 
-    // Safety: run_as must be called from a single threaded process.
-    // This device test is run as a separate single threaded process.
-    let gen_key_result = unsafe {
-        run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
-            // Remove user if already exist.
-            let maint_service = get_maintenance();
-            match maint_service.onUserRemoved(98) {
-                Ok(_) => {
-                    println!("User was existed, deleted successfully");
-                }
-                Err(e) => {
-                    println!("onUserRemoved error: {:#?}", e);
-                }
+    let gen_key_fn = || {
+        // Remove user if already exist.
+        let maint_service = get_maintenance();
+        match maint_service.onUserRemoved(98) {
+            Ok(_) => {
+                println!("User did exist, deleted successfully");
             }
+            Err(e) => {
+                println!("onUserRemoved error: {:#?}", e);
+            }
+        }
 
-            let sl = SecLevel::tee();
-            // Generate Key BLOB and prepare legacy keystore blob files.
-            let att_challenge: Option<&[u8]> = if rkp_only() { None } else { Some(b"foo") };
-            let key_metadata = key_generations::generate_ec_p256_signing_key(
-                &sl,
-                Domain::BLOB,
-                SELINUX_SHELL_NAMESPACE,
-                None,
-                att_challenge,
+        let sl = SecLevel::tee();
+        // Generate Key BLOB and prepare legacy keystore blob files.
+        let att_challenge: Option<&[u8]> = if rkp_only() { None } else { Some(b"foo") };
+        let key_metadata = key_generations::generate_ec_p256_signing_key(
+            &sl,
+            Domain::BLOB,
+            SELINUX_SHELL_NAMESPACE,
+            None,
+            att_challenge,
+        )
+        .expect("Failed to generate key blob");
+
+        // Create keystore file layout for user_98.
+        let pw: Password = PASSWORD.into();
+        let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
+        let super_key =
+            TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap());
+
+        let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+        if !path_buf.as_path().is_dir() {
+            std::fs::create_dir(path_buf.as_path()).unwrap();
+        }
+        path_buf.push(".masterkey");
+        if !path_buf.as_path().is_file() {
+            std::fs::write(path_buf.as_path(), SUPERKEY).unwrap();
+        }
+
+        let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+        path_buf.push("9810001_USRPKEY_authboundcertenc");
+        if !path_buf.as_path().is_file() {
+            make_encrypted_key_file(
+                path_buf.as_path(),
+                &super_key,
+                &key_metadata.key.blob.unwrap(),
             )
-            .expect("Failed to generate key blob");
+            .unwrap();
+        }
 
-            // Create keystore file layout for user_98.
-            let pw: Password = PASSWORD.into();
-            let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
-            let super_key =
-                TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap());
+        let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+        path_buf.push(".9810001_chr_USRPKEY_authboundcertenc");
+        if !path_buf.as_path().is_file() {
+            std::fs::write(path_buf.as_path(), USRPKEY_AUTHBOUND_CHR).unwrap();
+        }
 
+        let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+        path_buf.push("9810001_USRCERT_authboundcertenc");
+        if !path_buf.as_path().is_file() {
+            make_encrypted_usr_cert_file(
+                path_buf.as_path(),
+                &super_key,
+                key_metadata.certificate.as_ref().unwrap(),
+            )
+            .unwrap();
+        }
+
+        if let Some(chain) = key_metadata.certificateChain.as_ref() {
             let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
-            if !path_buf.as_path().is_dir() {
-                std::fs::create_dir(path_buf.as_path()).unwrap();
-            }
-            path_buf.push(".masterkey");
+            path_buf.push("9810001_CACERT_authboundcertenc");
             if !path_buf.as_path().is_file() {
-                std::fs::write(path_buf.as_path(), SUPERKEY).unwrap();
+                make_encrypted_ca_cert_file(path_buf.as_path(), &super_key, chain).unwrap();
             }
+        }
 
-            let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
-            path_buf.push("9810001_USRPKEY_authboundcertenc");
-            if !path_buf.as_path().is_file() {
-                make_encrypted_key_file(
-                    path_buf.as_path(),
-                    &super_key,
-                    &key_metadata.key.blob.unwrap(),
-                )
-                .unwrap();
+        // Keystore2 disables the legacy importer when it finds the legacy database empty.
+        // However, if the device boots with an empty legacy database, the optimization kicks in
+        // and keystore2 never checks the legacy file system layout.
+        // So, restart keystore2 service to detect populated legacy database.
+        keystore2_restart_service();
+
+        let auth_service = get_authorization();
+        match auth_service.onDeviceUnlocked(98, Some(PASSWORD)) {
+            Ok(result) => {
+                println!("Unlock Result: {:?}", result);
             }
-
-            let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
-            path_buf.push(".9810001_chr_USRPKEY_authboundcertenc");
-            if !path_buf.as_path().is_file() {
-                std::fs::write(path_buf.as_path(), USRPKEY_AUTHBOUND_CHR).unwrap();
+            Err(e) => {
+                panic!("Unlock should have succeeded: {:?}", e);
             }
+        }
 
-            let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
-            path_buf.push("9810001_USRCERT_authboundcertenc");
-            if !path_buf.as_path().is_file() {
-                make_encrypted_usr_cert_file(
-                    path_buf.as_path(),
-                    &super_key,
-                    key_metadata.certificate.as_ref().unwrap(),
-                )
-                .unwrap();
-            }
+        let mut key_params: Vec<KsKeyparameter> = Vec::new();
+        for param in key_metadata.authorizations {
+            let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+            key_params.push(key_param);
+        }
 
-            if let Some(chain) = key_metadata.certificateChain.as_ref() {
-                let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
-                path_buf.push("9810001_CACERT_authboundcertenc");
-                if !path_buf.as_path().is_file() {
-                    make_encrypted_ca_cert_file(path_buf.as_path(), &super_key, chain).unwrap();
-                }
-            }
-
-            // Keystore2 disables the legacy importer when it finds the legacy database empty.
-            // However, if the device boots with an empty legacy database, the optimization kicks in
-            // and keystore2 never checks the legacy file system layout.
-            // So, restart keystore2 service to detect populated legacy database.
-            keystore2_restart_service();
-
-            let auth_service = get_authorization();
-            match auth_service.onDeviceUnlocked(98, Some(PASSWORD)) {
-                Ok(result) => {
-                    println!("Unlock Result: {:?}", result);
-                }
-                Err(e) => {
-                    panic!("Unlock should have succeeded: {:?}", e);
-                }
-            }
-
-            let mut key_params: Vec<KsKeyparameter> = Vec::new();
-            for param in key_metadata.authorizations {
-                let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
-                key_params.push(key_param);
-            }
-
-            KeygenResult {
-                cert: key_metadata.certificate.unwrap(),
-                cert_chain: key_metadata.certificateChain.unwrap_or_default(),
-                key_parameters: key_params,
-            }
-        })
+        KeygenResult {
+            cert: key_metadata.certificate.unwrap(),
+            cert_chain: key_metadata.certificateChain.unwrap_or_default(),
+            key_parameters: key_params,
+        }
     };
 
-    // Safety: run_as must be called from a single threaded process.
-    // This device test is run as a separate single threaded process.
-    unsafe {
-        run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
-            println!("UID: {}", getuid());
-            println!("Android User ID: {}", rustutils::users::multiuser_get_user_id(9810001));
-            println!("Android app ID: {}", rustutils::users::multiuser_get_app_id(9810001));
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    let gen_key_result = unsafe { run_as::run_as_root(gen_key_fn) };
 
-            let test_alias = "authboundcertenc";
-            let keystore2 = get_keystore_service();
+    let use_key_fn = move || {
+        println!("UID: {}", getuid());
+        println!("Android User ID: {}", rustutils::users::multiuser_get_user_id(9810001));
+        println!("Android app ID: {}", rustutils::users::multiuser_get_app_id(9810001));
 
-            match keystore2.getKeyEntry(&KeyDescriptor {
-                domain: Domain::APP,
-                nspace: SELINUX_SHELL_NAMESPACE,
-                alias: Some(test_alias.to_string()),
-                blob: None,
-            }) {
-                Ok(key_entry_response) => {
-                    assert_eq!(
-                        key_entry_response.metadata.certificate.unwrap(),
-                        gen_key_result.cert
-                    );
-                    assert_eq!(
-                        key_entry_response.metadata.certificateChain.unwrap_or_default(),
-                        gen_key_result.cert_chain
-                    );
+        let test_alias = "authboundcertenc";
+        let keystore2 = get_keystore_service();
 
-                    // Preapare KsKeyParameter list from getKeEntry response Authorizations.
-                    let mut key_params: Vec<KsKeyparameter> = Vec::new();
-                    for param in key_entry_response.metadata.authorizations {
-                        let key_param =
-                            KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
-                        key_params.push(key_param);
+        match keystore2.getKeyEntry(&KeyDescriptor {
+            domain: Domain::APP,
+            nspace: SELINUX_SHELL_NAMESPACE,
+            alias: Some(test_alias.to_string()),
+            blob: None,
+        }) {
+            Ok(key_entry_response) => {
+                assert_eq!(key_entry_response.metadata.certificate.unwrap(), gen_key_result.cert);
+                assert_eq!(
+                    key_entry_response.metadata.certificateChain.unwrap_or_default(),
+                    gen_key_result.cert_chain
+                );
+
+                // Preapare KsKeyParameter list from getKeEntry response Authorizations.
+                let mut key_params: Vec<KsKeyparameter> = Vec::new();
+                for param in key_entry_response.metadata.authorizations {
+                    let key_param =
+                        KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+                    key_params.push(key_param);
+                }
+
+                println!("GetKeyEntry response key params: {:#?}", key_params);
+                println!("Generated key params: {:#?}", gen_key_result.key_parameters);
+                match structured_test_params_cache() {
+                    LegacyKeyCharacteristics::Cache(legacy_key_params) => {
+                        println!("Legacy key-char cache: {:#?}", legacy_key_params);
+                        // Validate all keyparameters present in getKeyEntry response.
+                        for param in &legacy_key_params {
+                            key_params.retain(|in_element| *in_element != *param);
+                        }
+
+                        println!("GetKeyEntry response unmatched key params: {:#?}", key_params);
+                        assert_eq!(key_params.len(), 0);
                     }
-
-                    println!("GetKeyEntry response key params: {:#?}", key_params);
-                    println!("Generated key params: {:#?}", gen_key_result.key_parameters);
-                    match structured_test_params_cache() {
-                        LegacyKeyCharacteristics::Cache(legacy_key_params) => {
-                            println!("Legacy key-char cache: {:#?}", legacy_key_params);
-                            // Validate all keyparameters present in getKeyEntry response.
-                            for param in &legacy_key_params {
-                                key_params.retain(|in_element| *in_element != *param);
-                            }
-
-                            println!(
-                                "GetKeyEntry response unmatched key params: {:#?}",
-                                key_params
-                            );
-                            assert_eq!(key_params.len(), 0);
-                        }
-                        _ => {
-                            panic!("Expecting file characteristics");
-                        }
+                    _ => {
+                        panic!("Expecting file characteristics");
                     }
                 }
-                Err(s) => {
-                    panic!("getKeyEntry should have succeeded. {:?}", s);
-                }
-            };
-        })
+            }
+            Err(s) => {
+                panic!("getKeyEntry should have succeeded. {:?}", s);
+            }
+        };
     };
 
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder.
+    unsafe { run_as::run_as_app(auid, agid, use_key_fn) };
+
     // Make sure keystore2 clean up imported legacy db.
     let path_buf = PathBuf::from("/data/misc/keystore/user_98");
     if path_buf.as_path().is_dir() {