1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 use crate::binder::AsNative;
18 use crate::sys;
19
20 use std::error;
21 use std::ffi::CStr;
22 use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
23 use std::result;
24
25 pub use sys::binder_status_t as status_t;
26
27 /// Low-level status codes from Android `libutils`.
28 // All error codes are negative integer values. Derived from the anonymous enum
29 // in utils/Errors.h
30 pub use sys::android_c_interface_StatusCode as StatusCode;
31
32 /// A specialized [`Result`](result::Result) for binder operations.
33 pub type Result<T> = result::Result<T, StatusCode>;
34
35 /// Convert a low-level status code into an empty result.
36 ///
37 /// An OK status is converted into an `Ok` result, any other status is converted
38 /// into an `Err` result holding the status code.
status_result(status: status_t) -> Result<()>39 pub fn status_result(status: status_t) -> Result<()> {
40 match parse_status_code(status) {
41 StatusCode::OK => Ok(()),
42 e => Err(e),
43 }
44 }
45
parse_status_code(code: i32) -> StatusCode46 fn parse_status_code(code: i32) -> StatusCode {
47 match code {
48 e if e == StatusCode::OK as i32 => StatusCode::OK,
49 e if e == StatusCode::NO_MEMORY as i32 => StatusCode::NO_MEMORY,
50 e if e == StatusCode::INVALID_OPERATION as i32 => StatusCode::INVALID_OPERATION,
51 e if e == StatusCode::BAD_VALUE as i32 => StatusCode::BAD_VALUE,
52 e if e == StatusCode::BAD_TYPE as i32 => StatusCode::BAD_TYPE,
53 e if e == StatusCode::NAME_NOT_FOUND as i32 => StatusCode::NAME_NOT_FOUND,
54 e if e == StatusCode::PERMISSION_DENIED as i32 => StatusCode::PERMISSION_DENIED,
55 e if e == StatusCode::NO_INIT as i32 => StatusCode::NO_INIT,
56 e if e == StatusCode::ALREADY_EXISTS as i32 => StatusCode::ALREADY_EXISTS,
57 e if e == StatusCode::DEAD_OBJECT as i32 => StatusCode::DEAD_OBJECT,
58 e if e == StatusCode::FAILED_TRANSACTION as i32 => StatusCode::FAILED_TRANSACTION,
59 e if e == StatusCode::BAD_INDEX as i32 => StatusCode::BAD_INDEX,
60 e if e == StatusCode::NOT_ENOUGH_DATA as i32 => StatusCode::NOT_ENOUGH_DATA,
61 e if e == StatusCode::WOULD_BLOCK as i32 => StatusCode::WOULD_BLOCK,
62 e if e == StatusCode::TIMED_OUT as i32 => StatusCode::TIMED_OUT,
63 e if e == StatusCode::UNKNOWN_TRANSACTION as i32 => StatusCode::UNKNOWN_TRANSACTION,
64 e if e == StatusCode::FDS_NOT_ALLOWED as i32 => StatusCode::FDS_NOT_ALLOWED,
65 e if e == StatusCode::UNEXPECTED_NULL as i32 => StatusCode::UNEXPECTED_NULL,
66 _ => StatusCode::UNKNOWN_ERROR,
67 }
68 }
69
70 pub use sys::android_c_interface_ExceptionCode as ExceptionCode;
71
parse_exception_code(code: i32) -> ExceptionCode72 fn parse_exception_code(code: i32) -> ExceptionCode {
73 match code {
74 e if e == ExceptionCode::NONE as i32 => ExceptionCode::NONE,
75 e if e == ExceptionCode::SECURITY as i32 => ExceptionCode::SECURITY,
76 e if e == ExceptionCode::BAD_PARCELABLE as i32 => ExceptionCode::BAD_PARCELABLE,
77 e if e == ExceptionCode::ILLEGAL_ARGUMENT as i32 => ExceptionCode::ILLEGAL_ARGUMENT,
78 e if e == ExceptionCode::NULL_POINTER as i32 => ExceptionCode::NULL_POINTER,
79 e if e == ExceptionCode::ILLEGAL_STATE as i32 => ExceptionCode::ILLEGAL_STATE,
80 e if e == ExceptionCode::NETWORK_MAIN_THREAD as i32 => ExceptionCode::NETWORK_MAIN_THREAD,
81 e if e == ExceptionCode::UNSUPPORTED_OPERATION as i32 => {
82 ExceptionCode::UNSUPPORTED_OPERATION
83 }
84 e if e == ExceptionCode::SERVICE_SPECIFIC as i32 => ExceptionCode::SERVICE_SPECIFIC,
85 _ => ExceptionCode::TRANSACTION_FAILED,
86 }
87 }
88
89 // Safety: `Status` always contains a owning pointer to a valid `AStatus`. The
90 // lifetime of the contained pointer is the same as the `Status` object.
91 /// High-level binder status object that encapsulates a standard way to keep
92 /// track of and chain binder errors along with service specific errors.
93 ///
94 /// Used in AIDL transactions to represent failed transactions.
95 pub struct Status(*mut sys::AStatus);
96
97 // Safety: The `AStatus` that the `Status` points to must have an entirely thread-safe API for the
98 // duration of the `Status` object's lifetime. We ensure this by not allowing mutation of a `Status`
99 // in Rust, and the NDK API says we're the owner of our `AStatus` objects so outside code should not
100 // be mutating them underneath us.
101 unsafe impl Sync for Status {}
102
103 // Safety: `Status` always contains an owning pointer to a global, immutable, interned `AStatus`.
104 // A thread-local `AStatus` would not be valid.
105 unsafe impl Send for Status {}
106
107 impl Status {
108 /// Create a status object representing a successful transaction.
ok() -> Self109 pub fn ok() -> Self {
110 let ptr = unsafe {
111 // Safety: `AStatus_newOk` always returns a new, heap allocated
112 // pointer to an `ASTatus` object, so we know this pointer will be
113 // valid.
114 //
115 // Rust takes ownership of the returned pointer.
116 sys::AStatus_newOk()
117 };
118 Self(ptr)
119 }
120
121 /// Create a status object from a service specific error
new_service_specific_error(err: i32, message: Option<&CStr>) -> Status122 pub fn new_service_specific_error(err: i32, message: Option<&CStr>) -> Status {
123 let ptr = if let Some(message) = message {
124 unsafe {
125 // Safety: Any i32 is a valid service specific error for the
126 // error code parameter. We construct a valid, null-terminated
127 // `CString` from the message, which must be a valid C-style
128 // string to pass as the message. This function always returns a
129 // new, heap allocated pointer to an `AStatus` object, so we
130 // know the returned pointer will be valid.
131 //
132 // Rust takes ownership of the returned pointer.
133 sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr())
134 }
135 } else {
136 unsafe {
137 // Safety: Any i32 is a valid service specific error for the
138 // error code parameter. This function always returns a new,
139 // heap allocated pointer to an `AStatus` object, so we know the
140 // returned pointer will be valid.
141 //
142 // Rust takes ownership of the returned pointer.
143 sys::AStatus_fromServiceSpecificError(err)
144 }
145 };
146 Self(ptr)
147 }
148
149 /// Create a status object from an exception code
new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status150 pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status {
151 if let Some(message) = message {
152 let ptr = unsafe {
153 sys::AStatus_fromExceptionCodeWithMessage(exception as i32, message.as_ptr())
154 };
155 Self(ptr)
156 } else {
157 exception.into()
158 }
159 }
160
161 /// Create a status object from a raw `AStatus` pointer.
162 ///
163 /// # Safety
164 ///
165 /// This constructor is safe iff `ptr` is a valid pointer to an `AStatus`.
from_ptr(ptr: *mut sys::AStatus) -> Self166 pub(crate) unsafe fn from_ptr(ptr: *mut sys::AStatus) -> Self {
167 Self(ptr)
168 }
169
170 /// Returns `true` if this status represents a successful transaction.
is_ok(&self) -> bool171 pub fn is_ok(&self) -> bool {
172 unsafe {
173 // Safety: `Status` always contains a valid `AStatus` pointer, so we
174 // are always passing a valid pointer to `AStatus_isOk` here.
175 sys::AStatus_isOk(self.as_native())
176 }
177 }
178
179 /// Returns a description of the status.
get_description(&self) -> String180 pub fn get_description(&self) -> String {
181 let description_ptr = unsafe {
182 // Safety: `Status` always contains a valid `AStatus` pointer, so we
183 // are always passing a valid pointer to `AStatus_getDescription`
184 // here.
185 //
186 // `AStatus_getDescription` always returns a valid pointer to a null
187 // terminated C string. Rust is responsible for freeing this pointer
188 // via `AStatus_deleteDescription`.
189 sys::AStatus_getDescription(self.as_native())
190 };
191 let description = unsafe {
192 // Safety: `AStatus_getDescription` always returns a valid C string,
193 // which can be safely converted to a `CStr`.
194 CStr::from_ptr(description_ptr)
195 };
196 let description = description.to_string_lossy().to_string();
197 unsafe {
198 // Safety: `description_ptr` was returned from
199 // `AStatus_getDescription` above, and must be freed via
200 // `AStatus_deleteDescription`. We must not access the pointer after
201 // this call, so we copy it into an owned string above and return
202 // that string.
203 sys::AStatus_deleteDescription(description_ptr);
204 }
205 description
206 }
207
208 /// Returns the exception code of the status.
exception_code(&self) -> ExceptionCode209 pub fn exception_code(&self) -> ExceptionCode {
210 let code = unsafe {
211 // Safety: `Status` always contains a valid `AStatus` pointer, so we
212 // are always passing a valid pointer to `AStatus_getExceptionCode`
213 // here.
214 sys::AStatus_getExceptionCode(self.as_native())
215 };
216 parse_exception_code(code)
217 }
218
219 /// Return a status code representing a transaction failure, or
220 /// `StatusCode::OK` if there was no transaction failure.
221 ///
222 /// If this method returns `OK`, the status may still represent a different
223 /// exception or a service specific error. To find out if this transaction
224 /// as a whole is okay, use [`is_ok`](Self::is_ok) instead.
transaction_error(&self) -> StatusCode225 pub fn transaction_error(&self) -> StatusCode {
226 let code = unsafe {
227 // Safety: `Status` always contains a valid `AStatus` pointer, so we
228 // are always passing a valid pointer to `AStatus_getStatus` here.
229 sys::AStatus_getStatus(self.as_native())
230 };
231 parse_status_code(code)
232 }
233
234 /// Return a service specific error if this status represents one.
235 ///
236 /// This function will only ever return a non-zero result if
237 /// [`exception_code`](Self::exception_code) returns
238 /// `ExceptionCode::SERVICE_SPECIFIC`. If this function returns 0, the
239 /// status object may still represent a different exception or status. To
240 /// find out if this transaction as a whole is okay, use
241 /// [`is_ok`](Self::is_ok) instead.
service_specific_error(&self) -> i32242 pub fn service_specific_error(&self) -> i32 {
243 unsafe {
244 // Safety: `Status` always contains a valid `AStatus` pointer, so we
245 // are always passing a valid pointer to
246 // `AStatus_getServiceSpecificError` here.
247 sys::AStatus_getServiceSpecificError(self.as_native())
248 }
249 }
250
251 /// Calls `op` if the status was ok, otherwise returns an `Err` value of
252 /// `self`.
and_then<T, F>(self, op: F) -> result::Result<T, Status> where F: FnOnce() -> result::Result<T, Status>,253 pub fn and_then<T, F>(self, op: F) -> result::Result<T, Status>
254 where
255 F: FnOnce() -> result::Result<T, Status>,
256 {
257 <result::Result<(), Status>>::from(self)?;
258 op()
259 }
260 }
261
262 impl error::Error for Status {}
263
264 impl Display for Status {
fmt(&self, f: &mut Formatter) -> FmtResult265 fn fmt(&self, f: &mut Formatter) -> FmtResult {
266 f.write_str(&self.get_description())
267 }
268 }
269
270 impl Debug for Status {
fmt(&self, f: &mut Formatter) -> FmtResult271 fn fmt(&self, f: &mut Formatter) -> FmtResult {
272 f.write_str(&self.get_description())
273 }
274 }
275
276 impl PartialEq for Status {
eq(&self, other: &Status) -> bool277 fn eq(&self, other: &Status) -> bool {
278 let self_code = self.exception_code();
279 let other_code = other.exception_code();
280
281 match (self_code, other_code) {
282 (ExceptionCode::NONE, ExceptionCode::NONE) => true,
283 (ExceptionCode::TRANSACTION_FAILED, ExceptionCode::TRANSACTION_FAILED) => {
284 self.transaction_error() == other.transaction_error()
285 && self.get_description() == other.get_description()
286 }
287 (ExceptionCode::SERVICE_SPECIFIC, ExceptionCode::SERVICE_SPECIFIC) => {
288 self.service_specific_error() == other.service_specific_error()
289 && self.get_description() == other.get_description()
290 }
291 (e1, e2) => e1 == e2 && self.get_description() == other.get_description(),
292 }
293 }
294 }
295
296 impl Eq for Status {}
297
298 impl From<StatusCode> for Status {
from(status: StatusCode) -> Status299 fn from(status: StatusCode) -> Status {
300 (status as status_t).into()
301 }
302 }
303
304 impl From<status_t> for Status {
from(status: status_t) -> Status305 fn from(status: status_t) -> Status {
306 let ptr = unsafe {
307 // Safety: `AStatus_fromStatus` expects any `status_t` integer, so
308 // this is a safe FFI call. Unknown values will be coerced into
309 // UNKNOWN_ERROR.
310 sys::AStatus_fromStatus(status)
311 };
312 Self(ptr)
313 }
314 }
315
316 impl From<ExceptionCode> for Status {
from(code: ExceptionCode) -> Status317 fn from(code: ExceptionCode) -> Status {
318 let ptr = unsafe {
319 // Safety: `AStatus_fromExceptionCode` expects any
320 // `binder_exception_t` (i32) integer, so this is a safe FFI call.
321 // Unknown values will be coerced into EX_TRANSACTION_FAILED.
322 sys::AStatus_fromExceptionCode(code as i32)
323 };
324 Self(ptr)
325 }
326 }
327
328 // TODO: impl Try for Status when try_trait is stabilized
329 // https://github.com/rust-lang/rust/issues/42327
330 impl From<Status> for result::Result<(), Status> {
from(status: Status) -> result::Result<(), Status>331 fn from(status: Status) -> result::Result<(), Status> {
332 if status.is_ok() {
333 Ok(())
334 } else {
335 Err(status)
336 }
337 }
338 }
339
340 impl From<Status> for status_t {
from(status: Status) -> status_t341 fn from(status: Status) -> status_t {
342 status.transaction_error() as status_t
343 }
344 }
345
346 impl Drop for Status {
drop(&mut self)347 fn drop(&mut self) {
348 unsafe {
349 // Safety: `Status` manages the lifetime of its inner `AStatus`
350 // pointee, so we need to delete it here. We know that the pointer
351 // will be valid here since `Status` always contains a valid pointer
352 // while it is alive.
353 sys::AStatus_delete(self.0);
354 }
355 }
356 }
357
358 /// # Safety
359 ///
360 /// `Status` always contains a valid pointer to an `AStatus` object, so we can
361 /// trivially convert it to a correctly-typed raw pointer.
362 ///
363 /// Care must be taken that the returned pointer is only dereferenced while the
364 /// `Status` object is still alive.
365 unsafe impl AsNative<sys::AStatus> for Status {
as_native(&self) -> *const sys::AStatus366 fn as_native(&self) -> *const sys::AStatus {
367 self.0
368 }
369
as_native_mut(&mut self) -> *mut sys::AStatus370 fn as_native_mut(&mut self) -> *mut sys::AStatus {
371 self.0
372 }
373 }
374