blob: 10b77f484098c4c76ba16fa052f6ceb25da05a0c [file] [log] [blame]
Stephen Crane2a3c2502020-06-16 17:48:35 -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//! Rust Binder crate integration tests
18
19use binder::declare_binder_interface;
20use binder::parcel::Parcel;
Andrew Walbran12400d82021-03-04 17:04:34 +000021use binder::{
Andrew Walbran88eca4f2021-04-13 14:26:01 +000022 Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
Andrew Walbran12400d82021-03-04 17:04:34 +000023 FIRST_CALL_TRANSACTION,
24};
Janis Danisevskis798a09a2020-08-18 08:35:38 -070025use std::convert::{TryFrom, TryInto};
Stephen Crane2a3c2502020-06-16 17:48:35 -070026
27/// Name of service runner.
28///
29/// Must match the binary name in Android.bp
30const RUST_SERVICE_BINARY: &str = "rustBinderTestService";
31
32/// Binary to run a test service.
33///
34/// This needs to be in a separate process from the tests, so we spawn this
35/// binary as a child, providing the service name as an argument.
36fn main() -> Result<(), &'static str> {
37 // Ensure that we can handle all transactions on the main thread.
38 binder::ProcessState::set_thread_pool_max_thread_count(0);
39 binder::ProcessState::start_thread_pool();
40
41 let mut args = std::env::args().skip(1);
42 if args.len() < 1 || args.len() > 2 {
43 print_usage();
44 return Err("");
45 }
46 let service_name = args.next().ok_or_else(|| {
47 print_usage();
48 "Missing SERVICE_NAME argument"
49 })?;
50 let extension_name = args.next();
51
52 {
53 let mut service = Binder::new(BnTest(Box::new(TestService {
54 s: service_name.clone(),
55 })));
Janis Danisevskis798a09a2020-08-18 08:35:38 -070056 service.set_requesting_sid(true);
Stephen Crane2a3c2502020-06-16 17:48:35 -070057 if let Some(extension_name) = extension_name {
Andrew Walbran88eca4f2021-04-13 14:26:01 +000058 let extension =
59 BnTest::new_binder(TestService { s: extension_name }, BinderFeatures::default());
Stephen Crane2a3c2502020-06-16 17:48:35 -070060 service
61 .set_extension(&mut extension.as_binder())
62 .expect("Could not add extension");
63 }
64 binder::add_service(&service_name, service.as_binder())
65 .expect("Could not register service");
66 }
67
68 binder::ProcessState::join_thread_pool();
69 Err("Unexpected exit after join_thread_pool")
70}
71
72fn print_usage() {
73 eprintln!(
74 "Usage: {} SERVICE_NAME [EXTENSION_NAME]",
75 RUST_SERVICE_BINARY
76 );
77 eprintln!(concat!(
78 "Spawn a Binder test service identified by SERVICE_NAME,",
79 " optionally with an extesion named EXTENSION_NAME",
80 ));
81}
82
83#[derive(Clone)]
84struct TestService {
85 s: String,
86}
87
Janis Danisevskis798a09a2020-08-18 08:35:38 -070088#[repr(u32)]
89enum TestTransactionCode {
Andrew Walbran12400d82021-03-04 17:04:34 +000090 Test = FIRST_CALL_TRANSACTION,
Janis Danisevskis798a09a2020-08-18 08:35:38 -070091 GetSelinuxContext,
92}
93
94impl TryFrom<u32> for TestTransactionCode {
95 type Error = StatusCode;
96
97 fn try_from(c: u32) -> Result<Self, Self::Error> {
98 match c {
99 _ if c == TestTransactionCode::Test as u32 => Ok(TestTransactionCode::Test),
100 _ if c == TestTransactionCode::GetSelinuxContext as u32 => {
101 Ok(TestTransactionCode::GetSelinuxContext)
102 }
103 _ => Err(StatusCode::UNKNOWN_TRANSACTION),
104 }
105 }
106}
107
Stephen Crane2a3c2502020-06-16 17:48:35 -0700108impl Interface for TestService {}
109
110impl ITest for TestService {
111 fn test(&self) -> binder::Result<String> {
112 Ok(self.s.clone())
113 }
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700114
115 fn get_selinux_context(&self) -> binder::Result<String> {
116 let sid =
117 ThreadState::with_calling_sid(|sid| sid.map(|s| s.to_string_lossy().into_owned()));
118 sid.ok_or(StatusCode::UNEXPECTED_NULL)
119 }
Stephen Crane2a3c2502020-06-16 17:48:35 -0700120}
121
122/// Trivial testing binder interface
123pub trait ITest: Interface {
124 /// Returns a test string
125 fn test(&self) -> binder::Result<String>;
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700126
127 /// Returns the caller's SELinux context
128 fn get_selinux_context(&self) -> binder::Result<String>;
Stephen Crane2a3c2502020-06-16 17:48:35 -0700129}
130
131declare_binder_interface! {
132 ITest["android.os.ITest"] {
133 native: BnTest(on_transact),
134 proxy: BpTest {
135 x: i32 = 100
136 },
137 }
138}
139
140fn on_transact(
141 service: &dyn ITest,
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700142 code: TransactionCode,
Stephen Crane2a3c2502020-06-16 17:48:35 -0700143 _data: &Parcel,
144 reply: &mut Parcel,
145) -> binder::Result<()> {
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700146 match code.try_into()? {
147 TestTransactionCode::Test => reply.write(&service.test()?),
148 TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
149 }
Stephen Crane2a3c2502020-06-16 17:48:35 -0700150}
151
152impl ITest for BpTest {
153 fn test(&self) -> binder::Result<String> {
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700154 let reply =
155 self.binder
156 .transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
157 reply.read()
158 }
159
160 fn get_selinux_context(&self) -> binder::Result<String> {
161 let reply = self.binder.transact(
162 TestTransactionCode::GetSelinuxContext as TransactionCode,
163 0,
164 |_| Ok(()),
165 )?;
Stephen Crane2a3c2502020-06-16 17:48:35 -0700166 reply.read()
167 }
168}
169
170impl ITest for Binder<BnTest> {
171 fn test(&self) -> binder::Result<String> {
172 self.0.test()
173 }
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700174
175 fn get_selinux_context(&self) -> binder::Result<String> {
176 self.0.get_selinux_context()
177 }
Stephen Crane2a3c2502020-06-16 17:48:35 -0700178}
179
Stephen Crane669deb62020-09-10 17:31:39 -0700180/// Trivial testing binder interface
181pub trait ITestSameDescriptor: Interface {}
182
183declare_binder_interface! {
184 ITestSameDescriptor["android.os.ITest"] {
185 native: BnTestSameDescriptor(on_transact_same_descriptor),
186 proxy: BpTestSameDescriptor,
187 }
188}
189
190fn on_transact_same_descriptor(
191 _service: &dyn ITestSameDescriptor,
192 _code: TransactionCode,
193 _data: &Parcel,
194 _reply: &mut Parcel,
195) -> binder::Result<()> {
196 Ok(())
197}
198
199impl ITestSameDescriptor for BpTestSameDescriptor {}
200
201impl ITestSameDescriptor for Binder<BnTestSameDescriptor> {}
202
Stephen Crane2a3c2502020-06-16 17:48:35 -0700203#[cfg(test)]
204mod tests {
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700205 use selinux_bindgen as selinux_sys;
206 use std::ffi::CStr;
Stephen Crane2a3c2502020-06-16 17:48:35 -0700207 use std::fs::File;
208 use std::process::{Child, Command};
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700209 use std::ptr;
Stephen Crane2a3c2502020-06-16 17:48:35 -0700210 use std::sync::atomic::{AtomicBool, Ordering};
211 use std::sync::Arc;
212 use std::thread;
213 use std::time::Duration;
214
Andrew Walbran12400d82021-03-04 17:04:34 +0000215 use binder::{
Andrew Walbran88eca4f2021-04-13 14:26:01 +0000216 Binder, BinderFeatures, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface,
217 SpIBinder, StatusCode, Strong,
Andrew Walbran12400d82021-03-04 17:04:34 +0000218 };
Stephen Crane2a3c2502020-06-16 17:48:35 -0700219
Andrew Walbran12400d82021-03-04 17:04:34 +0000220 use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
Stephen Crane2a3c2502020-06-16 17:48:35 -0700221
222 pub struct ScopedServiceProcess(Child);
223
224 impl ScopedServiceProcess {
225 pub fn new(identifier: &str) -> Self {
226 Self::new_internal(identifier, None)
227 }
228
229 pub fn new_with_extension(identifier: &str, extension: &str) -> Self {
230 Self::new_internal(identifier, Some(extension))
231 }
232
233 fn new_internal(identifier: &str, extension: Option<&str>) -> Self {
234 let mut binary_path =
235 std::env::current_exe().expect("Could not retrieve current executable path");
236 binary_path.pop();
237 binary_path.push(RUST_SERVICE_BINARY);
238 let mut command = Command::new(&binary_path);
239 command.arg(identifier);
240 if let Some(ext) = extension {
241 command.arg(ext);
242 }
243 let child = command.spawn().expect("Could not start service");
244 Self(child)
245 }
246 }
247
248 impl Drop for ScopedServiceProcess {
249 fn drop(&mut self) {
250 self.0.kill().expect("Could not kill child process");
251 self.0
252 .wait()
253 .expect("Could not wait for child process to die");
254 }
255 }
256
257 #[test]
258 fn check_services() {
259 let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
260 assert!(sm.is_binder_alive());
261 assert!(sm.ping_binder().is_ok());
262
263 assert!(binder::get_service("this_service_does_not_exist").is_none());
264 assert_eq!(
265 binder::get_interface::<dyn ITest>("this_service_does_not_exist").err(),
266 Some(StatusCode::NAME_NOT_FOUND)
267 );
268
269 // The service manager service isn't an ITest, so this must fail.
270 assert_eq!(
271 binder::get_interface::<dyn ITest>("manager").err(),
272 Some(StatusCode::BAD_TYPE)
273 );
274 }
275
276 #[test]
Andrew Walbranc3ce5c32021-06-03 16:15:56 +0000277 fn check_wait_for_service() {
278 let mut sm =
279 binder::wait_for_service("manager").expect("Did not get manager binder service");
280 assert!(sm.is_binder_alive());
281 assert!(sm.ping_binder().is_ok());
282
283 // The service manager service isn't an ITest, so this must fail.
284 assert_eq!(
285 binder::wait_for_interface::<dyn ITest>("manager").err(),
286 Some(StatusCode::BAD_TYPE)
287 );
288 }
289
290 #[test]
Stephen Crane2a3c2502020-06-16 17:48:35 -0700291 fn trivial_client() {
292 let service_name = "trivial_client_test";
293 let _process = ScopedServiceProcess::new(service_name);
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800294 let test_client: Strong<dyn ITest> =
Stephen Crane2a3c2502020-06-16 17:48:35 -0700295 binder::get_interface(service_name).expect("Did not get manager binder service");
296 assert_eq!(test_client.test().unwrap(), "trivial_client_test");
297 }
298
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700299 #[test]
Andrew Walbranc3ce5c32021-06-03 16:15:56 +0000300 fn wait_for_trivial_client() {
301 let service_name = "wait_for_trivial_client_test";
302 let _process = ScopedServiceProcess::new(service_name);
303 let test_client: Strong<dyn ITest> =
304 binder::wait_for_interface(service_name).expect("Did not get manager binder service");
305 assert_eq!(test_client.test().unwrap(), "wait_for_trivial_client_test");
306 }
307
308 #[test]
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700309 fn get_selinux_context() {
310 let service_name = "get_selinux_context";
311 let _process = ScopedServiceProcess::new(service_name);
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800312 let test_client: Strong<dyn ITest> =
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700313 binder::get_interface(service_name).expect("Did not get manager binder service");
314 let expected_context = unsafe {
315 let mut out_ptr = ptr::null_mut();
316 assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
317 assert!(!out_ptr.is_null());
318 CStr::from_ptr(out_ptr)
319 };
320 assert_eq!(
321 test_client.get_selinux_context().unwrap(),
Andrew Walbran12400d82021-03-04 17:04:34 +0000322 expected_context
323 .to_str()
324 .expect("context was invalid UTF-8"),
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700325 );
326 }
327
Stephen Crane2a3c2502020-06-16 17:48:35 -0700328 fn register_death_notification(binder: &mut SpIBinder) -> (Arc<AtomicBool>, DeathRecipient) {
329 let binder_died = Arc::new(AtomicBool::new(false));
330
331 let mut death_recipient = {
332 let flag = binder_died.clone();
333 DeathRecipient::new(move || {
334 flag.store(true, Ordering::Relaxed);
335 })
336 };
337
338 binder
339 .link_to_death(&mut death_recipient)
340 .expect("link_to_death failed");
341
342 (binder_died, death_recipient)
343 }
344
345 /// Killing a remote service should unregister the service and trigger
346 /// death notifications.
347 #[test]
348 fn test_death_notifications() {
349 binder::ProcessState::start_thread_pool();
350
351 let service_name = "test_death_notifications";
352 let service_process = ScopedServiceProcess::new(service_name);
353 let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
354
355 let (binder_died, _recipient) = register_death_notification(&mut remote);
356
357 drop(service_process);
358 remote
359 .ping_binder()
360 .expect_err("Service should have died already");
361
362 // Pause to ensure any death notifications get delivered
363 thread::sleep(Duration::from_secs(1));
364
365 assert!(
366 binder_died.load(Ordering::Relaxed),
367 "Did not receive death notification"
368 );
369 }
370
371 /// Test unregistering death notifications.
372 #[test]
373 fn test_unregister_death_notifications() {
374 binder::ProcessState::start_thread_pool();
375
376 let service_name = "test_unregister_death_notifications";
377 let service_process = ScopedServiceProcess::new(service_name);
378 let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
379
380 let (binder_died, mut recipient) = register_death_notification(&mut remote);
381
382 remote
383 .unlink_to_death(&mut recipient)
384 .expect("Could not unlink death notifications");
385
386 drop(service_process);
387 remote
388 .ping_binder()
389 .expect_err("Service should have died already");
390
391 // Pause to ensure any death notifications get delivered
392 thread::sleep(Duration::from_secs(1));
393
394 assert!(
395 !binder_died.load(Ordering::Relaxed),
396 "Received unexpected death notification after unlinking",
397 );
398 }
399
400 /// Dropping a remote handle should unregister any death notifications.
401 #[test]
402 fn test_death_notification_registration_lifetime() {
403 binder::ProcessState::start_thread_pool();
404
405 let service_name = "test_death_notification_registration_lifetime";
406 let service_process = ScopedServiceProcess::new(service_name);
407 let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
408
409 let (binder_died, _recipient) = register_death_notification(&mut remote);
410
411 // This should automatically unregister our death notification.
412 drop(remote);
413
414 drop(service_process);
415
416 // Pause to ensure any death notifications get delivered
417 thread::sleep(Duration::from_secs(1));
418
419 // We dropped the remote handle, so we should not receive the death
420 // notification when the remote process dies here.
421 assert!(
422 !binder_died.load(Ordering::Relaxed),
423 "Received unexpected death notification after dropping remote handle"
424 );
425 }
426
427 /// Test IBinder interface methods not exercised elsewhere.
428 #[test]
429 fn test_misc_ibinder() {
430 let service_name = "rust_test_ibinder";
431
432 {
433 let _process = ScopedServiceProcess::new(service_name);
434
435 let mut remote = binder::get_service(service_name);
436 assert!(remote.is_binder_alive());
437 remote.ping_binder().expect("Could not ping remote service");
438
439 // We're not testing the output of dump here, as that's really a
440 // property of the C++ implementation. There is the risk that the
441 // method just does nothing, but we don't want to depend on any
442 // particular output from the underlying library.
443 let null_out = File::open("/dev/null").expect("Could not open /dev/null");
444 remote
445 .dump(&null_out, &[])
446 .expect("Could not dump remote service");
447 }
448
449 // get/set_extensions is tested in test_extensions()
450
451 // transact is tested everywhere else, and we can't make raw
452 // transactions outside the [FIRST_CALL_TRANSACTION,
453 // LAST_CALL_TRANSACTION] range from the NDK anyway.
454
455 // link_to_death is tested in test_*_death_notification* tests.
456 }
457
458 #[test]
459 fn test_extensions() {
460 let service_name = "rust_test_extensions";
461 let extension_name = "rust_test_extensions_ext";
462
463 {
464 let _process = ScopedServiceProcess::new(service_name);
465
466 let mut remote = binder::get_service(service_name);
467 assert!(remote.is_binder_alive());
468
469 let extension = remote
470 .get_extension()
471 .expect("Could not check for an extension");
472 assert!(extension.is_none());
473 }
474
475 {
476 let _process = ScopedServiceProcess::new_with_extension(service_name, extension_name);
477
478 let mut remote = binder::get_service(service_name);
479 assert!(remote.is_binder_alive());
480
481 let maybe_extension = remote
482 .get_extension()
483 .expect("Could not check for an extension");
484
485 let extension = maybe_extension.expect("Remote binder did not have an extension");
486
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800487 let extension: Strong<dyn ITest> = FromIBinder::try_from(extension)
Stephen Crane2a3c2502020-06-16 17:48:35 -0700488 .expect("Extension could not be converted to the expected interface");
489
490 assert_eq!(extension.test().unwrap(), extension_name);
491 }
492 }
Stephen Crane669deb62020-09-10 17:31:39 -0700493
494 /// Test re-associating a local binder object with a different class.
495 ///
496 /// This is needed because different binder service (e.g. NDK vs Rust)
497 /// implementations are incompatible and must not be interchanged. A local
498 /// service with the same descriptor string but a different class pointer
499 /// may have been created by an NDK service and is therefore incompatible
500 /// with the Rust service implementation. It must be treated as remote and
501 /// all API calls parceled and sent through transactions.
502 ///
503 /// Further tests of this behavior with the C NDK and Rust API are in
504 /// rust_ndk_interop.rs
505 #[test]
506 fn associate_existing_class() {
507 let service = Binder::new(BnTest(Box::new(TestService {
508 s: "testing_service".to_string(),
509 })));
510
511 // This should succeed although we will have to treat the service as
512 // remote.
Andrew Walbran12400d82021-03-04 17:04:34 +0000513 let _interface: Strong<dyn ITestSameDescriptor> =
514 FromIBinder::try_from(service.as_binder())
515 .expect("Could not re-interpret service as the ITestSameDescriptor interface");
Stephen Crane669deb62020-09-10 17:31:39 -0700516 }
517
518 /// Test that we can round-trip a rust service through a generic IBinder
519 #[test]
520 fn reassociate_rust_binder() {
521 let service_name = "testing_service";
Andrew Walbran88eca4f2021-04-13 14:26:01 +0000522 let service_ibinder = BnTest::new_binder(
523 TestService {
524 s: service_name.to_string(),
525 },
526 BinderFeatures::default(),
527 )
Andrew Walbran12400d82021-03-04 17:04:34 +0000528 .as_binder();
Stephen Crane669deb62020-09-10 17:31:39 -0700529
Andrew Walbran12400d82021-03-04 17:04:34 +0000530 let service: Strong<dyn ITest> = service_ibinder
531 .into_interface()
Stephen Crane669deb62020-09-10 17:31:39 -0700532 .expect("Could not reassociate the generic ibinder");
533
534 assert_eq!(service.test().unwrap(), service_name);
535 }
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800536
537 #[test]
538 fn weak_binder_upgrade() {
539 let service_name = "testing_service";
Andrew Walbran88eca4f2021-04-13 14:26:01 +0000540 let service = BnTest::new_binder(
541 TestService {
542 s: service_name.to_string(),
543 },
544 BinderFeatures::default(),
545 );
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800546
547 let weak = Strong::downgrade(&service);
548
549 let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
550
551 assert_eq!(service, upgraded);
552 }
553
554 #[test]
555 fn weak_binder_upgrade_dead() {
556 let service_name = "testing_service";
557 let weak = {
Andrew Walbran88eca4f2021-04-13 14:26:01 +0000558 let service = BnTest::new_binder(
559 TestService {
560 s: service_name.to_string(),
561 },
562 BinderFeatures::default(),
563 );
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800564
565 Strong::downgrade(&service)
566 };
567
568 assert_eq!(weak.upgrade(), Err(StatusCode::DEAD_OBJECT));
569 }
570
571 #[test]
572 fn weak_binder_clone() {
573 let service_name = "testing_service";
Andrew Walbran88eca4f2021-04-13 14:26:01 +0000574 let service = BnTest::new_binder(
575 TestService {
576 s: service_name.to_string(),
577 },
578 BinderFeatures::default(),
579 );
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800580
581 let weak = Strong::downgrade(&service);
582 let cloned = weak.clone();
583 assert_eq!(weak, cloned);
584
585 let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
586 let clone_upgraded = cloned.upgrade().expect("Could not upgrade weak binder");
587
588 assert_eq!(service, upgraded);
589 assert_eq!(service, clone_upgraded);
590 }
591
592 #[test]
593 #[allow(clippy::eq_op)]
594 fn binder_ord() {
Andrew Walbran88eca4f2021-04-13 14:26:01 +0000595 let service1 = BnTest::new_binder(
596 TestService {
597 s: "testing_service1".to_string(),
598 },
599 BinderFeatures::default(),
600 );
601 let service2 = BnTest::new_binder(
602 TestService {
603 s: "testing_service2".to_string(),
604 },
605 BinderFeatures::default(),
606 );
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800607
608 assert!(!(service1 < service1));
609 assert!(!(service1 > service1));
610 assert_eq!(service1 < service2, !(service2 < service1));
611 }
Stephen Crane2a3c2502020-06-16 17:48:35 -0700612}