Add tests covering android.system.keystore2.IKeystoreOperation::abort
API.

1. When attempting to abort a finalized operation, the test should
   expect the backend implementation to return an
   `ErrorCode::INVALID_OPERATION_HANDLE`

2. If an operation is aborted before completion, the test should expect
   the operation to finalize successfully. Additionally, attempting to
   reuse the aborted operation handle should result in an
   `INVALID_OPERATION_HANDLE` error code.

3. To test concurrency and abort behavior, create multiple threads that
   use the same operation handle to perform a large number of update
   operations. Subsequently, attempt to abort the operation. The abort
   operation should fail with an `OPERATION_BUSY` error response,
   indicating that the operation is currently in use by multiple
   threads.

Bug: 361167455
Test: atest keystore2_client_tests
Change-Id: Icc2ccddb86bc08f91468746e0bdcb47c43fea635
diff --git a/keystore2/tests/keystore2_client_operation_tests.rs b/keystore2/tests/keystore2_client_operation_tests.rs
index 02cf260..5f640ef 100644
--- a/keystore2/tests/keystore2_client_operation_tests.rs
+++ b/keystore2/tests/keystore2_client_operation_tests.rs
@@ -28,6 +28,10 @@
 };
 use nix::unistd::{getuid, Gid, Uid};
 use rustutils::users::AID_USER_OFFSET;
+use std::sync::{
+    atomic::{AtomicBool, Ordering},
+    Arc,
+};
 use std::thread;
 use std::thread::JoinHandle;
 
@@ -461,3 +465,120 @@
 
     assert!(result1 || result2);
 }
+
+/// Create an operation and use it for performing sign operation. After completing the operation
+/// try to abort the operation. Test should fail to abort already finalized operation with error
+/// code `INVALID_OPERATION_HANDLE`.
+#[test]
+fn keystore2_abort_finalized_op_fail_test() {
+    let op_response = create_signing_operation(
+        ForcedOp(false),
+        KeyPurpose::SIGN,
+        Digest::SHA_2_256,
+        Domain::APP,
+        -1,
+        Some("ks_op_abort_fail_test_key".to_string()),
+    )
+    .unwrap();
+
+    let op: binder::Strong<dyn IKeystoreOperation> = op_response.iOperation.unwrap();
+    perform_sample_sign_operation(&op).unwrap();
+    let result = key_generations::map_ks_error(op.abort());
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE), result.unwrap_err());
+}
+
+/// Create an operation and use it for performing sign operation. Before finishing the operation
+/// try to abort the operation. Test should successfully abort the operation. After aborting try to
+/// use the operation handle, test should fail to use already aborted operation handle with error
+/// code `INVALID_OPERATION_HANDLE`.
+#[test]
+fn keystore2_op_abort_success_test() {
+    let op_response = create_signing_operation(
+        ForcedOp(false),
+        KeyPurpose::SIGN,
+        Digest::SHA_2_256,
+        Domain::APP,
+        -1,
+        Some("ks_op_abort_success_key".to_string()),
+    )
+    .unwrap();
+
+    let op: binder::Strong<dyn IKeystoreOperation> = op_response.iOperation.unwrap();
+    op.update(b"my message").unwrap();
+    let result = key_generations::map_ks_error(op.abort());
+    assert!(result.is_ok());
+
+    // Try to use the op handle after abort.
+    let result = key_generations::map_ks_error(op.finish(None, None));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE), result.unwrap_err());
+}
+
+/// Executes an operation in a thread. Performs an `update` operation repeatedly till the user
+/// interrupts it or encounters any error other than `OPERATION_BUSY`.
+/// Return `false` in case of any error other than `OPERATION_BUSY`, otherwise it returns true.
+fn perform_abort_op_busy_in_thread(
+    op: binder::Strong<dyn IKeystoreOperation>,
+    should_exit_clone: Arc<AtomicBool>,
+) -> JoinHandle<bool> {
+    thread::spawn(move || {
+        loop {
+            if should_exit_clone.load(Ordering::Relaxed) {
+                // Caller requested to exit the thread.
+                return true;
+            }
+
+            match key_generations::map_ks_error(op.update(b"my message")) {
+                Ok(_) => continue,
+                Err(Error::Rc(ResponseCode::OPERATION_BUSY)) => continue,
+                Err(_) => return false,
+            }
+        }
+    })
+}
+
+/// Create an operation and try to use same operation handle in multiple threads to perform
+/// operations. Test tries to abort the operation and expects `abort` call to fail with the error
+/// response `OPERATION_BUSY` as multiple threads try to access the same operation handle
+/// simultaneously. Test tries to simulate `OPERATION_BUSY` error response from `abort` api.
+#[test]
+fn keystore2_op_abort_fails_with_operation_busy_error_test() {
+    loop {
+        let op_response = create_signing_operation(
+            ForcedOp(false),
+            KeyPurpose::SIGN,
+            Digest::SHA_2_256,
+            Domain::APP,
+            -1,
+            Some("op_abort_busy_alias_test_key".to_string()),
+        )
+        .unwrap();
+        let op: binder::Strong<dyn IKeystoreOperation> = op_response.iOperation.unwrap();
+
+        let should_exit = Arc::new(AtomicBool::new(false));
+
+        let update_t_handle1 = perform_abort_op_busy_in_thread(op.clone(), should_exit.clone());
+        let update_t_handle2 = perform_abort_op_busy_in_thread(op.clone(), should_exit.clone());
+
+        // Attempt to abort the operation and anticipate an 'OPERATION_BUSY' error, as multiple
+        // threads are concurrently accessing the same operation handle.
+        let result = match op.abort() {
+            Ok(_) => 0, // Operation successfully aborted.
+            Err(e) => e.service_specific_error(),
+        };
+
+        // Notify threads to stop performing `update` operation.
+        should_exit.store(true, Ordering::Relaxed);
+
+        let _update_op_result = update_t_handle1.join().unwrap();
+        let _update_op_result2 = update_t_handle2.join().unwrap();
+
+        if result == ResponseCode::OPERATION_BUSY.0 {
+            // The abort call failed with an OPERATION_BUSY error, as anticipated, due to multiple
+            // threads competing for access to the same operation handle.
+            return;
+        }
+        assert_eq!(result, 0);
+    }
+}