Skip to main content

rsbinder/
error.rs

1// Copyright 2022 Jeff Kim <hiking90@gmail.com>
2// SPDX-License-Identifier: Apache-2.0
3
4//! Error handling and status codes for binder operations.
5//!
6//! This module defines the result types and error codes used throughout
7//! the binder library for consistent error handling across IPC operations.
8
9use std::error::Error;
10use std::fmt;
11
12/// Result type alias for binder operations.
13pub type Result<T> = std::result::Result<T, StatusCode>;
14
15const UNKNOWN_ERROR: i32 = -2147483647 - 1;
16
17/// Status codes for binder operations.
18///
19/// Represents various error conditions that can occur during binder IPC operations,
20/// including system errors, protocol errors, and application-specific errors.
21#[derive(Default, Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
22#[non_exhaustive]
23pub enum StatusCode {
24    /// Operation completed successfully
25    #[default]
26    Ok,
27    /// Unknown error occurred
28    Unknown,
29    /// Out of memory
30    NoMemory,
31    /// Invalid operation for current state
32    InvalidOperation,
33    /// Invalid parameter value
34    BadValue,
35    /// Wrong data type
36    BadType,
37    /// Named resource not found
38    NameNotFound,
39    /// Permission denied
40    PermissionDenied,
41    /// Object not initialized
42    NoInit,
43    /// Resource already exists
44    AlreadyExists,
45    /// Remote object is dead
46    DeadObject,
47    /// Transaction failed
48    FailedTransaction,
49    /// Unknown transaction code
50    UnknownTransaction,
51    /// Invalid array index
52    BadIndex,
53    /// File descriptors not allowed
54    FdsNotAllowed,
55    /// Unexpected null pointer
56    UnexpectedNull,
57    /// Not enough data available
58    NotEnoughData,
59    /// Operation would block
60    WouldBlock,
61    /// Operation timed out
62    TimedOut,
63    /// Bad file descriptor
64    BadFd,
65    /// System errno value
66    Errno(i32),
67    /// Service-specific error code
68    ServiceSpecific(i32),
69}
70
71impl Error for StatusCode {}
72
73impl fmt::Display for StatusCode {
74    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75        match self {
76            StatusCode::Ok => write!(f, "Ok"),
77            StatusCode::Unknown => write!(f, "Unknown"),
78            StatusCode::NoMemory => write!(f, "NoMemory"),
79            StatusCode::InvalidOperation => write!(f, "InvalidOperation"),
80            StatusCode::BadValue => write!(f, "BadValue"),
81            StatusCode::BadType => write!(f, "BadType"),
82            StatusCode::NameNotFound => write!(f, "NameNotFound"),
83            StatusCode::PermissionDenied => write!(f, "PermissionDenied"),
84            StatusCode::NoInit => write!(f, "NoInit"),
85            StatusCode::AlreadyExists => write!(f, "AlreadyExists"),
86            StatusCode::DeadObject => write!(f, "DeadObject"),
87            StatusCode::FailedTransaction => write!(f, "FailedTransaction"),
88            StatusCode::UnknownTransaction => write!(f, "UnknownTransaction"),
89            StatusCode::BadIndex => write!(f, "BadIndex"),
90            StatusCode::FdsNotAllowed => write!(f, "FdsNotAllowed"),
91            StatusCode::UnexpectedNull => write!(f, "UnexpectedNull"),
92            StatusCode::NotEnoughData => write!(f, "NotEnoughData"),
93            StatusCode::WouldBlock => write!(f, "WouldBlock"),
94            StatusCode::TimedOut => write!(f, "TimedOut"),
95            StatusCode::BadFd => write!(f, "BadFd"),
96            StatusCode::Errno(errno) => write!(f, "Errno({errno})"),
97            StatusCode::ServiceSpecific(v) => write!(f, "ServiceSpecific({v})"),
98        }
99    }
100}
101
102impl From<StatusCode> for i32 {
103    fn from(code: StatusCode) -> Self {
104        match code {
105            StatusCode::Ok => 0,
106            StatusCode::Unknown => UNKNOWN_ERROR as _,
107            StatusCode::NoMemory => -(rustix::io::Errno::NOMEM.raw_os_error()),
108            StatusCode::InvalidOperation => -(rustix::io::Errno::NOSYS.raw_os_error()),
109            StatusCode::BadValue => -(rustix::io::Errno::INVAL.raw_os_error()),
110            StatusCode::BadType => UNKNOWN_ERROR + 1,
111            StatusCode::NameNotFound => -(rustix::io::Errno::NOENT.raw_os_error()),
112            StatusCode::PermissionDenied => -(rustix::io::Errno::PERM.raw_os_error()),
113            StatusCode::NoInit => -(rustix::io::Errno::NODEV.raw_os_error()),
114            StatusCode::AlreadyExists => -(rustix::io::Errno::EXIST.raw_os_error()),
115            StatusCode::DeadObject => -(rustix::io::Errno::PIPE.raw_os_error()),
116            StatusCode::FailedTransaction => UNKNOWN_ERROR + 2,
117            StatusCode::UnknownTransaction => -(rustix::io::Errno::BADMSG.raw_os_error()),
118            StatusCode::BadIndex => -(rustix::io::Errno::OVERFLOW.raw_os_error()),
119            StatusCode::FdsNotAllowed => UNKNOWN_ERROR + 7,
120            StatusCode::UnexpectedNull => UNKNOWN_ERROR + 8,
121            StatusCode::NotEnoughData => -(rustix::io::Errno::NODATA.raw_os_error()),
122            StatusCode::WouldBlock => -(rustix::io::Errno::WOULDBLOCK.raw_os_error()),
123            StatusCode::TimedOut => -(rustix::io::Errno::TIMEDOUT.raw_os_error()),
124            StatusCode::BadFd => -(rustix::io::Errno::BADF.raw_os_error()),
125            StatusCode::ServiceSpecific(v) => v,
126            StatusCode::Errno(errno) => errno,
127        }
128    }
129}
130
131impl From<i32> for StatusCode {
132    fn from(code: i32) -> Self {
133        match code {
134            code if code == StatusCode::Ok.into() => StatusCode::Ok,
135            code if code == StatusCode::Unknown.into() => StatusCode::Unknown,
136            code if code == StatusCode::NoMemory.into() => StatusCode::NoMemory,
137            code if code == StatusCode::InvalidOperation.into() => StatusCode::InvalidOperation,
138            code if code == StatusCode::BadValue.into() => StatusCode::BadValue,
139            code if code == StatusCode::BadType.into() => StatusCode::BadType,
140            code if code == StatusCode::NameNotFound.into() => StatusCode::NameNotFound,
141            code if code == StatusCode::PermissionDenied.into() => StatusCode::PermissionDenied,
142            code if code == StatusCode::NoInit.into() => StatusCode::NoInit,
143            code if code == StatusCode::AlreadyExists.into() => StatusCode::AlreadyExists,
144            code if code == StatusCode::DeadObject.into() => StatusCode::DeadObject,
145            code if code == StatusCode::FailedTransaction.into() => StatusCode::FailedTransaction,
146            code if code == StatusCode::UnknownTransaction.into() => StatusCode::UnknownTransaction,
147            code if code == StatusCode::BadIndex.into() => StatusCode::BadIndex,
148            code if code == StatusCode::FdsNotAllowed.into() => StatusCode::FdsNotAllowed,
149            code if code == StatusCode::UnexpectedNull.into() => StatusCode::UnexpectedNull,
150            code if code == StatusCode::NotEnoughData.into() => StatusCode::NotEnoughData,
151            code if code == StatusCode::WouldBlock.into() => StatusCode::WouldBlock,
152            code if code == StatusCode::TimedOut.into() => StatusCode::TimedOut,
153            code if code == StatusCode::BadFd.into() => StatusCode::BadFd,
154            code if code < 0 => StatusCode::Errno(code),
155            _ => StatusCode::ServiceSpecific(code),
156        }
157    }
158}
159
160impl From<std::array::TryFromSliceError> for StatusCode {
161    fn from(_: std::array::TryFromSliceError) -> Self {
162        StatusCode::NotEnoughData
163    }
164}
165
166impl From<std::io::Error> for StatusCode {
167    fn from(_: std::io::Error) -> Self {
168        StatusCode::BadFd
169    }
170}
171
172impl From<rustix::io::Errno> for StatusCode {
173    fn from(errno: rustix::io::Errno) -> Self {
174        match errno {
175            rustix::io::Errno::NOMEM => StatusCode::NoMemory,
176            rustix::io::Errno::NOSYS => StatusCode::InvalidOperation,
177            rustix::io::Errno::INVAL => StatusCode::BadValue,
178            rustix::io::Errno::NOENT => StatusCode::NameNotFound,
179            rustix::io::Errno::PERM => StatusCode::PermissionDenied,
180            rustix::io::Errno::NODEV => StatusCode::NoInit,
181            rustix::io::Errno::EXIST => StatusCode::AlreadyExists,
182            rustix::io::Errno::PIPE => StatusCode::DeadObject,
183            rustix::io::Errno::BADMSG => StatusCode::UnknownTransaction,
184            rustix::io::Errno::OVERFLOW => StatusCode::BadIndex,
185            rustix::io::Errno::NODATA => StatusCode::NotEnoughData,
186            rustix::io::Errno::WOULDBLOCK => StatusCode::WouldBlock,
187            rustix::io::Errno::TIMEDOUT => StatusCode::TimedOut,
188            rustix::io::Errno::BADF => StatusCode::BadFd,
189            _ => StatusCode::Errno(-errno.raw_os_error()),
190        }
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use super::*;
197
198    #[test]
199    fn test_status_code() {
200        let code = StatusCode::Ok;
201        assert_eq!(code, StatusCode::from(0));
202        assert_eq!(code, StatusCode::from(Into::<i32>::into(StatusCode::Ok)));
203
204        let code = StatusCode::Unknown;
205        assert_eq!(code, StatusCode::from(UNKNOWN_ERROR));
206        assert_eq!(
207            code,
208            StatusCode::from(Into::<i32>::into(StatusCode::Unknown))
209        );
210
211        let code = StatusCode::NoMemory;
212        assert_eq!(
213            code,
214            StatusCode::from(-(rustix::io::Errno::NOMEM.raw_os_error()))
215        );
216        assert_eq!(
217            code,
218            StatusCode::from(Into::<i32>::into(StatusCode::NoMemory))
219        );
220
221        let code = StatusCode::InvalidOperation;
222        assert_eq!(
223            code,
224            StatusCode::from(-(rustix::io::Errno::NOSYS.raw_os_error()))
225        );
226        assert_eq!(
227            code,
228            StatusCode::from(Into::<i32>::into(StatusCode::InvalidOperation))
229        );
230
231        let code = StatusCode::BadValue;
232        assert_eq!(
233            code,
234            StatusCode::from(-(rustix::io::Errno::INVAL.raw_os_error()))
235        );
236        assert_eq!(
237            code,
238            StatusCode::from(Into::<i32>::into(StatusCode::BadValue))
239        );
240
241        let code = StatusCode::BadType;
242        assert_eq!(code, StatusCode::from(UNKNOWN_ERROR + 1));
243        assert_eq!(
244            code,
245            StatusCode::from(Into::<i32>::into(StatusCode::BadType))
246        );
247
248        let code = StatusCode::NameNotFound;
249        assert_eq!(
250            code,
251            StatusCode::from(-(rustix::io::Errno::NOENT.raw_os_error()))
252        );
253        assert_eq!(
254            code,
255            StatusCode::from(Into::<i32>::into(StatusCode::NameNotFound))
256        );
257
258        let code = StatusCode::PermissionDenied;
259        assert_eq!(
260            code,
261            StatusCode::from(-(rustix::io::Errno::PERM.raw_os_error()))
262        );
263        assert_eq!(
264            code,
265            StatusCode::from(Into::<i32>::into(StatusCode::PermissionDenied))
266        );
267
268        let code = StatusCode::NoInit;
269        assert_eq!(
270            code,
271            StatusCode::from(-(rustix::io::Errno::NODEV.raw_os_error()))
272        );
273        assert_eq!(
274            code,
275            StatusCode::from(Into::<i32>::into(StatusCode::NoInit))
276        );
277
278        let code = StatusCode::AlreadyExists;
279        assert_eq!(
280            code,
281            StatusCode::from(-(rustix::io::Errno::EXIST.raw_os_error()))
282        );
283        assert_eq!(
284            code,
285            StatusCode::from(Into::<i32>::into(StatusCode::AlreadyExists))
286        );
287
288        let code = StatusCode::DeadObject;
289        assert_eq!(
290            code,
291            StatusCode::from(-(rustix::io::Errno::PIPE.raw_os_error()))
292        );
293        assert_eq!(
294            code,
295            StatusCode::from(Into::<i32>::into(StatusCode::DeadObject))
296        );
297
298        let code = StatusCode::FailedTransaction;
299        assert_eq!(code, StatusCode::from(UNKNOWN_ERROR + 2));
300        assert_eq!(
301            code,
302            StatusCode::from(Into::<i32>::into(StatusCode::FailedTransaction))
303        );
304
305        let code = StatusCode::UnknownTransaction;
306        assert_eq!(
307            code,
308            StatusCode::from(-(rustix::io::Errno::BADMSG.raw_os_error()))
309        );
310        assert_eq!(
311            code,
312            StatusCode::from(Into::<i32>::into(StatusCode::UnknownTransaction))
313        );
314
315        let code = StatusCode::BadIndex;
316        assert_eq!(
317            code,
318            StatusCode::from(-(rustix::io::Errno::OVERFLOW.raw_os_error()))
319        );
320        assert_eq!(
321            code,
322            StatusCode::from(Into::<i32>::into(StatusCode::BadIndex))
323        );
324
325        let code = StatusCode::FdsNotAllowed;
326        assert_eq!(code, StatusCode::from(UNKNOWN_ERROR + 7));
327        assert_eq!(
328            code,
329            StatusCode::from(Into::<i32>::into(StatusCode::FdsNotAllowed))
330        );
331
332        let code = StatusCode::UnexpectedNull;
333        assert_eq!(code, StatusCode::from(UNKNOWN_ERROR + 8));
334        assert_eq!(
335            code,
336            StatusCode::from(Into::<i32>::into(StatusCode::UnexpectedNull))
337        );
338
339        let code = StatusCode::NotEnoughData;
340        assert_eq!(
341            code,
342            StatusCode::from(-(rustix::io::Errno::NODATA.raw_os_error()))
343        );
344        assert_eq!(
345            code,
346            StatusCode::from(Into::<i32>::into(StatusCode::NotEnoughData))
347        );
348
349        let code = StatusCode::WouldBlock;
350        assert_eq!(
351            code,
352            StatusCode::from(-(rustix::io::Errno::WOULDBLOCK.raw_os_error()))
353        );
354        assert_eq!(
355            code,
356            StatusCode::from(Into::<i32>::into(StatusCode::WouldBlock))
357        );
358
359        let code = StatusCode::TimedOut;
360        assert_eq!(
361            code,
362            StatusCode::from(-(rustix::io::Errno::TIMEDOUT.raw_os_error()))
363        );
364        assert_eq!(
365            code,
366            StatusCode::from(Into::<i32>::into(StatusCode::TimedOut))
367        );
368
369        let code = StatusCode::BadFd;
370        assert_eq!(
371            code,
372            StatusCode::from(-(rustix::io::Errno::BADF.raw_os_error()))
373        );
374        assert_eq!(code, StatusCode::from(Into::<i32>::into(StatusCode::BadFd)));
375
376        let code = StatusCode::ServiceSpecific(1);
377        assert_eq!(code, StatusCode::from(1));
378        assert_eq!(
379            code,
380            StatusCode::from(Into::<i32>::into(StatusCode::ServiceSpecific(1)))
381        );
382
383        let code: StatusCode = StatusCode::Errno(-64);
384        assert_eq!(code, StatusCode::from(-64));
385        assert_eq!(
386            code,
387            StatusCode::from(Into::<i32>::into(StatusCode::Errno(-64)))
388        );
389    }
390
391    #[test]
392    fn test_status_code_from_errno() {
393        let code = StatusCode::from(rustix::io::Errno::NOMEM);
394        assert_eq!(code, StatusCode::NoMemory);
395
396        let code = StatusCode::from(rustix::io::Errno::NOSYS);
397        assert_eq!(code, StatusCode::InvalidOperation);
398
399        let code = StatusCode::from(rustix::io::Errno::INVAL);
400        assert_eq!(code, StatusCode::BadValue);
401
402        let code = StatusCode::from(rustix::io::Errno::NOENT);
403        assert_eq!(code, StatusCode::NameNotFound);
404
405        let code = StatusCode::from(rustix::io::Errno::PERM);
406        assert_eq!(code, StatusCode::PermissionDenied);
407
408        let code = StatusCode::from(rustix::io::Errno::NODEV);
409        assert_eq!(code, StatusCode::NoInit);
410
411        let code = StatusCode::from(rustix::io::Errno::EXIST);
412        assert_eq!(code, StatusCode::AlreadyExists);
413
414        let code = StatusCode::from(rustix::io::Errno::PIPE);
415        assert_eq!(code, StatusCode::DeadObject);
416
417        let code = StatusCode::from(rustix::io::Errno::BADMSG);
418        assert_eq!(code, StatusCode::UnknownTransaction);
419
420        let code = StatusCode::from(rustix::io::Errno::OVERFLOW);
421        assert_eq!(code, StatusCode::BadIndex);
422
423        let code = StatusCode::from(rustix::io::Errno::NODATA);
424        assert_eq!(code, StatusCode::NotEnoughData);
425
426        let code = StatusCode::from(rustix::io::Errno::WOULDBLOCK);
427        assert_eq!(code, StatusCode::WouldBlock);
428
429        let code = StatusCode::from(rustix::io::Errno::TIMEDOUT);
430        assert_eq!(code, StatusCode::TimedOut);
431
432        let code = StatusCode::from(rustix::io::Errno::BADF);
433        assert_eq!(code, StatusCode::BadFd);
434
435        let code = StatusCode::from(rustix::io::Errno::from_raw_os_error(64));
436        assert_eq!(code, StatusCode::Errno(-64));
437    }
438}