1use crate::binder::AsNative;
18use crate::sys;
19
20use std::error;
21use std::ffi::{CStr, CString};
22use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
23use std::ptr;
24use std::result;
25
26pub use sys::binder_status_t as status_t;
27
28pub use sys::android_c_interface_StatusCode as StatusCode;
32
33pub type Result<T> = result::Result<T, StatusCode>;
35
36pub fn status_result(status: status_t) -> Result<()> {
41 match parse_status_code(status) {
42 StatusCode::OK => Ok(()),
43 e => Err(e),
44 }
45}
46
47fn parse_status_code(code: i32) -> StatusCode {
48 match code {
49 e if e == StatusCode::OK as i32 => StatusCode::OK,
50 e if e == StatusCode::NO_MEMORY as i32 => StatusCode::NO_MEMORY,
51 e if e == StatusCode::INVALID_OPERATION as i32 => StatusCode::INVALID_OPERATION,
52 e if e == StatusCode::BAD_VALUE as i32 => StatusCode::BAD_VALUE,
53 e if e == StatusCode::BAD_TYPE as i32 => StatusCode::BAD_TYPE,
54 e if e == StatusCode::NAME_NOT_FOUND as i32 => StatusCode::NAME_NOT_FOUND,
55 e if e == StatusCode::PERMISSION_DENIED as i32 => StatusCode::PERMISSION_DENIED,
56 e if e == StatusCode::NO_INIT as i32 => StatusCode::NO_INIT,
57 e if e == StatusCode::ALREADY_EXISTS as i32 => StatusCode::ALREADY_EXISTS,
58 e if e == StatusCode::DEAD_OBJECT as i32 => StatusCode::DEAD_OBJECT,
59 e if e == StatusCode::FAILED_TRANSACTION as i32 => StatusCode::FAILED_TRANSACTION,
60 e if e == StatusCode::BAD_INDEX as i32 => StatusCode::BAD_INDEX,
61 e if e == StatusCode::NOT_ENOUGH_DATA as i32 => StatusCode::NOT_ENOUGH_DATA,
62 e if e == StatusCode::WOULD_BLOCK as i32 => StatusCode::WOULD_BLOCK,
63 e if e == StatusCode::TIMED_OUT as i32 => StatusCode::TIMED_OUT,
64 e if e == StatusCode::UNKNOWN_TRANSACTION as i32 => StatusCode::UNKNOWN_TRANSACTION,
65 e if e == StatusCode::FDS_NOT_ALLOWED as i32 => StatusCode::FDS_NOT_ALLOWED,
66 e if e == StatusCode::UNEXPECTED_NULL as i32 => StatusCode::UNEXPECTED_NULL,
67 _ => StatusCode::UNKNOWN_ERROR,
68 }
69}
70
71pub use sys::android_c_interface_ExceptionCode as ExceptionCode;
72
73fn parse_exception_code(code: i32) -> ExceptionCode {
74 match code {
75 e if e == ExceptionCode::NONE as i32 => ExceptionCode::NONE,
76 e if e == ExceptionCode::SECURITY as i32 => ExceptionCode::SECURITY,
77 e if e == ExceptionCode::BAD_PARCELABLE as i32 => ExceptionCode::BAD_PARCELABLE,
78 e if e == ExceptionCode::ILLEGAL_ARGUMENT as i32 => ExceptionCode::ILLEGAL_ARGUMENT,
79 e if e == ExceptionCode::NULL_POINTER as i32 => ExceptionCode::NULL_POINTER,
80 e if e == ExceptionCode::ILLEGAL_STATE as i32 => ExceptionCode::ILLEGAL_STATE,
81 e if e == ExceptionCode::NETWORK_MAIN_THREAD as i32 => ExceptionCode::NETWORK_MAIN_THREAD,
82 e if e == ExceptionCode::UNSUPPORTED_OPERATION as i32 => {
83 ExceptionCode::UNSUPPORTED_OPERATION
84 }
85 e if e == ExceptionCode::SERVICE_SPECIFIC as i32 => ExceptionCode::SERVICE_SPECIFIC,
86 _ => ExceptionCode::TRANSACTION_FAILED,
87 }
88}
89
90pub struct Status(ptr::NonNull<sys::AStatus>);
97
98unsafe impl Sync for Status {}
103
104unsafe impl Send for Status {}
107
108fn to_cstring<T: AsRef<str>>(message: T) -> Option<CString> {
109 CString::new(message.as_ref()).ok()
110}
111
112impl Status {
113 pub fn ok() -> Self {
115 let ptr = unsafe { sys::AStatus_newOk() };
121 Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
122 }
123
124 pub fn new_service_specific_error(err: i32, message: Option<&CStr>) -> Status {
126 let ptr = if let Some(message) = message {
127 unsafe { sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr()) }
136 } else {
137 unsafe { sys::AStatus_fromServiceSpecificError(err) }
144 };
145 Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
146 }
147
148 pub fn new_service_specific_error_str<T: AsRef<str>>(err: i32, message: Option<T>) -> Status {
150 Self::new_service_specific_error(err, message.and_then(to_cstring).as_deref())
151 }
152
153 pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status {
155 if let Some(message) = message {
156 let ptr = unsafe {
159 sys::AStatus_fromExceptionCodeWithMessage(exception as i32, message.as_ptr())
160 };
161 Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
162 } else {
163 exception.into()
164 }
165 }
166
167 pub fn new_exception_str<T: AsRef<str>>(
169 exception: ExceptionCode,
170 message: Option<T>,
171 ) -> Status {
172 Self::new_exception(exception, message.and_then(to_cstring).as_deref())
173 }
174
175 pub(crate) unsafe fn from_ptr(ptr: *mut sys::AStatus) -> Self {
181 Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
182 }
183
184 pub fn is_ok(&self) -> bool {
186 unsafe { sys::AStatus_isOk(self.as_native()) }
189 }
190
191 pub fn get_description(&self) -> String {
193 let description_ptr = unsafe { sys::AStatus_getDescription(self.as_native()) };
201 let description = unsafe { CStr::from_ptr(description_ptr) };
204 let description = description.to_string_lossy().to_string();
205 unsafe {
211 sys::AStatus_deleteDescription(description_ptr);
212 }
213 description
214 }
215
216 pub fn exception_code(&self) -> ExceptionCode {
218 let code = unsafe { sys::AStatus_getExceptionCode(self.as_native()) };
222 parse_exception_code(code)
223 }
224
225 pub fn transaction_error(&self) -> StatusCode {
232 let code = unsafe { sys::AStatus_getStatus(self.as_native()) };
235 parse_status_code(code)
236 }
237
238 pub fn service_specific_error(&self) -> i32 {
247 unsafe { sys::AStatus_getServiceSpecificError(self.as_native()) }
251 }
252
253 pub fn and_then<T, F>(self, op: F) -> result::Result<T, Status>
256 where
257 F: FnOnce() -> result::Result<T, Status>,
258 {
259 <result::Result<(), Status>>::from(self)?;
260 op()
261 }
262}
263
264impl error::Error for Status {}
265
266impl Display for Status {
267 fn fmt(&self, f: &mut Formatter) -> FmtResult {
268 f.write_str(&self.get_description())
269 }
270}
271
272impl Debug for Status {
273 fn fmt(&self, f: &mut Formatter) -> FmtResult {
274 f.write_str(&self.get_description())
275 }
276}
277
278impl PartialEq for Status {
279 fn eq(&self, other: &Status) -> bool {
280 let self_code = self.exception_code();
281 let other_code = other.exception_code();
282
283 match (self_code, other_code) {
284 (ExceptionCode::NONE, ExceptionCode::NONE) => true,
285 (ExceptionCode::TRANSACTION_FAILED, ExceptionCode::TRANSACTION_FAILED) => {
286 self.transaction_error() == other.transaction_error()
287 && self.get_description() == other.get_description()
288 }
289 (ExceptionCode::SERVICE_SPECIFIC, ExceptionCode::SERVICE_SPECIFIC) => {
290 self.service_specific_error() == other.service_specific_error()
291 && self.get_description() == other.get_description()
292 }
293 (e1, e2) => e1 == e2 && self.get_description() == other.get_description(),
294 }
295 }
296}
297
298impl Eq for Status {}
299
300impl From<StatusCode> for Status {
301 fn from(status: StatusCode) -> Status {
302 (status as status_t).into()
303 }
304}
305
306impl From<status_t> for Status {
307 fn from(status: status_t) -> Status {
308 let ptr = unsafe { sys::AStatus_fromStatus(status) };
312 Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
313 }
314}
315
316impl From<ExceptionCode> for Status {
317 fn from(code: ExceptionCode) -> Status {
318 let ptr = unsafe { sys::AStatus_fromExceptionCode(code as i32) };
322 Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
323 }
324}
325
326impl From<Status> for result::Result<(), Status> {
329 fn from(status: Status) -> result::Result<(), Status> {
330 if status.is_ok() {
331 Ok(())
332 } else {
333 Err(status)
334 }
335 }
336}
337
338impl From<Status> for status_t {
339 fn from(status: Status) -> status_t {
340 status.transaction_error() as status_t
341 }
342}
343
344impl Drop for Status {
345 fn drop(&mut self) {
346 unsafe {
351 sys::AStatus_delete(self.0.as_mut());
352 }
353 }
354}
355
356unsafe impl AsNative<sys::AStatus> for Status {
362 fn as_native(&self) -> *const sys::AStatus {
363 self.0.as_ptr()
364 }
365
366 fn as_native_mut(&mut self) -> *mut sys::AStatus {
367 unsafe { self.0.as_mut() }
370 }
371}
372
373pub trait IntoBinderResult<T, E> {
408 fn or_binder_exception(self, exception: ExceptionCode) -> result::Result<T, Status>;
411
412 fn or_binder_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
415 self,
416 exception: ExceptionCode,
417 op: O,
418 ) -> result::Result<T, Status>;
419
420 fn or_service_specific_exception(self, error_code: i32) -> result::Result<T, Status>;
424
425 fn or_service_specific_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
429 self,
430 error_code: i32,
431 op: O,
432 ) -> result::Result<T, Status>;
433}
434
435impl<T, E: std::fmt::Debug> IntoBinderResult<T, E> for result::Result<T, E> {
436 fn or_binder_exception(self, exception: ExceptionCode) -> result::Result<T, Status> {
437 self.or_binder_exception_with(exception, |e| format!("{:?}", e))
438 }
439
440 fn or_binder_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
441 self,
442 exception: ExceptionCode,
443 op: O,
444 ) -> result::Result<T, Status> {
445 self.map_err(|e| Status::new_exception_str(exception, Some(op(e))))
446 }
447
448 fn or_service_specific_exception(self, error_code: i32) -> result::Result<T, Status> {
449 self.or_service_specific_exception_with(error_code, |e| format!("{:?}", e))
450 }
451
452 fn or_service_specific_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
453 self,
454 error_code: i32,
455 op: O,
456 ) -> result::Result<T, Status> {
457 self.map_err(|e| Status::new_service_specific_error_str(error_code, Some(op(e))))
458 }
459}
460
461#[cfg(test)]
462mod tests {
463 use super::*;
464
465 #[test]
466 fn make_service_specific_error() {
467 let status = Status::new_service_specific_error_str(-42, Some("message"));
468
469 assert!(!status.is_ok());
470 assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC);
471 assert_eq!(status.service_specific_error(), -42);
472 assert_eq!(
473 status.get_description(),
474 "Status(-8, EX_SERVICE_SPECIFIC): '-42: message'".to_string()
475 );
476 }
477
478 #[test]
479 fn make_exception() {
480 let status = Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some("message"));
481
482 assert!(!status.is_ok());
483 assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
484 assert_eq!(status.service_specific_error(), 0);
485 assert_eq!(status.get_description(), "Status(-5, EX_ILLEGAL_STATE): 'message'".to_string());
486 }
487
488 #[test]
489 fn make_exception_null() {
490 let status = Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some("one\0two"));
491
492 assert!(!status.is_ok());
493 assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
494 assert_eq!(status.service_specific_error(), 0);
495 assert_eq!(status.get_description(), "Status(-5, EX_ILLEGAL_STATE): ''".to_string());
496 }
497
498 #[test]
499 fn convert_to_service_specific_exception() {
500 let res: std::result::Result<(), Status> =
501 Err("message").or_service_specific_exception(-42);
502
503 assert!(res.is_err());
504 let status = res.unwrap_err();
505 assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC);
506 assert_eq!(status.service_specific_error(), -42);
507 assert_eq!(
508 status.get_description(),
509 "Status(-8, EX_SERVICE_SPECIFIC): '-42: \"message\"'".to_string()
510 );
511 }
512
513 #[test]
514 fn convert_to_service_specific_exception_with() {
515 let res: std::result::Result<(), Status> = Err("message")
516 .or_service_specific_exception_with(-42, |e| format!("outer message: {:?}", e));
517
518 assert!(res.is_err());
519 let status = res.unwrap_err();
520 assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC);
521 assert_eq!(status.service_specific_error(), -42);
522 assert_eq!(
523 status.get_description(),
524 "Status(-8, EX_SERVICE_SPECIFIC): '-42: outer message: \"message\"'".to_string()
525 );
526 }
527
528 #[test]
529 fn convert_to_binder_exception() {
530 let res: std::result::Result<(), Status> =
531 Err("message").or_binder_exception(ExceptionCode::ILLEGAL_STATE);
532
533 assert!(res.is_err());
534 let status = res.unwrap_err();
535 assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
536 assert_eq!(status.service_specific_error(), 0);
537 assert_eq!(
538 status.get_description(),
539 "Status(-5, EX_ILLEGAL_STATE): '\"message\"'".to_string()
540 );
541 }
542
543 #[test]
544 fn convert_to_binder_exception_with() {
545 let res: std::result::Result<(), Status> = Err("message")
546 .or_binder_exception_with(ExceptionCode::ILLEGAL_STATE, |e| {
547 format!("outer message: {:?}", e)
548 });
549
550 assert!(res.is_err());
551 let status = res.unwrap_err();
552 assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
553 assert_eq!(status.service_specific_error(), 0);
554 assert_eq!(
555 status.get_description(),
556 "Status(-5, EX_ILLEGAL_STATE): 'outer message: \"message\"'".to_string()
557 );
558 }
559}