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