Adding a test to simulate `OPERATION_BUSY` error from keystore.

The test tries to create a race condition: It creates an operation
and starts two threads, each trying to use the operation repeatedly
until it gets  `OPERATION_BUSY`  or finishes successfully.

Bug: 194359114
Test: atest keystore2_client_test
Change-Id: Ib3549d6bcad4e24bf621960f0f399481bf2da7c7
diff --git a/keystore2/tests/keystore2_client_operation_tests.rs b/keystore2/tests/keystore2_client_operation_tests.rs
index d8b85f6..e1102dd 100644
--- a/keystore2/tests/keystore2_client_operation_tests.rs
+++ b/keystore2/tests/keystore2_client_operation_tests.rs
@@ -14,12 +14,15 @@
 
 use nix::unistd::{getuid, Gid, Uid};
 use rustutils::users::AID_USER_OFFSET;
+use std::thread;
+use std::thread::JoinHandle;
 
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
 };
 use android_system_keystore2::aidl::android::system::keystore2::{
-    CreateOperationResponse::CreateOperationResponse, Domain::Domain, ResponseCode::ResponseCode,
+    CreateOperationResponse::CreateOperationResponse, Domain::Domain,
+    IKeystoreOperation::IKeystoreOperation, ResponseCode::ResponseCode,
 };
 
 use keystore2_test_utils::{
@@ -57,6 +60,25 @@
         .collect()
 }
 
+/// Executes an operation in a thread. Expect an `OPERATION_BUSY` error in case of operation
+/// failure. Returns True if `OPERATION_BUSY` error is encountered otherwise returns false.
+fn perform_op_busy_in_thread(op: binder::Strong<dyn IKeystoreOperation>) -> JoinHandle<bool> {
+    thread::spawn(move || {
+        for _n in 1..1000 {
+            match key_generations::map_ks_error(op.update(b"my message")) {
+                Ok(_) => continue,
+                Err(e) => {
+                    assert_eq!(Error::Rc(ResponseCode::OPERATION_BUSY), e);
+                    return true;
+                }
+            }
+        }
+        let sig = op.finish(None, None).unwrap();
+        assert!(sig.is_some());
+        false
+    })
+}
+
 /// This test verifies that backend service throws BACKEND_BUSY error when all
 /// operations slots are full. This test creates operations in child processes and
 /// collects the status of operations performed in each child proc and determines
@@ -402,3 +424,29 @@
         });
     }
 }
+
+/// Create an operation and try to use this operation handle in multiple threads to perform
+/// operations. Test should fail to perform an operation with an error response `OPERATION_BUSY`
+/// when multiple threads try to access the operation handle at same time.
+#[test]
+fn keystore2_op_fails_operation_busy() {
+    let op_response = create_signing_operation(
+        ForcedOp(false),
+        KeyPurpose::SIGN,
+        Digest::SHA_2_256,
+        Domain::APP,
+        -1,
+        Some("op_busy_alias_test_key".to_string()),
+    )
+    .unwrap();
+
+    let op: binder::Strong<dyn IKeystoreOperation> = op_response.iOperation.unwrap();
+
+    let th_handle_1 = perform_op_busy_in_thread(op.clone());
+    let th_handle_2 = perform_op_busy_in_thread(op);
+
+    let result1 = th_handle_1.join().unwrap();
+    let result2 = th_handle_2.join().unwrap();
+
+    assert!(result1 || result2);
+}