1 // Copyright 2022, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! KeyMint HAL device implementation. 16 17 use crate::binder; 18 use crate::hal::{ 19 failed_conversion, keymint, keymint::IKeyMintOperation::IKeyMintOperation, 20 secureclock::TimeStampToken::TimeStampToken, Innto, TryInnto, 21 }; 22 use crate::{ChannelHalService, SerializedChannel}; 23 use kmr_wire::{keymint::KeyParam, AsCborValue, *}; 24 use log::warn; 25 use std::ffi::CString; 26 use std::{ 27 ops::DerefMut, 28 sync::{Arc, Mutex, MutexGuard, RwLock}, 29 }; 30 31 /// Maximum overhead size from CBOR serialization of operation messages. 32 /// 33 /// A serialized `FinishRequest` includes the following additional bytes over and 34 /// above the size of the input (at most): 35 /// - 1: array wrapper (0x86) 36 /// - 9: int (0x1b + u64) [op_handle] 37 /// - 1: array wrapper (0x81) [input] 38 /// - 9: input data length 39 /// - XX: input data 40 /// - 1: array wrapper (0x81) [signature] 41 /// - 5: signature data length 42 /// - 132: signature data (P-521 point) 43 /// - 1: array wrapper (0x81) [auth_token] 44 /// - 9: int (0x1b + u64) [challenge] 45 /// - 9: int (0x1b + u64) [user_id] 46 /// - 9: int (0x1b + u64) [authenticator_id] 47 /// - 9: int (0x1b + u64) [authenticator_type] 48 /// - 1: array wrapper (0x81)[timestamp] 49 /// - 9: int (0x1b + u64) [user_id] 50 /// - 2: bstr header [mac] 51 /// - 32: bstr [mac] 52 /// - 1: array wrapper (0x81) [timestamp_token] 53 /// - 1: array wrapper [TimeStampToken] 54 /// - 9: int (0x1b + u64) [challenge] 55 /// - 1: array wrapper (0x81)[timestamp] 56 /// - 9: int (0x1b + u64) [user_id] 57 /// - 2: bstr header [mac] 58 /// - 32: bstr [mac] 59 /// - 1: array wrapper (0x81) [confirmation_token] 60 /// - 2: bstr header [confirmation token] 61 /// - 32: bstr [confirmation token (HMAC-SHA256)] 62 /// 63 /// Add some leeway in case encodings change. 64 pub const MAX_CBOR_OVERHEAD: usize = 350; 65 66 /// IKeyMintDevice implementation which converts all method invocations to serialized 67 /// requests that are sent down the associated channel. 68 pub struct Device<T: SerializedChannel + 'static> { 69 channel: Arc<Mutex<T>>, 70 } 71 72 impl<T: SerializedChannel + 'static> Device<T> { 73 /// Construct a new instance that uses the provided channel. new(channel: Arc<Mutex<T>>) -> Self74 pub fn new(channel: Arc<Mutex<T>>) -> Self { 75 Self { channel } 76 } 77 78 /// Create a new instance wrapped in a proxy object. new_as_binder( channel: Arc<Mutex<T>>, ) -> binder::Strong<dyn keymint::IKeyMintDevice::IKeyMintDevice>79 pub fn new_as_binder( 80 channel: Arc<Mutex<T>>, 81 ) -> binder::Strong<dyn keymint::IKeyMintDevice::IKeyMintDevice> { 82 keymint::IKeyMintDevice::BnKeyMintDevice::new_binder( 83 Self::new(channel), 84 binder::BinderFeatures::default(), 85 ) 86 } 87 } 88 89 impl<T: SerializedChannel> ChannelHalService<T> for Device<T> { channel(&self) -> MutexGuard<T>90 fn channel(&self) -> MutexGuard<T> { 91 self.channel.lock().unwrap() 92 } 93 } 94 95 impl<T: SerializedChannel> binder::Interface for Device<T> {} 96 97 impl<T: SerializedChannel> keymint::IKeyMintDevice::IKeyMintDevice for Device<T> { getHardwareInfo(&self) -> binder::Result<keymint::KeyMintHardwareInfo::KeyMintHardwareInfo>98 fn getHardwareInfo(&self) -> binder::Result<keymint::KeyMintHardwareInfo::KeyMintHardwareInfo> { 99 let rsp: GetHardwareInfoResponse = self.execute(GetHardwareInfoRequest {})?; 100 Ok(rsp.ret.innto()) 101 } addRngEntropy(&self, data: &[u8]) -> binder::Result<()>102 fn addRngEntropy(&self, data: &[u8]) -> binder::Result<()> { 103 let _rsp: AddRngEntropyResponse = 104 self.execute(AddRngEntropyRequest { data: data.to_vec() })?; 105 Ok(()) 106 } generateKey( &self, keyParams: &[keymint::KeyParameter::KeyParameter], attestationKey: Option<&keymint::AttestationKey::AttestationKey>, ) -> binder::Result<keymint::KeyCreationResult::KeyCreationResult>107 fn generateKey( 108 &self, 109 keyParams: &[keymint::KeyParameter::KeyParameter], 110 attestationKey: Option<&keymint::AttestationKey::AttestationKey>, 111 ) -> binder::Result<keymint::KeyCreationResult::KeyCreationResult> { 112 let rsp: GenerateKeyResponse = self.execute(GenerateKeyRequest { 113 key_params: keyParams 114 .iter() 115 .filter_map(|p| p.try_innto().transpose()) 116 .collect::<Result<Vec<KeyParam>, _>>() 117 .map_err(failed_conversion)?, 118 attestation_key: match attestationKey { 119 None => None, 120 Some(k) => Some(k.clone().try_innto().map_err(failed_conversion)?), 121 }, 122 })?; 123 Ok(rsp.ret.innto()) 124 } importKey( &self, keyParams: &[keymint::KeyParameter::KeyParameter], keyFormat: keymint::KeyFormat::KeyFormat, keyData: &[u8], attestationKey: Option<&keymint::AttestationKey::AttestationKey>, ) -> binder::Result<keymint::KeyCreationResult::KeyCreationResult>125 fn importKey( 126 &self, 127 keyParams: &[keymint::KeyParameter::KeyParameter], 128 keyFormat: keymint::KeyFormat::KeyFormat, 129 keyData: &[u8], 130 attestationKey: Option<&keymint::AttestationKey::AttestationKey>, 131 ) -> binder::Result<keymint::KeyCreationResult::KeyCreationResult> { 132 let rsp: ImportKeyResponse = self.execute(ImportKeyRequest { 133 key_params: keyParams 134 .iter() 135 .filter_map(|p| p.try_innto().transpose()) 136 .collect::<Result<Vec<KeyParam>, _>>() 137 .map_err(failed_conversion)?, 138 key_format: keyFormat.try_innto().map_err(failed_conversion)?, 139 key_data: keyData.to_vec(), 140 attestation_key: match attestationKey { 141 None => None, 142 Some(k) => Some(k.clone().try_innto().map_err(failed_conversion)?), 143 }, 144 })?; 145 Ok(rsp.ret.innto()) 146 } importWrappedKey( &self, wrappedKeyData: &[u8], wrappingKeyBlob: &[u8], maskingKey: &[u8], unwrappingParams: &[keymint::KeyParameter::KeyParameter], passwordSid: i64, biometricSid: i64, ) -> binder::Result<keymint::KeyCreationResult::KeyCreationResult>147 fn importWrappedKey( 148 &self, 149 wrappedKeyData: &[u8], 150 wrappingKeyBlob: &[u8], 151 maskingKey: &[u8], 152 unwrappingParams: &[keymint::KeyParameter::KeyParameter], 153 passwordSid: i64, 154 biometricSid: i64, 155 ) -> binder::Result<keymint::KeyCreationResult::KeyCreationResult> { 156 let rsp: ImportWrappedKeyResponse = self.execute(ImportWrappedKeyRequest { 157 wrapped_key_data: wrappedKeyData.to_vec(), 158 wrapping_key_blob: wrappingKeyBlob.to_vec(), 159 masking_key: maskingKey.to_vec(), 160 unwrapping_params: unwrappingParams 161 .iter() 162 .filter_map(|p| p.try_innto().transpose()) 163 .collect::<Result<Vec<KeyParam>, _>>() 164 .map_err(failed_conversion)?, 165 password_sid: passwordSid, 166 biometric_sid: biometricSid, 167 })?; 168 Ok(rsp.ret.innto()) 169 } upgradeKey( &self, keyBlobToUpgrade: &[u8], upgradeParams: &[keymint::KeyParameter::KeyParameter], ) -> binder::Result<Vec<u8>>170 fn upgradeKey( 171 &self, 172 keyBlobToUpgrade: &[u8], 173 upgradeParams: &[keymint::KeyParameter::KeyParameter], 174 ) -> binder::Result<Vec<u8>> { 175 let rsp: UpgradeKeyResponse = self.execute(UpgradeKeyRequest { 176 key_blob_to_upgrade: keyBlobToUpgrade.to_vec(), 177 upgrade_params: upgradeParams 178 .iter() 179 .filter_map(|p| p.try_innto().transpose()) 180 .collect::<Result<Vec<KeyParam>, _>>() 181 .map_err(failed_conversion)?, 182 })?; 183 Ok(rsp.ret) 184 } deleteKey(&self, keyBlob: &[u8]) -> binder::Result<()>185 fn deleteKey(&self, keyBlob: &[u8]) -> binder::Result<()> { 186 let _rsp: DeleteKeyResponse = 187 self.execute(DeleteKeyRequest { key_blob: keyBlob.to_vec() })?; 188 Ok(()) 189 } deleteAllKeys(&self) -> binder::Result<()>190 fn deleteAllKeys(&self) -> binder::Result<()> { 191 let _rsp: DeleteAllKeysResponse = self.execute(DeleteAllKeysRequest {})?; 192 Ok(()) 193 } destroyAttestationIds(&self) -> binder::Result<()>194 fn destroyAttestationIds(&self) -> binder::Result<()> { 195 let _rsp: DestroyAttestationIdsResponse = self.execute(DestroyAttestationIdsRequest {})?; 196 Ok(()) 197 } begin( &self, purpose: keymint::KeyPurpose::KeyPurpose, keyBlob: &[u8], params: &[keymint::KeyParameter::KeyParameter], authToken: Option<&keymint::HardwareAuthToken::HardwareAuthToken>, ) -> binder::Result<keymint::BeginResult::BeginResult>198 fn begin( 199 &self, 200 purpose: keymint::KeyPurpose::KeyPurpose, 201 keyBlob: &[u8], 202 params: &[keymint::KeyParameter::KeyParameter], 203 authToken: Option<&keymint::HardwareAuthToken::HardwareAuthToken>, 204 ) -> binder::Result<keymint::BeginResult::BeginResult> { 205 let rsp: BeginResponse = self.execute(BeginRequest { 206 purpose: purpose.try_innto().map_err(failed_conversion)?, 207 key_blob: keyBlob.to_vec(), 208 params: params 209 .iter() 210 .filter_map(|p| p.try_innto().transpose()) 211 .collect::<Result<Vec<KeyParam>, _>>() 212 .map_err(failed_conversion)?, 213 auth_token: match authToken { 214 None => None, 215 Some(t) => Some(t.clone().try_innto().map_err(failed_conversion)?), 216 }, 217 })?; 218 // The `begin()` method is a special case. 219 // - Internally, the in-progress operation is identified by an opaque handle value. 220 // - Externally, the in-progress operation is represented as an `IKeyMintOperation` Binder 221 // object. 222 // The `WireOperation` struct contains the former, and acts as the latter. 223 let op = Operation::new_as_binder(self.channel.clone(), rsp.ret.op_handle); 224 Ok(keymint::BeginResult::BeginResult { 225 challenge: rsp.ret.challenge, 226 params: rsp.ret.params.innto(), 227 operation: Some(op), 228 }) 229 } deviceLocked( &self, _passwordOnly: bool, _timestampToken: Option<&TimeStampToken>, ) -> binder::Result<()>230 fn deviceLocked( 231 &self, 232 _passwordOnly: bool, 233 _timestampToken: Option<&TimeStampToken>, 234 ) -> binder::Result<()> { 235 // This method is deprecated and unused, so just fail with error UNIMPLEMENTED. 236 warn!("Deprecated method devicedLocked() was called"); 237 Err(binder::Status::new_service_specific_error( 238 keymint::ErrorCode::ErrorCode::UNIMPLEMENTED.0, 239 Some(&CString::new("Deprecated method deviceLocked() is not implemented").unwrap()), 240 )) 241 } earlyBootEnded(&self) -> binder::Result<()>242 fn earlyBootEnded(&self) -> binder::Result<()> { 243 let _rsp: EarlyBootEndedResponse = self.execute(EarlyBootEndedRequest {})?; 244 Ok(()) 245 } convertStorageKeyToEphemeral(&self, storageKeyBlob: &[u8]) -> binder::Result<Vec<u8>>246 fn convertStorageKeyToEphemeral(&self, storageKeyBlob: &[u8]) -> binder::Result<Vec<u8>> { 247 let rsp: ConvertStorageKeyToEphemeralResponse = 248 self.execute(ConvertStorageKeyToEphemeralRequest { 249 storage_key_blob: storageKeyBlob.to_vec(), 250 })?; 251 Ok(rsp.ret) 252 } getKeyCharacteristics( &self, keyBlob: &[u8], appId: &[u8], appData: &[u8], ) -> binder::Result<Vec<keymint::KeyCharacteristics::KeyCharacteristics>>253 fn getKeyCharacteristics( 254 &self, 255 keyBlob: &[u8], 256 appId: &[u8], 257 appData: &[u8], 258 ) -> binder::Result<Vec<keymint::KeyCharacteristics::KeyCharacteristics>> { 259 let rsp: GetKeyCharacteristicsResponse = self.execute(GetKeyCharacteristicsRequest { 260 key_blob: keyBlob.to_vec(), 261 app_id: appId.to_vec(), 262 app_data: appData.to_vec(), 263 })?; 264 Ok(rsp.ret.innto()) 265 } 266 #[cfg(feature = "hal_v2")] getRootOfTrustChallenge(&self) -> binder::Result<[u8; 16]>267 fn getRootOfTrustChallenge(&self) -> binder::Result<[u8; 16]> { 268 let rsp: GetRootOfTrustChallengeResponse = 269 self.execute(GetRootOfTrustChallengeRequest {})?; 270 Ok(rsp.ret) 271 } 272 #[cfg(feature = "hal_v2")] getRootOfTrust(&self, challenge: &[u8; 16]) -> binder::Result<Vec<u8>>273 fn getRootOfTrust(&self, challenge: &[u8; 16]) -> binder::Result<Vec<u8>> { 274 let rsp: GetRootOfTrustResponse = 275 self.execute(GetRootOfTrustRequest { challenge: *challenge })?; 276 Ok(rsp.ret) 277 } 278 #[cfg(feature = "hal_v2")] sendRootOfTrust(&self, root_of_trust: &[u8]) -> binder::Result<()>279 fn sendRootOfTrust(&self, root_of_trust: &[u8]) -> binder::Result<()> { 280 let _rsp: SendRootOfTrustResponse = 281 self.execute(SendRootOfTrustRequest { root_of_trust: root_of_trust.to_vec() })?; 282 Ok(()) 283 } 284 #[cfg(feature = "hal_v4")] setAdditionalAttestationInfo( &self, info: &[keymint::KeyParameter::KeyParameter], ) -> binder::Result<()>285 fn setAdditionalAttestationInfo( 286 &self, 287 info: &[keymint::KeyParameter::KeyParameter], 288 ) -> binder::Result<()> { 289 let _rsp: SetAdditionalAttestationInfoResponse = 290 self.execute(SetAdditionalAttestationInfoRequest { 291 info: info 292 .iter() 293 .filter_map(|p| p.try_innto().transpose()) 294 .collect::<Result<Vec<KeyParam>, _>>() 295 .map_err(failed_conversion)?, 296 })?; 297 Ok(()) 298 } 299 } 300 301 /// Representation of an in-progress KeyMint operation on a `SerializedChannel`. 302 #[derive(Debug)] 303 struct Operation<T: SerializedChannel + 'static> { 304 channel: Arc<Mutex<T>>, 305 op_handle: RwLock<Option<i64>>, 306 } 307 308 impl<T: SerializedChannel + 'static> Drop for Operation<T> { drop(&mut self)309 fn drop(&mut self) { 310 // Ensure that the TA is kept up-to-date by calling `abort()`, but ignore the result. 311 let _ = self.abort(); 312 } 313 } 314 315 impl<T: SerializedChannel> ChannelHalService<T> for Operation<T> { channel(&self) -> MutexGuard<T>316 fn channel(&self) -> MutexGuard<T> { 317 self.channel.lock().unwrap() 318 } 319 320 /// Execute the given request as part of the operation. If the request fails, the operation is 321 /// invalidated (and any future requests for the operation will fail). execute<R, S>(&self, req: R) -> binder::Result<S> where R: AsCborValue + Code<KeyMintOperation>, S: AsCborValue + Code<KeyMintOperation>,322 fn execute<R, S>(&self, req: R) -> binder::Result<S> 323 where 324 R: AsCborValue + Code<KeyMintOperation>, 325 S: AsCborValue + Code<KeyMintOperation>, 326 { 327 let result = super::channel_execute(self.channel().deref_mut(), req); 328 if result.is_err() { 329 // Any failed method on an operation terminates the operation. 330 self.invalidate(); 331 } 332 result 333 } 334 } 335 336 impl<T: SerializedChannel> binder::Interface for Operation<T> {} 337 338 impl<T: SerializedChannel + 'static> Operation<T> { 339 /// Create a new `Operation` wrapped in a proxy object. new_as_binder( channel: Arc<Mutex<T>>, op_handle: i64, ) -> binder::Strong<dyn keymint::IKeyMintOperation::IKeyMintOperation>340 fn new_as_binder( 341 channel: Arc<Mutex<T>>, 342 op_handle: i64, 343 ) -> binder::Strong<dyn keymint::IKeyMintOperation::IKeyMintOperation> { 344 let op = Self { channel, op_handle: RwLock::new(Some(op_handle)) }; 345 keymint::IKeyMintOperation::BnKeyMintOperation::new_binder( 346 op, 347 binder::BinderFeatures::default(), 348 ) 349 } 350 } 351 352 impl<T: SerializedChannel> Operation<T> { 353 // Maximum size allowed for the operation data. 354 const MAX_DATA_SIZE: usize = T::MAX_SIZE - MAX_CBOR_OVERHEAD; 355 356 /// Invalidate the operation. invalidate(&self)357 fn invalidate(&self) { 358 *self.op_handle.write().unwrap() = None; 359 } 360 361 /// Retrieve the operation handle, if not already failed. validate_handle(&self) -> binder::Result<i64>362 fn validate_handle(&self) -> binder::Result<i64> { 363 self.op_handle.read().unwrap().ok_or_else(|| { 364 binder::Status::new_service_specific_error( 365 keymint::ErrorCode::ErrorCode::INVALID_OPERATION_HANDLE.0, 366 Some(&CString::new("Operation handle not valid").unwrap()), 367 ) 368 }) 369 } 370 } 371 372 /// Implement the `IKeyMintOperation` interface for a [`Operation`]. Each method invocation is 373 /// serialized into a request message that is sent over the `Operation`'s channel, and a 374 /// corresponding response message is read. This response message is deserialized back into the 375 /// method's output value(s). 376 impl<T: SerializedChannel + 'static> keymint::IKeyMintOperation::IKeyMintOperation 377 for Operation<T> 378 { updateAad( &self, mut input: &[u8], authToken: Option<&keymint::HardwareAuthToken::HardwareAuthToken>, timeStampToken: Option<&TimeStampToken>, ) -> binder::Result<()>379 fn updateAad( 380 &self, 381 mut input: &[u8], 382 authToken: Option<&keymint::HardwareAuthToken::HardwareAuthToken>, 383 timeStampToken: Option<&TimeStampToken>, 384 ) -> binder::Result<()> { 385 let req_template = UpdateAadRequest { 386 op_handle: self.validate_handle()?, 387 input: vec![], 388 auth_token: match authToken { 389 None => None, 390 Some(t) => Some(t.clone().try_innto().map_err(failed_conversion)?), 391 }, 392 timestamp_token: timeStampToken.map(|t| t.clone().innto()), 393 }; 394 while !input.is_empty() { 395 let mut req = req_template.clone(); 396 let batch_len = core::cmp::min(Self::MAX_DATA_SIZE, input.len()); 397 req.input = input[..batch_len].to_vec(); 398 input = &input[batch_len..]; 399 let _rsp: UpdateAadResponse = self.execute(req).inspect_err(|_| { 400 // Any failure invalidates the operation 401 self.invalidate(); 402 })?; 403 } 404 Ok(()) 405 } update( &self, mut input: &[u8], authToken: Option<&keymint::HardwareAuthToken::HardwareAuthToken>, timeStampToken: Option<&TimeStampToken>, ) -> binder::Result<Vec<u8>>406 fn update( 407 &self, 408 mut input: &[u8], 409 authToken: Option<&keymint::HardwareAuthToken::HardwareAuthToken>, 410 timeStampToken: Option<&TimeStampToken>, 411 ) -> binder::Result<Vec<u8>> { 412 let req_template = UpdateRequest { 413 op_handle: self.validate_handle()?, 414 input: input.to_vec(), 415 auth_token: match authToken { 416 None => None, 417 Some(t) => Some(t.clone().try_innto().map_err(failed_conversion)?), 418 }, 419 timestamp_token: timeStampToken.map(|t| t.clone().innto()), 420 }; 421 let mut output = vec![]; 422 while !input.is_empty() { 423 let mut req = req_template.clone(); 424 let batch_len = core::cmp::min(Self::MAX_DATA_SIZE, input.len()); 425 req.input = input[..batch_len].to_vec(); 426 input = &input[batch_len..]; 427 let rsp: UpdateResponse = self.execute(req).inspect_err(|_| { 428 self.invalidate(); 429 })?; 430 output.extend_from_slice(&rsp.ret); 431 } 432 Ok(output) 433 } finish( &self, input: Option<&[u8]>, signature: Option<&[u8]>, authToken: Option<&keymint::HardwareAuthToken::HardwareAuthToken>, timestampToken: Option<&TimeStampToken>, confirmationToken: Option<&[u8]>, ) -> binder::Result<Vec<u8>>434 fn finish( 435 &self, 436 input: Option<&[u8]>, 437 signature: Option<&[u8]>, 438 authToken: Option<&keymint::HardwareAuthToken::HardwareAuthToken>, 439 timestampToken: Option<&TimeStampToken>, 440 confirmationToken: Option<&[u8]>, 441 ) -> binder::Result<Vec<u8>> { 442 let op_handle = self.validate_handle()?; 443 let auth_token = match authToken { 444 None => None, 445 Some(t) => Some(t.clone().try_innto().map_err(failed_conversion)?), 446 }; 447 let timestamp_token = timestampToken.map(|t| t.clone().innto()); 448 let confirmation_token = confirmationToken.map(|v| v.to_vec()); 449 450 let mut output = vec![]; 451 let result: binder::Result<FinishResponse> = if let Some(mut input) = input { 452 let MAX_DATA_SIZE = Self::MAX_DATA_SIZE; 453 while input.len() > MAX_DATA_SIZE { 454 let req = UpdateRequest { 455 op_handle, 456 input: input[..MAX_DATA_SIZE].to_vec(), 457 auth_token: auth_token.clone(), 458 timestamp_token: timestamp_token.clone(), 459 }; 460 input = &input[MAX_DATA_SIZE..]; 461 let rsp: UpdateResponse = self.execute(req).inspect_err(|_| { 462 self.invalidate(); 463 })?; 464 output.extend_from_slice(&rsp.ret); 465 } 466 467 self.execute(FinishRequest { 468 op_handle, 469 input: Some(input.to_vec()), 470 signature: signature.map(|v| v.to_vec()), 471 auth_token, 472 timestamp_token, 473 confirmation_token, 474 }) 475 } else { 476 self.execute(FinishRequest { 477 op_handle, 478 input: None, 479 signature: signature.map(|v| v.to_vec()), 480 auth_token, 481 timestamp_token, 482 confirmation_token, 483 }) 484 }; 485 // Finish always invalidates the operation. 486 self.invalidate(); 487 result.map(|rsp| { 488 output.extend_from_slice(&rsp.ret); 489 output 490 }) 491 } abort(&self) -> binder::Result<()>492 fn abort(&self) -> binder::Result<()> { 493 let result: binder::Result<AbortResponse> = 494 self.execute(AbortRequest { op_handle: self.validate_handle()? }); 495 // Abort always invalidates the operation. 496 self.invalidate(); 497 let _ = result?; 498 Ok(()) 499 } 500 } 501