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 //! Rust Binder crate integration tests
18
19 use binder::{declare_binder_enum, declare_binder_interface};
20 use binder::{BinderFeatures, Interface, StatusCode, ThreadState};
21 // Import from internal API for testing only, do not use this module in
22 // production.
23 use binder::binder_impl::{
24 Binder, BorrowedParcel, IBinderInternal, TransactionCode, FIRST_CALL_TRANSACTION,
25 };
26
27 use std::convert::{TryFrom, TryInto};
28 use std::ffi::CStr;
29 use std::io::Write;
30 use std::sync::Mutex;
31
32 /// Name of service runner.
33 ///
34 /// Must match the binary name in Android.bp
35 const RUST_SERVICE_BINARY: &str = "rustBinderTestService";
36
37 /// Binary to run a test service.
38 ///
39 /// This needs to be in a separate process from the tests, so we spawn this
40 /// binary as a child, providing the service name as an argument.
main() -> Result<(), &'static str>41 fn main() -> Result<(), &'static str> {
42 // Ensure that we can handle all transactions on the main thread.
43 binder::ProcessState::set_thread_pool_max_thread_count(0);
44 binder::ProcessState::start_thread_pool();
45
46 let mut args = std::env::args().skip(1);
47 if args.len() < 1 || args.len() > 2 {
48 print_usage();
49 return Err("");
50 }
51 let service_name = args.next().ok_or_else(|| {
52 print_usage();
53 "Missing SERVICE_NAME argument"
54 })?;
55 let extension_name = args.next();
56
57 {
58 let mut service = Binder::new(BnTest(Box::new(TestService::new(&service_name))));
59 service.set_requesting_sid(true);
60 if let Some(extension_name) = extension_name {
61 let extension =
62 BnTest::new_binder(TestService::new(&extension_name), BinderFeatures::default());
63 service.set_extension(&mut extension.as_binder()).expect("Could not add extension");
64 }
65 binder::add_service(&service_name, service.as_binder())
66 .expect("Could not register service");
67 }
68
69 binder::ProcessState::join_thread_pool();
70 Err("Unexpected exit after join_thread_pool")
71 }
72
print_usage()73 fn print_usage() {
74 eprintln!("Usage: {} SERVICE_NAME [EXTENSION_NAME]", RUST_SERVICE_BINARY);
75 eprintln!(concat!(
76 "Spawn a Binder test service identified by SERVICE_NAME,",
77 " optionally with an extesion named EXTENSION_NAME",
78 ));
79 }
80
81 struct TestService {
82 s: String,
83 dump_args: Mutex<Vec<String>>,
84 }
85
86 impl TestService {
new(s: &str) -> Self87 fn new(s: &str) -> Self {
88 Self { s: s.to_string(), dump_args: Mutex::new(Vec::new()) }
89 }
90 }
91
92 #[repr(u32)]
93 enum TestTransactionCode {
94 Test = FIRST_CALL_TRANSACTION,
95 GetDumpArgs,
96 GetSelinuxContext,
97 GetIsHandlingTransaction,
98 }
99
100 impl TryFrom<u32> for TestTransactionCode {
101 type Error = StatusCode;
102
try_from(c: u32) -> Result<Self, Self::Error>103 fn try_from(c: u32) -> Result<Self, Self::Error> {
104 match c {
105 _ if c == TestTransactionCode::Test as u32 => Ok(TestTransactionCode::Test),
106 _ if c == TestTransactionCode::GetDumpArgs as u32 => {
107 Ok(TestTransactionCode::GetDumpArgs)
108 }
109 _ if c == TestTransactionCode::GetSelinuxContext as u32 => {
110 Ok(TestTransactionCode::GetSelinuxContext)
111 }
112 _ if c == TestTransactionCode::GetIsHandlingTransaction as u32 => {
113 Ok(TestTransactionCode::GetIsHandlingTransaction)
114 }
115 _ => Err(StatusCode::UNKNOWN_TRANSACTION),
116 }
117 }
118 }
119
120 impl Interface for TestService {
dump(&self, _writer: &mut dyn Write, args: &[&CStr]) -> Result<(), StatusCode>121 fn dump(&self, _writer: &mut dyn Write, args: &[&CStr]) -> Result<(), StatusCode> {
122 let mut dump_args = self.dump_args.lock().unwrap();
123 dump_args.extend(args.iter().map(|s| s.to_str().unwrap().to_owned()));
124 Ok(())
125 }
126 }
127
128 impl ITest for TestService {
test(&self) -> Result<String, StatusCode>129 fn test(&self) -> Result<String, StatusCode> {
130 Ok(self.s.clone())
131 }
132
get_dump_args(&self) -> Result<Vec<String>, StatusCode>133 fn get_dump_args(&self) -> Result<Vec<String>, StatusCode> {
134 let args = self.dump_args.lock().unwrap().clone();
135 Ok(args)
136 }
137
get_selinux_context(&self) -> Result<String, StatusCode>138 fn get_selinux_context(&self) -> Result<String, StatusCode> {
139 let sid =
140 ThreadState::with_calling_sid(|sid| sid.map(|s| s.to_string_lossy().into_owned()));
141 sid.ok_or(StatusCode::UNEXPECTED_NULL)
142 }
143
get_is_handling_transaction(&self) -> Result<bool, StatusCode>144 fn get_is_handling_transaction(&self) -> Result<bool, StatusCode> {
145 Ok(binder::is_handling_transaction())
146 }
147 }
148
149 /// Trivial testing binder interface
150 pub trait ITest: Interface {
151 /// Returns a test string
test(&self) -> Result<String, StatusCode>152 fn test(&self) -> Result<String, StatusCode>;
153
154 /// Return the arguments sent via dump
get_dump_args(&self) -> Result<Vec<String>, StatusCode>155 fn get_dump_args(&self) -> Result<Vec<String>, StatusCode>;
156
157 /// Returns the caller's SELinux context
get_selinux_context(&self) -> Result<String, StatusCode>158 fn get_selinux_context(&self) -> Result<String, StatusCode>;
159
160 /// Returns the value of calling `is_handling_transaction`.
get_is_handling_transaction(&self) -> Result<bool, StatusCode>161 fn get_is_handling_transaction(&self) -> Result<bool, StatusCode>;
162 }
163
164 /// Async trivial testing binder interface
165 pub trait IATest<P>: Interface {
166 /// Returns a test string
test(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>167 fn test(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>;
168
169 /// Return the arguments sent via dump
get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>>170 fn get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>>;
171
172 /// Returns the caller's SELinux context
get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>173 fn get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>;
174
175 /// Returns the value of calling `is_handling_transaction`.
get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>>176 fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>>;
177 }
178
179 declare_binder_interface! {
180 ITest["android.os.ITest"] {
181 native: BnTest(on_transact),
182 proxy: BpTest {
183 x: i32 = 100
184 },
185 async: IATest,
186 }
187 }
188
on_transact( service: &dyn ITest, code: TransactionCode, _data: &BorrowedParcel<'_>, reply: &mut BorrowedParcel<'_>, ) -> Result<(), StatusCode>189 fn on_transact(
190 service: &dyn ITest,
191 code: TransactionCode,
192 _data: &BorrowedParcel<'_>,
193 reply: &mut BorrowedParcel<'_>,
194 ) -> Result<(), StatusCode> {
195 match code.try_into()? {
196 TestTransactionCode::Test => reply.write(&service.test()?),
197 TestTransactionCode::GetDumpArgs => reply.write(&service.get_dump_args()?),
198 TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
199 TestTransactionCode::GetIsHandlingTransaction => {
200 reply.write(&service.get_is_handling_transaction()?)
201 }
202 }
203 }
204
205 impl ITest for BpTest {
test(&self) -> Result<String, StatusCode>206 fn test(&self) -> Result<String, StatusCode> {
207 let reply =
208 self.binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
209 reply.read()
210 }
211
get_dump_args(&self) -> Result<Vec<String>, StatusCode>212 fn get_dump_args(&self) -> Result<Vec<String>, StatusCode> {
213 let reply =
214 self.binder
215 .transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(()))?;
216 reply.read()
217 }
218
get_selinux_context(&self) -> Result<String, StatusCode>219 fn get_selinux_context(&self) -> Result<String, StatusCode> {
220 let reply = self.binder.transact(
221 TestTransactionCode::GetSelinuxContext as TransactionCode,
222 0,
223 |_| Ok(()),
224 )?;
225 reply.read()
226 }
227
get_is_handling_transaction(&self) -> Result<bool, StatusCode>228 fn get_is_handling_transaction(&self) -> Result<bool, StatusCode> {
229 let reply = self.binder.transact(
230 TestTransactionCode::GetIsHandlingTransaction as TransactionCode,
231 0,
232 |_| Ok(()),
233 )?;
234 reply.read()
235 }
236 }
237
238 impl<P: binder::BinderAsyncPool> IATest<P> for BpTest {
test(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>239 fn test(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
240 let binder = self.binder.clone();
241 P::spawn(
242 move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())),
243 |reply| async move { reply?.read() },
244 )
245 }
246
get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>>247 fn get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>> {
248 let binder = self.binder.clone();
249 P::spawn(
250 move || {
251 binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(()))
252 },
253 |reply| async move { reply?.read() },
254 )
255 }
256
get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>257 fn get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
258 let binder = self.binder.clone();
259 P::spawn(
260 move || {
261 binder.transact(
262 TestTransactionCode::GetSelinuxContext as TransactionCode,
263 0,
264 |_| Ok(()),
265 )
266 },
267 |reply| async move { reply?.read() },
268 )
269 }
270
get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>>271 fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>> {
272 let binder = self.binder.clone();
273 P::spawn(
274 move || {
275 binder.transact(
276 TestTransactionCode::GetIsHandlingTransaction as TransactionCode,
277 0,
278 |_| Ok(()),
279 )
280 },
281 |reply| async move { reply?.read() },
282 )
283 }
284 }
285
286 impl ITest for Binder<BnTest> {
test(&self) -> Result<String, StatusCode>287 fn test(&self) -> Result<String, StatusCode> {
288 self.0.test()
289 }
290
get_dump_args(&self) -> Result<Vec<String>, StatusCode>291 fn get_dump_args(&self) -> Result<Vec<String>, StatusCode> {
292 self.0.get_dump_args()
293 }
294
get_selinux_context(&self) -> Result<String, StatusCode>295 fn get_selinux_context(&self) -> Result<String, StatusCode> {
296 self.0.get_selinux_context()
297 }
298
get_is_handling_transaction(&self) -> Result<bool, StatusCode>299 fn get_is_handling_transaction(&self) -> Result<bool, StatusCode> {
300 self.0.get_is_handling_transaction()
301 }
302 }
303
304 impl<P: binder::BinderAsyncPool> IATest<P> for Binder<BnTest> {
test(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>305 fn test(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
306 let res = self.0.test();
307 Box::pin(async move { res })
308 }
309
get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>>310 fn get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>> {
311 let res = self.0.get_dump_args();
312 Box::pin(async move { res })
313 }
314
get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>315 fn get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
316 let res = self.0.get_selinux_context();
317 Box::pin(async move { res })
318 }
319
get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>>320 fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>> {
321 let res = self.0.get_is_handling_transaction();
322 Box::pin(async move { res })
323 }
324 }
325
326 /// Trivial testing binder interface
327 pub trait ITestSameDescriptor: Interface {}
328
329 declare_binder_interface! {
330 ITestSameDescriptor["android.os.ITest"] {
331 native: BnTestSameDescriptor(on_transact_same_descriptor),
332 proxy: BpTestSameDescriptor,
333 }
334 }
335
on_transact_same_descriptor( _service: &dyn ITestSameDescriptor, _code: TransactionCode, _data: &BorrowedParcel<'_>, _reply: &mut BorrowedParcel<'_>, ) -> Result<(), StatusCode>336 fn on_transact_same_descriptor(
337 _service: &dyn ITestSameDescriptor,
338 _code: TransactionCode,
339 _data: &BorrowedParcel<'_>,
340 _reply: &mut BorrowedParcel<'_>,
341 ) -> Result<(), StatusCode> {
342 Ok(())
343 }
344
345 impl ITestSameDescriptor for BpTestSameDescriptor {}
346
347 impl ITestSameDescriptor for Binder<BnTestSameDescriptor> {}
348
349 declare_binder_enum! {
350 TestEnum : [i32; 3] {
351 FOO = 1,
352 BAR = 2,
353 BAZ = 3,
354 }
355 }
356
357 declare_binder_enum! {
358 #[deprecated(since = "1.0.0")]
359 TestDeprecatedEnum : [i32; 3] {
360 FOO = 1,
361 BAR = 2,
362 BAZ = 3,
363 }
364 }
365
366 #[cfg(test)]
367 mod tests {
368 use selinux_bindgen as selinux_sys;
369 use std::ffi::CStr;
370 use std::fs::File;
371 use std::process::{Child, Command};
372 use std::ptr;
373 use std::sync::atomic::{AtomicBool, Ordering};
374 use std::sync::Arc;
375 use std::thread;
376 use std::time::Duration;
377
378 use binder::{
379 BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode,
380 Strong,
381 };
382 // Import from impl API for testing only, should not be necessary as long as
383 // you are using AIDL.
384 use binder::binder_impl::{Binder, IBinderInternal, TransactionCode};
385
386 use binder_tokio::Tokio;
387
388 use super::{BnTest, IATest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
389
390 pub struct ScopedServiceProcess(Child);
391
392 impl ScopedServiceProcess {
new(identifier: &str) -> Self393 pub fn new(identifier: &str) -> Self {
394 Self::new_internal(identifier, None)
395 }
396
new_with_extension(identifier: &str, extension: &str) -> Self397 pub fn new_with_extension(identifier: &str, extension: &str) -> Self {
398 Self::new_internal(identifier, Some(extension))
399 }
400
new_internal(identifier: &str, extension: Option<&str>) -> Self401 fn new_internal(identifier: &str, extension: Option<&str>) -> Self {
402 let mut binary_path =
403 std::env::current_exe().expect("Could not retrieve current executable path");
404 binary_path.pop();
405 binary_path.push(RUST_SERVICE_BINARY);
406 let mut command = Command::new(&binary_path);
407 command.arg(identifier);
408 if let Some(ext) = extension {
409 command.arg(ext);
410 }
411 let child = command.spawn().expect("Could not start service");
412 Self(child)
413 }
414 }
415
416 impl Drop for ScopedServiceProcess {
drop(&mut self)417 fn drop(&mut self) {
418 self.0.kill().expect("Could not kill child process");
419 self.0.wait().expect("Could not wait for child process to die");
420 }
421 }
422
423 #[test]
check_get_service()424 fn check_get_service() {
425 let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
426 assert!(sm.is_binder_alive());
427 assert!(sm.ping_binder().is_ok());
428
429 assert!(binder::get_service("this_service_does_not_exist").is_none());
430 assert_eq!(
431 binder::get_interface::<dyn ITest>("this_service_does_not_exist").err(),
432 Some(StatusCode::NAME_NOT_FOUND)
433 );
434 assert_eq!(
435 binder::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").err(),
436 Some(StatusCode::NAME_NOT_FOUND)
437 );
438
439 // The service manager service isn't an ITest, so this must fail.
440 assert_eq!(binder::get_interface::<dyn ITest>("manager").err(), Some(StatusCode::BAD_TYPE));
441 assert_eq!(
442 binder::get_interface::<dyn IATest<Tokio>>("manager").err(),
443 Some(StatusCode::BAD_TYPE)
444 );
445 }
446
447 #[tokio::test]
check_get_service_async()448 async fn check_get_service_async() {
449 let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
450 assert!(sm.is_binder_alive());
451 assert!(sm.ping_binder().is_ok());
452
453 assert!(binder::get_service("this_service_does_not_exist").is_none());
454 assert_eq!(
455 binder_tokio::get_interface::<dyn ITest>("this_service_does_not_exist").await.err(),
456 Some(StatusCode::NAME_NOT_FOUND)
457 );
458 assert_eq!(
459 binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist")
460 .await
461 .err(),
462 Some(StatusCode::NAME_NOT_FOUND)
463 );
464
465 // The service manager service isn't an ITest, so this must fail.
466 assert_eq!(
467 binder_tokio::get_interface::<dyn ITest>("manager").await.err(),
468 Some(StatusCode::BAD_TYPE)
469 );
470 assert_eq!(
471 binder_tokio::get_interface::<dyn IATest<Tokio>>("manager").await.err(),
472 Some(StatusCode::BAD_TYPE)
473 );
474 }
475
476 #[test]
check_check_service()477 fn check_check_service() {
478 let mut sm = binder::check_service("manager").expect("Did not find manager binder service");
479 assert!(sm.is_binder_alive());
480 assert!(sm.ping_binder().is_ok());
481
482 assert!(binder::check_service("this_service_does_not_exist").is_none());
483 assert_eq!(
484 binder::check_interface::<dyn ITest>("this_service_does_not_exist").err(),
485 Some(StatusCode::NAME_NOT_FOUND)
486 );
487 assert_eq!(
488 binder::check_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").err(),
489 Some(StatusCode::NAME_NOT_FOUND)
490 );
491
492 // The service manager service isn't an ITest, so this must fail.
493 assert_eq!(
494 binder::check_interface::<dyn ITest>("manager").err(),
495 Some(StatusCode::BAD_TYPE)
496 );
497 assert_eq!(
498 binder::check_interface::<dyn IATest<Tokio>>("manager").err(),
499 Some(StatusCode::BAD_TYPE)
500 );
501 }
502
503 #[tokio::test]
check_check_service_async()504 async fn check_check_service_async() {
505 let mut sm = binder::check_service("manager").expect("Did not find manager binder service");
506 assert!(sm.is_binder_alive());
507 assert!(sm.ping_binder().is_ok());
508
509 assert!(binder::check_service("this_service_does_not_exist").is_none());
510 assert_eq!(
511 binder_tokio::check_interface::<dyn ITest>("this_service_does_not_exist").await.err(),
512 Some(StatusCode::NAME_NOT_FOUND)
513 );
514 assert_eq!(
515 binder_tokio::check_interface::<dyn IATest<Tokio>>("this_service_does_not_exist")
516 .await
517 .err(),
518 Some(StatusCode::NAME_NOT_FOUND)
519 );
520
521 // The service manager service isn't an ITest, so this must fail.
522 assert_eq!(
523 binder_tokio::check_interface::<dyn ITest>("manager").await.err(),
524 Some(StatusCode::BAD_TYPE)
525 );
526 assert_eq!(
527 binder_tokio::check_interface::<dyn IATest<Tokio>>("manager").await.err(),
528 Some(StatusCode::BAD_TYPE)
529 );
530 }
531
532 #[test]
check_wait_for_service()533 fn check_wait_for_service() {
534 let mut sm =
535 binder::wait_for_service("manager").expect("Did not get manager binder service");
536 assert!(sm.is_binder_alive());
537 assert!(sm.ping_binder().is_ok());
538
539 // The service manager service isn't an ITest, so this must fail.
540 assert_eq!(
541 binder::wait_for_interface::<dyn ITest>("manager").err(),
542 Some(StatusCode::BAD_TYPE)
543 );
544 assert_eq!(
545 binder::wait_for_interface::<dyn IATest<Tokio>>("manager").err(),
546 Some(StatusCode::BAD_TYPE)
547 );
548 }
549
550 #[test]
get_declared_instances()551 fn get_declared_instances() {
552 // At the time of writing this test, there is no good VINTF interface
553 // guaranteed to be on all devices. Cuttlefish has light, so this will
554 // generally test things.
555 let has_lights = binder::is_declared("android.hardware.light.ILights/default")
556 .expect("Could not check for declared interface");
557
558 let instances = binder::get_declared_instances("android.hardware.light.ILights")
559 .expect("Could not get declared instances");
560
561 let expected_defaults = usize::from(has_lights);
562 assert_eq!(expected_defaults, instances.iter().filter(|i| i.as_str() == "default").count());
563 }
564
565 #[test]
trivial_client()566 fn trivial_client() {
567 let service_name = "trivial_client_test";
568 let _process = ScopedServiceProcess::new(service_name);
569 let test_client: Strong<dyn ITest> =
570 binder::get_interface(service_name).expect("Did not get manager binder service");
571 assert_eq!(test_client.test().unwrap(), "trivial_client_test");
572 }
573
574 #[tokio::test]
trivial_client_async()575 async fn trivial_client_async() {
576 let service_name = "trivial_client_test";
577 let _process = ScopedServiceProcess::new(service_name);
578 let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
579 .await
580 .expect("Did not get manager binder service");
581 assert_eq!(test_client.test().await.unwrap(), "trivial_client_test");
582 }
583
584 #[test]
wait_for_trivial_client()585 fn wait_for_trivial_client() {
586 let service_name = "wait_for_trivial_client_test";
587 let _process = ScopedServiceProcess::new(service_name);
588 let test_client: Strong<dyn ITest> =
589 binder::wait_for_interface(service_name).expect("Did not get manager binder service");
590 assert_eq!(test_client.test().unwrap(), "wait_for_trivial_client_test");
591 }
592
593 #[tokio::test]
wait_for_trivial_client_async()594 async fn wait_for_trivial_client_async() {
595 let service_name = "wait_for_trivial_client_test";
596 let _process = ScopedServiceProcess::new(service_name);
597 let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::wait_for_interface(service_name)
598 .await
599 .expect("Did not get manager binder service");
600 assert_eq!(test_client.test().await.unwrap(), "wait_for_trivial_client_test");
601 }
602
get_expected_selinux_context() -> &'static str603 fn get_expected_selinux_context() -> &'static str {
604 // SAFETY: The pointer we pass to `getcon` is valid because it comes from a reference, and
605 // `getcon` doesn't retain it after it returns. If `getcon` succeeds then `out_ptr` will
606 // point to a valid C string, otherwise it will remain null. We check for null, so the
607 // pointer we pass to `CStr::from_ptr` must be a valid pointer to a C string. There is a
608 // memory leak as we don't call `freecon`, but that's fine because this is just a test.
609 unsafe {
610 let mut out_ptr = ptr::null_mut();
611 assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
612 assert!(!out_ptr.is_null());
613 CStr::from_ptr(out_ptr).to_str().expect("context was invalid UTF-8")
614 }
615 }
616
617 #[test]
get_selinux_context()618 fn get_selinux_context() {
619 let service_name = "get_selinux_context";
620 let _process = ScopedServiceProcess::new(service_name);
621 let test_client: Strong<dyn ITest> =
622 binder::get_interface(service_name).expect("Did not get manager binder service");
623 assert_eq!(test_client.get_selinux_context().unwrap(), get_expected_selinux_context());
624 }
625
626 #[tokio::test]
get_selinux_context_async()627 async fn get_selinux_context_async() {
628 let service_name = "get_selinux_context_async";
629 let _process = ScopedServiceProcess::new(service_name);
630 let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
631 .await
632 .expect("Did not get manager binder service");
633 assert_eq!(
634 test_client.get_selinux_context().await.unwrap(),
635 get_expected_selinux_context()
636 );
637 }
638
639 #[tokio::test]
get_selinux_context_sync_to_async()640 async fn get_selinux_context_sync_to_async() {
641 let service_name = "get_selinux_context";
642 let _process = ScopedServiceProcess::new(service_name);
643 let test_client: Strong<dyn ITest> =
644 binder::get_interface(service_name).expect("Did not get manager binder service");
645 let test_client = test_client.into_async::<Tokio>();
646 assert_eq!(
647 test_client.get_selinux_context().await.unwrap(),
648 get_expected_selinux_context()
649 );
650 }
651
652 #[tokio::test]
get_selinux_context_async_to_sync()653 async fn get_selinux_context_async_to_sync() {
654 let service_name = "get_selinux_context";
655 let _process = ScopedServiceProcess::new(service_name);
656 let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
657 .await
658 .expect("Did not get manager binder service");
659 let test_client = test_client.into_sync();
660 assert_eq!(test_client.get_selinux_context().unwrap(), get_expected_selinux_context());
661 }
662
663 struct Bools {
664 binder_died: Arc<AtomicBool>,
665 binder_dealloc: Arc<AtomicBool>,
666 }
667
668 impl Bools {
is_dead(&self) -> bool669 fn is_dead(&self) -> bool {
670 self.binder_died.load(Ordering::Relaxed)
671 }
assert_died(&self)672 fn assert_died(&self) {
673 assert!(self.is_dead(), "Did not receive death notification");
674 }
assert_dropped(&self)675 fn assert_dropped(&self) {
676 assert!(
677 self.binder_dealloc.load(Ordering::Relaxed),
678 "Did not dealloc death notification"
679 );
680 }
assert_not_dropped(&self)681 fn assert_not_dropped(&self) {
682 assert!(
683 !self.binder_dealloc.load(Ordering::Relaxed),
684 "Dealloc death notification too early"
685 );
686 }
687 }
688
register_death_notification(binder: &mut SpIBinder) -> (Bools, DeathRecipient)689 fn register_death_notification(binder: &mut SpIBinder) -> (Bools, DeathRecipient) {
690 let binder_died = Arc::new(AtomicBool::new(false));
691 let binder_dealloc = Arc::new(AtomicBool::new(false));
692
693 struct SetOnDrop {
694 binder_dealloc: Arc<AtomicBool>,
695 }
696 impl Drop for SetOnDrop {
697 fn drop(&mut self) {
698 self.binder_dealloc.store(true, Ordering::Relaxed);
699 }
700 }
701
702 let mut death_recipient = {
703 let flag = binder_died.clone();
704 let set_on_drop = SetOnDrop { binder_dealloc: binder_dealloc.clone() };
705 DeathRecipient::new(move || {
706 flag.store(true, Ordering::Relaxed);
707 // Force the closure to take ownership of set_on_drop. When the closure is
708 // dropped, the destructor of `set_on_drop` will run.
709 let _ = &set_on_drop;
710 })
711 };
712
713 binder.link_to_death(&mut death_recipient).expect("link_to_death failed");
714
715 let bools = Bools { binder_died, binder_dealloc };
716
717 (bools, death_recipient)
718 }
719
720 /// Killing a remote service should unregister the service and trigger
721 /// death notifications.
722 #[test]
test_death_notifications()723 fn test_death_notifications() {
724 binder::ProcessState::start_thread_pool();
725
726 let service_name = "test_death_notifications";
727 let service_process = ScopedServiceProcess::new(service_name);
728 let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
729
730 let (bools, recipient) = register_death_notification(&mut remote);
731
732 drop(service_process);
733 remote.ping_binder().expect_err("Service should have died already");
734
735 // Pause to ensure any death notifications get delivered
736 thread::sleep(Duration::from_secs(1));
737
738 bools.assert_died();
739 bools.assert_not_dropped();
740
741 drop(recipient);
742
743 bools.assert_dropped();
744 }
745
746 /// Test unregistering death notifications.
747 #[test]
test_unregister_death_notifications()748 fn test_unregister_death_notifications() {
749 binder::ProcessState::start_thread_pool();
750
751 let service_name = "test_unregister_death_notifications";
752 let service_process = ScopedServiceProcess::new(service_name);
753 let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
754
755 let (bools, mut recipient) = register_death_notification(&mut remote);
756
757 remote.unlink_to_death(&mut recipient).expect("Could not unlink death notifications");
758
759 drop(service_process);
760 remote.ping_binder().expect_err("Service should have died already");
761
762 // Pause to ensure any death notifications get delivered
763 thread::sleep(Duration::from_secs(1));
764
765 assert!(!bools.is_dead(), "Received unexpected death notification after unlinking",);
766
767 bools.assert_not_dropped();
768 drop(recipient);
769 bools.assert_dropped();
770 }
771
772 /// Dropping a remote handle should unregister any death notifications.
773 #[test]
test_death_notification_registration_lifetime()774 fn test_death_notification_registration_lifetime() {
775 binder::ProcessState::start_thread_pool();
776
777 let service_name = "test_death_notification_registration_lifetime";
778 let service_process = ScopedServiceProcess::new(service_name);
779 let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
780
781 let (bools, recipient) = register_death_notification(&mut remote);
782
783 // This should automatically unregister our death notification.
784 drop(remote);
785
786 drop(service_process);
787
788 // Pause to ensure any death notifications get delivered
789 thread::sleep(Duration::from_secs(1));
790
791 // We dropped the remote handle, so we should not receive the death
792 // notification when the remote process dies here.
793 assert!(
794 !bools.is_dead(),
795 "Received unexpected death notification after dropping remote handle"
796 );
797
798 bools.assert_not_dropped();
799 drop(recipient);
800 bools.assert_dropped();
801 }
802
803 /// Test IBinder interface methods not exercised elsewhere.
804 #[test]
test_misc_ibinder()805 fn test_misc_ibinder() {
806 let service_name = "rust_test_ibinder";
807
808 {
809 let _process = ScopedServiceProcess::new(service_name);
810
811 let test_client: Strong<dyn ITest> =
812 binder::get_interface(service_name).expect("Did not get test binder service");
813 let mut remote = test_client.as_binder();
814 assert!(remote.is_binder_alive());
815 remote.ping_binder().expect("Could not ping remote service");
816
817 let dump_args = ["dump", "args", "for", "testing"];
818
819 let null_out = File::open("/dev/null").expect("Could not open /dev/null");
820 remote.dump(&null_out, &dump_args).expect("Could not dump remote service");
821
822 let remote_args = test_client.get_dump_args().expect("Could not fetched dumped args");
823 assert_eq!(dump_args, remote_args[..], "Remote args don't match call to dump");
824 }
825
826 // get/set_extensions is tested in test_extensions()
827
828 // transact is tested everywhere else, and we can't make raw
829 // transactions outside the [FIRST_CALL_TRANSACTION,
830 // LAST_CALL_TRANSACTION] range from the NDK anyway.
831
832 // link_to_death is tested in test_*_death_notification* tests.
833 }
834
835 #[test]
test_extensions()836 fn test_extensions() {
837 let service_name = "rust_test_extensions";
838 let extension_name = "rust_test_extensions_ext";
839
840 {
841 let _process = ScopedServiceProcess::new(service_name);
842
843 let mut remote = binder::get_service(service_name);
844 assert!(remote.is_binder_alive());
845
846 let extension = remote.get_extension().expect("Could not check for an extension");
847 assert!(extension.is_none());
848 }
849
850 {
851 let _process = ScopedServiceProcess::new_with_extension(service_name, extension_name);
852
853 let mut remote = binder::get_service(service_name);
854 assert!(remote.is_binder_alive());
855
856 let maybe_extension = remote.get_extension().expect("Could not check for an extension");
857
858 let extension = maybe_extension.expect("Remote binder did not have an extension");
859
860 let extension: Strong<dyn ITest> = FromIBinder::try_from(extension)
861 .expect("Extension could not be converted to the expected interface");
862
863 assert_eq!(extension.test().unwrap(), extension_name);
864 }
865 }
866
867 /// Test re-associating a local binder object with a different class.
868 ///
869 /// This is needed because different binder service (e.g. NDK vs Rust)
870 /// implementations are incompatible and must not be interchanged. A local
871 /// service with the same descriptor string but a different class pointer
872 /// may have been created by an NDK service and is therefore incompatible
873 /// with the Rust service implementation. It must be treated as remote and
874 /// all API calls parceled and sent through transactions.
875 ///
876 /// Further tests of this behavior with the C NDK and Rust API are in
877 /// rust_ndk_interop.rs
878 #[test]
associate_existing_class()879 fn associate_existing_class() {
880 let service = Binder::new(BnTest(Box::new(TestService::new("testing_service"))));
881
882 // This should succeed although we will have to treat the service as
883 // remote.
884 let _interface: Strong<dyn ITestSameDescriptor> =
885 FromIBinder::try_from(service.as_binder())
886 .expect("Could not re-interpret service as the ITestSameDescriptor interface");
887 }
888
889 /// Test that we can round-trip a rust service through a generic IBinder
890 #[test]
reassociate_rust_binder()891 fn reassociate_rust_binder() {
892 let service_name = "testing_service";
893 let service_ibinder =
894 BnTest::new_binder(TestService::new(service_name), BinderFeatures::default())
895 .as_binder();
896
897 let service: Strong<dyn ITest> =
898 service_ibinder.into_interface().expect("Could not reassociate the generic ibinder");
899
900 assert_eq!(service.test().unwrap(), service_name);
901 }
902
903 #[test]
weak_binder_upgrade()904 fn weak_binder_upgrade() {
905 let service_name = "testing_service";
906 let service = BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
907
908 let weak = Strong::downgrade(&service);
909
910 let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
911
912 assert_eq!(service, upgraded);
913 }
914
915 #[test]
weak_binder_upgrade_dead()916 fn weak_binder_upgrade_dead() {
917 let service_name = "testing_service";
918 let weak = {
919 let service =
920 BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
921
922 Strong::downgrade(&service)
923 };
924
925 assert_eq!(weak.upgrade(), Err(StatusCode::DEAD_OBJECT));
926 }
927
928 #[test]
weak_binder_clone()929 fn weak_binder_clone() {
930 let service_name = "testing_service";
931 let service = BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
932
933 let weak = Strong::downgrade(&service);
934 let cloned = weak.clone();
935 assert_eq!(weak, cloned);
936
937 let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
938 let clone_upgraded = cloned.upgrade().expect("Could not upgrade weak binder");
939
940 assert_eq!(service, upgraded);
941 assert_eq!(service, clone_upgraded);
942 }
943
944 #[test]
945 #[allow(clippy::eq_op)]
binder_ord()946 fn binder_ord() {
947 let service1 =
948 BnTest::new_binder(TestService::new("testing_service1"), BinderFeatures::default());
949 let service2 =
950 BnTest::new_binder(TestService::new("testing_service2"), BinderFeatures::default());
951
952 assert!((service1 >= service1));
953 assert!((service1 <= service1));
954 assert_eq!(service1 < service2, (service2 >= service1));
955 }
956
957 #[test]
binder_parcel_mixup()958 fn binder_parcel_mixup() {
959 let service1 =
960 BnTest::new_binder(TestService::new("testing_service1"), BinderFeatures::default());
961 let service2 =
962 BnTest::new_binder(TestService::new("testing_service2"), BinderFeatures::default());
963
964 let service1 = service1.as_binder();
965 let service2 = service2.as_binder();
966
967 let parcel = service1.prepare_transact().unwrap();
968 let res = service2.submit_transact(
969 super::TestTransactionCode::Test as TransactionCode,
970 parcel,
971 0,
972 );
973
974 match res {
975 Ok(_) => panic!("submit_transact should fail"),
976 Err(err) => assert_eq!(err, binder::StatusCode::BAD_VALUE),
977 }
978 }
979
980 #[test]
get_is_handling_transaction()981 fn get_is_handling_transaction() {
982 let service_name = "get_is_handling_transaction";
983 let _process = ScopedServiceProcess::new(service_name);
984 let test_client: Strong<dyn ITest> =
985 binder::get_interface(service_name).expect("Did not get manager binder service");
986 // Should be true externally.
987 assert!(test_client.get_is_handling_transaction().unwrap());
988
989 // Should be false locally.
990 assert!(!binder::is_handling_transaction());
991
992 // Should also be false in spawned thread.
993 std::thread::spawn(|| {
994 assert!(!binder::is_handling_transaction());
995 })
996 .join()
997 .unwrap();
998 }
999
1000 #[tokio::test]
get_is_handling_transaction_async()1001 async fn get_is_handling_transaction_async() {
1002 let service_name = "get_is_handling_transaction_async";
1003 let _process = ScopedServiceProcess::new(service_name);
1004 let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
1005 .await
1006 .expect("Did not get manager binder service");
1007 // Should be true externally.
1008 assert!(test_client.get_is_handling_transaction().await.unwrap());
1009
1010 // Should be false locally.
1011 assert!(!binder::is_handling_transaction());
1012
1013 // Should also be false in spawned task.
1014 tokio::spawn(async {
1015 assert!(!binder::is_handling_transaction());
1016 })
1017 .await
1018 .unwrap();
1019
1020 // And in spawn_blocking task.
1021 tokio::task::spawn_blocking(|| {
1022 assert!(!binder::is_handling_transaction());
1023 })
1024 .await
1025 .unwrap();
1026 }
1027 }
1028