blob: 2ae13f4dd8a97f04b8a3a06a478a411338977e45 [file] [log] [blame]
Stephen Craned58bce02020-07-07 12:26:02 -07001/*
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//! Included as a module in the binder crate internal tests for internal API
18//! access.
19
20use binder::declare_binder_interface;
21use binder::{
22 Binder, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
23 StatusCode, TransactionCode,
24};
25use binder::parcel::ParcelFileDescriptor;
26
27use std::ffi::{c_void, CStr, CString};
28use std::panic::{self, AssertUnwindSafe};
29use std::sync::Once;
30
31#[allow(
32 non_camel_case_types,
33 non_snake_case,
34 non_upper_case_globals,
35 unused,
36 improper_ctypes,
37 missing_docs,
38 clippy::all
39)]
40mod bindings {
41 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
42}
43
44static SERVICE_ONCE: Once = Once::new();
45static mut SERVICE: Option<SpIBinder> = None;
46
47/// Start binder service and return a raw AIBinder pointer to it.
48///
49/// Safe to call multiple times, only creates the service once.
50#[no_mangle]
51pub extern "C" fn rust_service() -> *mut c_void {
52 unsafe {
53 SERVICE_ONCE.call_once(|| {
54 SERVICE = Some(BnReadParcelTest::new_binder(()).as_binder());
55 });
56 SERVICE.as_ref().unwrap().as_raw().cast()
57 }
58}
59
60/// Empty interface just to use the declare_binder_interface macro
61pub trait ReadParcelTest: Interface {}
62
63declare_binder_interface! {
64 ReadParcelTest["read_parcel_test"] {
65 native: BnReadParcelTest(on_transact),
66 proxy: BpReadParcelTest,
67 }
68}
69
70impl ReadParcelTest for Binder<BnReadParcelTest> {}
71
72impl ReadParcelTest for BpReadParcelTest {}
73
74impl ReadParcelTest for () {}
75
76fn on_transact(
77 _service: &dyn ReadParcelTest,
78 code: TransactionCode,
79 parcel: &Parcel,
80 reply: &mut Parcel,
81) -> Result<()> {
82 panic::catch_unwind(AssertUnwindSafe(|| transact_inner(code, parcel, reply))).unwrap_or_else(
83 |e| {
84 eprintln!("Failure in Rust: {:?}", e.downcast_ref::<String>());
85 Err(StatusCode::FAILED_TRANSACTION)
86 },
87 )
88}
89
90#[allow(clippy::float_cmp)]
91fn transact_inner(code: TransactionCode, parcel: &Parcel, reply: &mut Parcel) -> Result<()> {
92 match code {
93 bindings::Transaction_TEST_BOOL => {
94 assert_eq!(parcel.read::<bool>()?, true);
95 assert_eq!(parcel.read::<bool>()?, false);
96 assert_eq!(parcel.read::<Vec<bool>>()?, unsafe {
97 bindings::TESTDATA_BOOL
98 });
99 assert_eq!(parcel.read::<Option<Vec<bool>>>()?, None);
100
101 reply.write(&true)?;
102 reply.write(&false)?;
103 reply.write(&unsafe { bindings::TESTDATA_BOOL }[..])?;
104 reply.write(&(None as Option<Vec<bool>>))?;
105 }
106 bindings::Transaction_TEST_BYTE => {
107 assert_eq!(parcel.read::<i8>()?, 0);
108 assert_eq!(parcel.read::<i8>()?, 1);
109 assert_eq!(parcel.read::<i8>()?, i8::max_value());
110 assert_eq!(parcel.read::<Vec<i8>>()?, unsafe { bindings::TESTDATA_I8 });
111 assert_eq!(parcel.read::<Vec<u8>>()?, unsafe { bindings::TESTDATA_U8 });
112 assert_eq!(parcel.read::<Option<Vec<i8>>>()?, None);
113
114 reply.write(&0i8)?;
115 reply.write(&1i8)?;
116 reply.write(&i8::max_value())?;
117 reply.write(&unsafe { bindings::TESTDATA_I8 }[..])?;
118 reply.write(&unsafe { bindings::TESTDATA_U8 }[..])?;
119 reply.write(&(None as Option<Vec<i8>>))?;
120 }
121 bindings::Transaction_TEST_U16 => {
122 assert_eq!(parcel.read::<u16>()?, 0);
123 assert_eq!(parcel.read::<u16>()?, 1);
124 assert_eq!(parcel.read::<u16>()?, u16::max_value());
125 assert_eq!(parcel.read::<Vec<u16>>()?, unsafe {
126 bindings::TESTDATA_CHARS
127 });
128 assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None);
129
130 reply.write(&0u16)?;
131 reply.write(&1u16)?;
132 reply.write(&u16::max_value())?;
133 reply.write(&unsafe { bindings::TESTDATA_CHARS }[..])?;
134 reply.write(&(None as Option<Vec<u16>>))?;
135 }
136 bindings::Transaction_TEST_I32 => {
137 assert_eq!(parcel.read::<i32>()?, 0);
138 assert_eq!(parcel.read::<i32>()?, 1);
139 assert_eq!(parcel.read::<i32>()?, i32::max_value());
140 assert_eq!(parcel.read::<Vec<i32>>()?, unsafe {
141 bindings::TESTDATA_I32
142 });
143 assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None);
144
145 reply.write(&0i32)?;
146 reply.write(&1i32)?;
147 reply.write(&i32::max_value())?;
148 reply.write(&unsafe { bindings::TESTDATA_I32 }[..])?;
149 reply.write(&(None as Option<Vec<i32>>))?;
150 }
151 bindings::Transaction_TEST_I64 => {
152 assert_eq!(parcel.read::<i64>()?, 0);
153 assert_eq!(parcel.read::<i64>()?, 1);
154 assert_eq!(parcel.read::<i64>()?, i64::max_value());
155 assert_eq!(parcel.read::<Vec<i64>>()?, unsafe {
156 bindings::TESTDATA_I64
157 });
158 assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None);
159
160 reply.write(&0i64)?;
161 reply.write(&1i64)?;
162 reply.write(&i64::max_value())?;
163 reply.write(&unsafe { bindings::TESTDATA_I64 }[..])?;
164 reply.write(&(None as Option<Vec<i64>>))?;
165 }
166 bindings::Transaction_TEST_U64 => {
167 assert_eq!(parcel.read::<u64>()?, 0);
168 assert_eq!(parcel.read::<u64>()?, 1);
169 assert_eq!(parcel.read::<u64>()?, u64::max_value());
170 assert_eq!(parcel.read::<Vec<u64>>()?, unsafe {
171 bindings::TESTDATA_U64
172 });
173 assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None);
174
175 reply.write(&0u64)?;
176 reply.write(&1u64)?;
177 reply.write(&u64::max_value())?;
178 reply.write(&unsafe { bindings::TESTDATA_U64 }[..])?;
179 reply.write(&(None as Option<Vec<u64>>))?;
180 }
181 bindings::Transaction_TEST_F32 => {
182 assert_eq!(parcel.read::<f32>()?, 0f32);
183 let floats = parcel.read::<Vec<f32>>()?;
184 assert!(floats[0].is_nan());
185 assert_eq!(floats[1..], unsafe { bindings::TESTDATA_FLOAT }[1..]);
186 assert_eq!(parcel.read::<Option<Vec<f32>>>()?, None);
187
188 reply.write(&0f32)?;
189 reply.write(&unsafe { bindings::TESTDATA_FLOAT }[..])?;
190 reply.write(&(None as Option<Vec<f32>>))?;
191 }
192 bindings::Transaction_TEST_F64 => {
193 assert_eq!(parcel.read::<f64>()?, 0f64);
194 let doubles = parcel.read::<Vec<f64>>()?;
195 assert!(doubles[0].is_nan());
196 assert_eq!(doubles[1..], unsafe { bindings::TESTDATA_DOUBLE }[1..]);
197 assert_eq!(parcel.read::<Option<Vec<f64>>>()?, None);
198
199 reply.write(&0f64)?;
200 reply.write(&unsafe { bindings::TESTDATA_DOUBLE }[..])?;
201 reply.write(&(None as Option<Vec<f64>>))?;
202 }
203 bindings::Transaction_TEST_STRING => {
204 let s: Option<String> = parcel.read()?;
205 assert_eq!(s.as_deref(), Some("testing"));
206 let s: Option<String> = parcel.read()?;
207 assert_eq!(s, None);
208 let s: Option<Vec<Option<String>>> = parcel.read()?;
209 for (s, expected) in s
210 .unwrap()
211 .iter()
212 .zip(unsafe { bindings::TESTDATA_STRS }.iter())
213 {
214 let expected = unsafe {
215 expected
216 .as_ref()
217 .and_then(|e| CStr::from_ptr(e).to_str().ok())
218 };
219 assert_eq!(s.as_deref(), expected);
220 }
221 let s: Option<Vec<Option<String>>> = parcel.read()?;
222 assert_eq!(s, None);
223
224 let strings: Vec<Option<String>> = unsafe {
225 bindings::TESTDATA_STRS
226 .iter()
227 .map(|s| {
228 s.as_ref().map(|s| {
229 CStr::from_ptr(s)
230 .to_str()
231 .expect("String was not UTF-8")
232 .to_owned()
233 })
234 })
235 .collect()
236 };
237
238 reply.write("testing")?;
239 reply.write(&(None as Option<String>))?;
240 reply.write(&strings)?;
241 reply.write(&(None as Option<Vec<String>>))?;
242 }
243 bindings::Transaction_TEST_FILE_DESCRIPTOR => {
244 let file1 = parcel.read::<ParcelFileDescriptor>()?;
245 let file2 = parcel.read::<ParcelFileDescriptor>()?;
246 let files = parcel.read::<Vec<Option<ParcelFileDescriptor>>>()?;
247
248 reply.write(&file1)?;
249 reply.write(&file2)?;
250 reply.write(&files)?;
251 }
252 bindings::Transaction_TEST_IBINDER => {
253 assert!(parcel.read::<Option<SpIBinder>>()?.is_some());
254 assert!(parcel.read::<Option<SpIBinder>>()?.is_none());
255 let ibinders = parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.unwrap();
256 assert_eq!(ibinders.len(), 2);
257 assert!(ibinders[0].is_some());
258 assert!(ibinders[1].is_none());
259 assert!(parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.is_none());
260
261 let service = unsafe {
262 SERVICE
263 .as_ref()
264 .expect("Global binder service not initialized")
265 .clone()
266 };
267 reply.write(&service)?;
268 reply.write(&(None as Option<&SpIBinder>))?;
269 reply.write(&[Some(&service), None][..])?;
270 reply.write(&(None as Option<Vec<Option<&SpIBinder>>>))?;
271 }
272 bindings::Transaction_TEST_STATUS => {
273 let status: Status = parcel.read()?;
274 assert!(status.is_ok());
275 let status: Status = parcel.read()?;
276 assert_eq!(status.exception_code(), ExceptionCode::NULL_POINTER);
277 assert_eq!(
278 status.get_description(),
279 "Status(-4, EX_NULL_POINTER): 'a status message'"
280 );
281 let status: Status = parcel.read()?;
282 assert_eq!(status.service_specific_error(), 42);
283 assert_eq!(
284 status.get_description(),
285 "Status(-8, EX_SERVICE_SPECIFIC): '42: a service-specific error'"
286 );
287
288 reply.write(&Status::ok())?;
289 reply.write(&Status::new_exception(
290 ExceptionCode::NULL_POINTER,
291 Some(&CString::new("a status message").unwrap()),
292 ))?;
293 reply.write(&Status::new_service_specific_error(
294 42,
295 Some(&CString::new("a service-specific error").unwrap()),
296 ))?;
297 }
298 bindings::Transaction_TEST_FAIL => {
299 panic!("Testing expected failure");
300 }
301 _ => return Err(StatusCode::UNKNOWN_TRANSACTION),
302 }
303
304 assert_eq!(parcel.read::<i32>(), Err(StatusCode::NOT_ENOUGH_DATA));
305 Ok(())
306}