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