1use crate::error;
11use crate::error::StatusCode;
12use crate::parcel::*;
13use crate::parcelable::*;
14use std::fmt::{Debug, Display, Formatter};
15
16pub type Result<T> = std::result::Result<T, Status>;
18
19#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
25#[repr(i32)]
26pub enum ExceptionCode {
27 None = 0,
29 Security = -1,
31 BadParcelable = -2,
33 IllegalArgument = -3,
35 NullPointer = -4,
37 IllegalState = -5,
39 NetworkMainThread = -6,
41 UnsupportedOperation = -7,
43 ServiceSpecific = -8,
45 Parcelable = -9,
47
48 HasReplyHeader = -128,
51 TransactionFailed = -129,
55 JustError = -256,
57}
58
59impl Display for ExceptionCode {
60 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
61 match self {
62 ExceptionCode::None => write!(f, "None"),
63 ExceptionCode::Security => write!(f, "Security"),
64 ExceptionCode::BadParcelable => write!(f, "BadParcelable"),
65 ExceptionCode::IllegalArgument => write!(f, "IllegalArgument"),
66 ExceptionCode::NullPointer => write!(f, "NullPointer"),
67 ExceptionCode::IllegalState => write!(f, "IllegalState"),
68 ExceptionCode::NetworkMainThread => write!(f, "NetworkMainThread"),
69 ExceptionCode::UnsupportedOperation => write!(f, "UnsupportedOperation"),
70 ExceptionCode::ServiceSpecific => write!(f, "ServiceSpecific"),
71 ExceptionCode::Parcelable => write!(f, "Parcelable"),
72 ExceptionCode::HasReplyHeader => write!(f, "HasReplyHeader"),
73 ExceptionCode::TransactionFailed => write!(f, "TransactionFailed"),
74 ExceptionCode::JustError => write!(f, "JustError"),
75 }
76 }
77}
78
79impl Serialize for ExceptionCode {
80 fn serialize(&self, parcel: &mut Parcel) -> error::Result<()> {
81 parcel.write::<i32>(&(*self as i32))
82 }
83}
84
85impl Deserialize for ExceptionCode {
86 fn deserialize(parcel: &mut Parcel) -> error::Result<Self> {
87 let exception = parcel.read::<i32>()?;
88 let code = match exception {
89 exception if exception == ExceptionCode::None as i32 => ExceptionCode::None,
90 exception if exception == ExceptionCode::Security as i32 => ExceptionCode::Security,
91 exception if exception == ExceptionCode::BadParcelable as i32 => {
92 ExceptionCode::BadParcelable
93 }
94 exception if exception == ExceptionCode::IllegalArgument as i32 => {
95 ExceptionCode::IllegalArgument
96 }
97 exception if exception == ExceptionCode::NullPointer as i32 => {
98 ExceptionCode::NullPointer
99 }
100 exception if exception == ExceptionCode::IllegalState as i32 => {
101 ExceptionCode::IllegalState
102 }
103 exception if exception == ExceptionCode::NetworkMainThread as i32 => {
104 ExceptionCode::NetworkMainThread
105 }
106 exception if exception == ExceptionCode::UnsupportedOperation as i32 => {
107 ExceptionCode::UnsupportedOperation
108 }
109 exception if exception == ExceptionCode::ServiceSpecific as i32 => {
110 ExceptionCode::ServiceSpecific
111 }
112 exception if exception == ExceptionCode::Parcelable as i32 => ExceptionCode::Parcelable,
113 exception if exception == ExceptionCode::HasReplyHeader as i32 => {
114 ExceptionCode::HasReplyHeader
115 }
116 exception if exception == ExceptionCode::TransactionFailed as i32 => {
117 ExceptionCode::TransactionFailed
118 }
119 _ => ExceptionCode::JustError,
120 };
121 Ok(code)
122 }
123}
124
125pub struct Status {
131 code: StatusCode,
132 exception: ExceptionCode,
133 message: Option<String>,
134}
135
136impl PartialEq for Status {
137 fn eq(&self, other: &Self) -> bool {
138 self.code == other.code && self.exception == other.exception
139 }
140}
141
142impl Status {
143 fn new(exception: ExceptionCode, status: StatusCode, message: Option<String>) -> Self {
144 Status {
145 code: status,
146 exception,
147 message,
148 }
149 }
150
151 pub fn new_service_specific_error(err: i32, message: Option<String>) -> Self {
152 Self::new(
153 ExceptionCode::ServiceSpecific,
154 StatusCode::ServiceSpecific(err),
155 message,
156 )
157 }
158
159 pub fn is_ok(&self) -> bool {
160 self.exception == ExceptionCode::None
161 }
162
163 pub fn exception_code(&self) -> ExceptionCode {
164 self.exception
165 }
166
167 pub fn transaction_error(&self) -> StatusCode {
168 if self.exception == ExceptionCode::TransactionFailed {
169 self.code
170 } else {
171 StatusCode::Ok
172 }
173 }
174
175 pub fn service_specific_error(&self) -> i32 {
176 if let StatusCode::ServiceSpecific(err) = self.code {
177 err
178 } else {
179 0
180 }
181 }
182}
183
184impl std::error::Error for Status {}
185
186impl Display for Status {
187 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188 if self.exception == ExceptionCode::None {
189 write!(f, "{}", self.code)
190 } else {
191 write!(
192 f,
193 "{} / {}: {}",
194 self.exception,
195 self.code,
196 self.message.as_ref().unwrap_or(&"".to_owned())
197 )
198 }
199 }
200}
201
202impl Debug for Status {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 Display::fmt(self, f)
205 }
206}
207
208impl From<ExceptionCode> for StatusCode {
209 fn from(exception: ExceptionCode) -> Self {
210 match exception {
211 ExceptionCode::TransactionFailed => StatusCode::FailedTransaction,
212 _ => StatusCode::Ok,
213 }
214 }
215}
216
217impl From<Status> for StatusCode {
218 fn from(status: Status) -> Self {
219 status.code
220 }
221}
222
223impl From<StatusCode> for ExceptionCode {
224 fn from(status: StatusCode) -> Self {
225 match status {
226 StatusCode::Ok => ExceptionCode::None,
227 StatusCode::UnexpectedNull => ExceptionCode::NullPointer,
228 StatusCode::ServiceSpecific(_) => ExceptionCode::ServiceSpecific,
229 _ => ExceptionCode::TransactionFailed,
230 }
231 }
232}
233
234impl From<ExceptionCode> for Status {
235 fn from(exception: ExceptionCode) -> Self {
236 Status::new(exception, exception.into(), None)
237 }
238}
239
240impl From<(ExceptionCode, &str)> for Status {
241 fn from(arg: (ExceptionCode, &str)) -> Self {
242 Status::new(arg.0, arg.0.into(), Some(arg.1.to_owned()))
243 }
244}
245
246impl From<StatusCode> for Status {
247 fn from(status: StatusCode) -> Self {
248 Status::new(status.into(), status, None)
249 }
250}
251
252impl Serialize for Status {
253 fn serialize(&self, parcel: &mut Parcel) -> error::Result<()> {
254 if self.exception == ExceptionCode::TransactionFailed {
255 return Err(self.code);
256 }
257
258 parcel.write::<i32>(&(self.exception as _))?;
259 if self.exception == ExceptionCode::None {
260 return Ok(());
261 }
262
263 parcel.write::<String>(self.message.as_ref().unwrap_or(&"".to_owned()))?;
264 parcel.write::<i32>(&0)?; if self.exception == ExceptionCode::ServiceSpecific {
267 parcel.write::<i32>(&(self.code.into()))?;
268 } else if self.exception == ExceptionCode::Parcelable {
269 parcel.write::<i32>(&0)?;
270 }
271
272 Ok(())
273 }
274}
275
276fn read_check_header_size(parcel: &mut Parcel) -> error::Result<()> {
277 let header_start = parcel.data_position();
279 let header_avail = parcel.data_avail();
281
282 let header_size = parcel.read::<i32>()?;
283
284 if header_size < 0 {
286 log::error!("0x534e4554:132650049 Negative header_size({header_size}).");
287 return Err(StatusCode::BadValue);
288 }
289
290 let header_size_usize = header_size as usize;
292
293 if header_size_usize > header_avail {
295 log::error!(
296 "0x534e4554:132650049 Invalid header_size({header_size}) exceeds available({header_avail})."
297 );
298 return Err(StatusCode::BadValue);
299 }
300
301 let new_position = header_start.checked_add(header_size_usize).ok_or_else(|| {
303 log::error!("0x534e4554:132650049 Position overflow with header_size({header_size})");
304 StatusCode::BadValue
305 })?;
306
307 parcel.set_data_position(new_position);
308 Ok(())
309}
310
311impl Deserialize for Status {
312 fn deserialize(parcel: &mut Parcel) -> error::Result<Self> {
313 let mut exception = parcel.read::<ExceptionCode>()?;
314
315 if exception == ExceptionCode::HasReplyHeader {
316 read_check_header_size(parcel)?;
317 exception = ExceptionCode::None;
318 }
319 let status = if exception == ExceptionCode::None {
320 exception.into()
321 } else {
322 let message: String = parcel.read::<String>()?;
323 let remote_stack_trace_header_size = parcel.read::<i32>()?;
324
325 if remote_stack_trace_header_size < 0 {
327 log::error!(
328 "0x534e4554:132650049 Negative remote_stack_trace_header_size({remote_stack_trace_header_size})."
329 );
330 return Err(StatusCode::BadValue);
331 }
332
333 let trace_size_usize = remote_stack_trace_header_size as usize;
335
336 if trace_size_usize > parcel.data_avail() {
338 log::error!(
339 "0x534e4554:132650049 Invalid remote_stack_trace_header_size({remote_stack_trace_header_size}) exceeds available({}).",
340 parcel.data_avail()
341 );
342 return Err(StatusCode::BadValue);
343 }
344
345 let current_pos = parcel.data_position();
347 let new_position = current_pos.checked_add(trace_size_usize).ok_or_else(|| {
348 log::error!(
349 "0x534e4554:132650049 Position overflow with remote_stack_trace_header_size({remote_stack_trace_header_size})"
350 );
351 StatusCode::BadValue
352 })?;
353
354 parcel.set_data_position(new_position);
355
356 let code = if exception == ExceptionCode::ServiceSpecific {
357 let code = parcel.read::<i32>()?;
358 StatusCode::ServiceSpecific(code)
359 } else if exception == ExceptionCode::Parcelable {
360 read_check_header_size(parcel)?;
361 StatusCode::Ok
362 } else {
363 StatusCode::Ok
364 };
365
366 Status::new(exception, code, Some(message))
367 };
368
369 Ok(status)
370 }
371}
372
373#[cfg(test)]
374mod tests {
375 use crate::*;
376
377 #[test]
378 fn test_status() -> Result<()> {
379 let _status = Status::from(StatusCode::Unknown);
380
381 Ok(())
382 }
383
384 #[test]
385 fn test_status_display() -> Result<()> {
386 let unknown = Status::from(StatusCode::Unknown);
387 assert_eq!(format!("{unknown}"), "TransactionFailed / Unknown: ");
388
389 let service_specific =
390 Status::new_service_specific_error(1, Some("Service specific error".to_owned()));
391 assert_eq!(
392 format!("{service_specific}"),
393 "ServiceSpecific / ServiceSpecific(1): Service specific error"
394 );
395
396 let exception = Status::new(
397 ExceptionCode::BadParcelable,
398 StatusCode::Unknown,
399 Some("Bad parcelable".to_owned()),
400 );
401 assert_eq!(
402 format!("{exception}"),
403 "BadParcelable / Unknown: Bad parcelable"
404 );
405
406 Ok(())
407 }
408
409 #[test]
410 fn test_status_serialize() -> Result<()> {
411 let status = Status::from(StatusCode::ServiceSpecific(1));
412 let mut parcel = Parcel::new();
413 status.serialize(&mut parcel).unwrap();
414
415 parcel.set_data_position(0);
417 let deserialized = Status::deserialize(&mut parcel).unwrap();
418 assert_eq!(status, deserialized);
419
420 let status = Status::new(
422 ExceptionCode::Parcelable,
423 StatusCode::Ok,
424 Some("Parcelable".to_owned()),
425 );
426 let mut parcel = Parcel::new();
427 status.serialize(&mut parcel).unwrap();
428
429 parcel.set_data_position(0);
431 let deserialized = Status::deserialize(&mut parcel).unwrap();
432 assert_eq!(status, deserialized);
433
434 Ok(())
435 }
436}