blob: 60e350275969ea2339f088cf791392ead7643352 [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::{
22 Binder, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
23 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 {
58 let extension = BnTest::new_binder(TestService { s: extension_name });
59 service
60 .set_extension(&mut extension.as_binder())
61 .expect("Could not add extension");
62 }
63 binder::add_service(&service_name, service.as_binder())
64 .expect("Could not register service");
65 }
66
67 binder::ProcessState::join_thread_pool();
68 Err("Unexpected exit after join_thread_pool")
69}
70
71fn print_usage() {
72 eprintln!(
73 "Usage: {} SERVICE_NAME [EXTENSION_NAME]",
74 RUST_SERVICE_BINARY
75 );
76 eprintln!(concat!(
77 "Spawn a Binder test service identified by SERVICE_NAME,",
78 " optionally with an extesion named EXTENSION_NAME",
79 ));
80}
81
82#[derive(Clone)]
83struct TestService {
84 s: String,
85}
86
Janis Danisevskis798a09a2020-08-18 08:35:38 -070087#[repr(u32)]
88enum TestTransactionCode {
Andrew Walbran12400d82021-03-04 17:04:34 +000089 Test = FIRST_CALL_TRANSACTION,
Janis Danisevskis798a09a2020-08-18 08:35:38 -070090 GetSelinuxContext,
91}
92
93impl TryFrom<u32> for TestTransactionCode {
94 type Error = StatusCode;
95
96 fn try_from(c: u32) -> Result<Self, Self::Error> {
97 match c {
98 _ if c == TestTransactionCode::Test as u32 => Ok(TestTransactionCode::Test),
99 _ if c == TestTransactionCode::GetSelinuxContext as u32 => {
100 Ok(TestTransactionCode::GetSelinuxContext)
101 }
102 _ => Err(StatusCode::UNKNOWN_TRANSACTION),
103 }
104 }
105}
106
Stephen Crane2a3c2502020-06-16 17:48:35 -0700107impl Interface for TestService {}
108
109impl ITest for TestService {
110 fn test(&self) -> binder::Result<String> {
111 Ok(self.s.clone())
112 }
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700113
114 fn get_selinux_context(&self) -> binder::Result<String> {
115 let sid =
116 ThreadState::with_calling_sid(|sid| sid.map(|s| s.to_string_lossy().into_owned()));
117 sid.ok_or(StatusCode::UNEXPECTED_NULL)
118 }
Stephen Crane2a3c2502020-06-16 17:48:35 -0700119}
120
121/// Trivial testing binder interface
122pub trait ITest: Interface {
123 /// Returns a test string
124 fn test(&self) -> binder::Result<String>;
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700125
126 /// Returns the caller's SELinux context
127 fn get_selinux_context(&self) -> binder::Result<String>;
Stephen Crane2a3c2502020-06-16 17:48:35 -0700128}
129
130declare_binder_interface! {
131 ITest["android.os.ITest"] {
132 native: BnTest(on_transact),
133 proxy: BpTest {
134 x: i32 = 100
135 },
136 }
137}
138
139fn on_transact(
140 service: &dyn ITest,
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700141 code: TransactionCode,
Stephen Crane2a3c2502020-06-16 17:48:35 -0700142 _data: &Parcel,
143 reply: &mut Parcel,
144) -> binder::Result<()> {
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700145 match code.try_into()? {
146 TestTransactionCode::Test => reply.write(&service.test()?),
147 TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
148 }
Stephen Crane2a3c2502020-06-16 17:48:35 -0700149}
150
151impl ITest for BpTest {
152 fn test(&self) -> binder::Result<String> {
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700153 let reply =
154 self.binder
155 .transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
156 reply.read()
157 }
158
159 fn get_selinux_context(&self) -> binder::Result<String> {
160 let reply = self.binder.transact(
161 TestTransactionCode::GetSelinuxContext as TransactionCode,
162 0,
163 |_| Ok(()),
164 )?;
Stephen Crane2a3c2502020-06-16 17:48:35 -0700165 reply.read()
166 }
167}
168
169impl ITest for Binder<BnTest> {
170 fn test(&self) -> binder::Result<String> {
171 self.0.test()
172 }
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700173
174 fn get_selinux_context(&self) -> binder::Result<String> {
175 self.0.get_selinux_context()
176 }
Stephen Crane2a3c2502020-06-16 17:48:35 -0700177}
178
Stephen Crane669deb62020-09-10 17:31:39 -0700179/// Trivial testing binder interface
180pub trait ITestSameDescriptor: Interface {}
181
182declare_binder_interface! {
183 ITestSameDescriptor["android.os.ITest"] {
184 native: BnTestSameDescriptor(on_transact_same_descriptor),
185 proxy: BpTestSameDescriptor,
186 }
187}
188
189fn on_transact_same_descriptor(
190 _service: &dyn ITestSameDescriptor,
191 _code: TransactionCode,
192 _data: &Parcel,
193 _reply: &mut Parcel,
194) -> binder::Result<()> {
195 Ok(())
196}
197
198impl ITestSameDescriptor for BpTestSameDescriptor {}
199
200impl ITestSameDescriptor for Binder<BnTestSameDescriptor> {}
201
Stephen Crane2a3c2502020-06-16 17:48:35 -0700202#[cfg(test)]
203mod tests {
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700204 use selinux_bindgen as selinux_sys;
205 use std::ffi::CStr;
Stephen Crane2a3c2502020-06-16 17:48:35 -0700206 use std::fs::File;
207 use std::process::{Child, Command};
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700208 use std::ptr;
Stephen Crane2a3c2502020-06-16 17:48:35 -0700209 use std::sync::atomic::{AtomicBool, Ordering};
210 use std::sync::Arc;
211 use std::thread;
212 use std::time::Duration;
213
Andrew Walbran12400d82021-03-04 17:04:34 +0000214 use binder::{
215 Binder, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface, SpIBinder,
216 StatusCode, Strong,
217 };
Stephen Crane2a3c2502020-06-16 17:48:35 -0700218
Andrew Walbran12400d82021-03-04 17:04:34 +0000219 use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
Stephen Crane2a3c2502020-06-16 17:48:35 -0700220
221 pub struct ScopedServiceProcess(Child);
222
223 impl ScopedServiceProcess {
224 pub fn new(identifier: &str) -> Self {
225 Self::new_internal(identifier, None)
226 }
227
228 pub fn new_with_extension(identifier: &str, extension: &str) -> Self {
229 Self::new_internal(identifier, Some(extension))
230 }
231
232 fn new_internal(identifier: &str, extension: Option<&str>) -> Self {
233 let mut binary_path =
234 std::env::current_exe().expect("Could not retrieve current executable path");
235 binary_path.pop();
236 binary_path.push(RUST_SERVICE_BINARY);
237 let mut command = Command::new(&binary_path);
238 command.arg(identifier);
239 if let Some(ext) = extension {
240 command.arg(ext);
241 }
242 let child = command.spawn().expect("Could not start service");
243 Self(child)
244 }
245 }
246
247 impl Drop for ScopedServiceProcess {
248 fn drop(&mut self) {
249 self.0.kill().expect("Could not kill child process");
250 self.0
251 .wait()
252 .expect("Could not wait for child process to die");
253 }
254 }
255
256 #[test]
257 fn check_services() {
258 let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
259 assert!(sm.is_binder_alive());
260 assert!(sm.ping_binder().is_ok());
261
262 assert!(binder::get_service("this_service_does_not_exist").is_none());
263 assert_eq!(
264 binder::get_interface::<dyn ITest>("this_service_does_not_exist").err(),
265 Some(StatusCode::NAME_NOT_FOUND)
266 );
267
268 // The service manager service isn't an ITest, so this must fail.
269 assert_eq!(
270 binder::get_interface::<dyn ITest>("manager").err(),
271 Some(StatusCode::BAD_TYPE)
272 );
273 }
274
275 #[test]
276 fn trivial_client() {
277 let service_name = "trivial_client_test";
278 let _process = ScopedServiceProcess::new(service_name);
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800279 let test_client: Strong<dyn ITest> =
Stephen Crane2a3c2502020-06-16 17:48:35 -0700280 binder::get_interface(service_name).expect("Did not get manager binder service");
281 assert_eq!(test_client.test().unwrap(), "trivial_client_test");
282 }
283
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700284 #[test]
285 fn get_selinux_context() {
286 let service_name = "get_selinux_context";
287 let _process = ScopedServiceProcess::new(service_name);
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800288 let test_client: Strong<dyn ITest> =
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700289 binder::get_interface(service_name).expect("Did not get manager binder service");
290 let expected_context = unsafe {
291 let mut out_ptr = ptr::null_mut();
292 assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
293 assert!(!out_ptr.is_null());
294 CStr::from_ptr(out_ptr)
295 };
296 assert_eq!(
297 test_client.get_selinux_context().unwrap(),
Andrew Walbran12400d82021-03-04 17:04:34 +0000298 expected_context
299 .to_str()
300 .expect("context was invalid UTF-8"),
Janis Danisevskis798a09a2020-08-18 08:35:38 -0700301 );
302 }
303
Stephen Crane2a3c2502020-06-16 17:48:35 -0700304 fn register_death_notification(binder: &mut SpIBinder) -> (Arc<AtomicBool>, DeathRecipient) {
305 let binder_died = Arc::new(AtomicBool::new(false));
306
307 let mut death_recipient = {
308 let flag = binder_died.clone();
309 DeathRecipient::new(move || {
310 flag.store(true, Ordering::Relaxed);
311 })
312 };
313
314 binder
315 .link_to_death(&mut death_recipient)
316 .expect("link_to_death failed");
317
318 (binder_died, death_recipient)
319 }
320
321 /// Killing a remote service should unregister the service and trigger
322 /// death notifications.
323 #[test]
324 fn test_death_notifications() {
325 binder::ProcessState::start_thread_pool();
326
327 let service_name = "test_death_notifications";
328 let service_process = ScopedServiceProcess::new(service_name);
329 let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
330
331 let (binder_died, _recipient) = register_death_notification(&mut remote);
332
333 drop(service_process);
334 remote
335 .ping_binder()
336 .expect_err("Service should have died already");
337
338 // Pause to ensure any death notifications get delivered
339 thread::sleep(Duration::from_secs(1));
340
341 assert!(
342 binder_died.load(Ordering::Relaxed),
343 "Did not receive death notification"
344 );
345 }
346
347 /// Test unregistering death notifications.
348 #[test]
349 fn test_unregister_death_notifications() {
350 binder::ProcessState::start_thread_pool();
351
352 let service_name = "test_unregister_death_notifications";
353 let service_process = ScopedServiceProcess::new(service_name);
354 let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
355
356 let (binder_died, mut recipient) = register_death_notification(&mut remote);
357
358 remote
359 .unlink_to_death(&mut recipient)
360 .expect("Could not unlink death notifications");
361
362 drop(service_process);
363 remote
364 .ping_binder()
365 .expect_err("Service should have died already");
366
367 // Pause to ensure any death notifications get delivered
368 thread::sleep(Duration::from_secs(1));
369
370 assert!(
371 !binder_died.load(Ordering::Relaxed),
372 "Received unexpected death notification after unlinking",
373 );
374 }
375
376 /// Dropping a remote handle should unregister any death notifications.
377 #[test]
378 fn test_death_notification_registration_lifetime() {
379 binder::ProcessState::start_thread_pool();
380
381 let service_name = "test_death_notification_registration_lifetime";
382 let service_process = ScopedServiceProcess::new(service_name);
383 let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
384
385 let (binder_died, _recipient) = register_death_notification(&mut remote);
386
387 // This should automatically unregister our death notification.
388 drop(remote);
389
390 drop(service_process);
391
392 // Pause to ensure any death notifications get delivered
393 thread::sleep(Duration::from_secs(1));
394
395 // We dropped the remote handle, so we should not receive the death
396 // notification when the remote process dies here.
397 assert!(
398 !binder_died.load(Ordering::Relaxed),
399 "Received unexpected death notification after dropping remote handle"
400 );
401 }
402
403 /// Test IBinder interface methods not exercised elsewhere.
404 #[test]
405 fn test_misc_ibinder() {
406 let service_name = "rust_test_ibinder";
407
408 {
409 let _process = ScopedServiceProcess::new(service_name);
410
411 let mut remote = binder::get_service(service_name);
412 assert!(remote.is_binder_alive());
413 remote.ping_binder().expect("Could not ping remote service");
414
415 // We're not testing the output of dump here, as that's really a
416 // property of the C++ implementation. There is the risk that the
417 // method just does nothing, but we don't want to depend on any
418 // particular output from the underlying library.
419 let null_out = File::open("/dev/null").expect("Could not open /dev/null");
420 remote
421 .dump(&null_out, &[])
422 .expect("Could not dump remote service");
423 }
424
425 // get/set_extensions is tested in test_extensions()
426
427 // transact is tested everywhere else, and we can't make raw
428 // transactions outside the [FIRST_CALL_TRANSACTION,
429 // LAST_CALL_TRANSACTION] range from the NDK anyway.
430
431 // link_to_death is tested in test_*_death_notification* tests.
432 }
433
434 #[test]
435 fn test_extensions() {
436 let service_name = "rust_test_extensions";
437 let extension_name = "rust_test_extensions_ext";
438
439 {
440 let _process = ScopedServiceProcess::new(service_name);
441
442 let mut remote = binder::get_service(service_name);
443 assert!(remote.is_binder_alive());
444
445 let extension = remote
446 .get_extension()
447 .expect("Could not check for an extension");
448 assert!(extension.is_none());
449 }
450
451 {
452 let _process = ScopedServiceProcess::new_with_extension(service_name, extension_name);
453
454 let mut remote = binder::get_service(service_name);
455 assert!(remote.is_binder_alive());
456
457 let maybe_extension = remote
458 .get_extension()
459 .expect("Could not check for an extension");
460
461 let extension = maybe_extension.expect("Remote binder did not have an extension");
462
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800463 let extension: Strong<dyn ITest> = FromIBinder::try_from(extension)
Stephen Crane2a3c2502020-06-16 17:48:35 -0700464 .expect("Extension could not be converted to the expected interface");
465
466 assert_eq!(extension.test().unwrap(), extension_name);
467 }
468 }
Stephen Crane669deb62020-09-10 17:31:39 -0700469
470 /// Test re-associating a local binder object with a different class.
471 ///
472 /// This is needed because different binder service (e.g. NDK vs Rust)
473 /// implementations are incompatible and must not be interchanged. A local
474 /// service with the same descriptor string but a different class pointer
475 /// may have been created by an NDK service and is therefore incompatible
476 /// with the Rust service implementation. It must be treated as remote and
477 /// all API calls parceled and sent through transactions.
478 ///
479 /// Further tests of this behavior with the C NDK and Rust API are in
480 /// rust_ndk_interop.rs
481 #[test]
482 fn associate_existing_class() {
483 let service = Binder::new(BnTest(Box::new(TestService {
484 s: "testing_service".to_string(),
485 })));
486
487 // This should succeed although we will have to treat the service as
488 // remote.
Andrew Walbran12400d82021-03-04 17:04:34 +0000489 let _interface: Strong<dyn ITestSameDescriptor> =
490 FromIBinder::try_from(service.as_binder())
491 .expect("Could not re-interpret service as the ITestSameDescriptor interface");
Stephen Crane669deb62020-09-10 17:31:39 -0700492 }
493
494 /// Test that we can round-trip a rust service through a generic IBinder
495 #[test]
496 fn reassociate_rust_binder() {
497 let service_name = "testing_service";
Andrew Walbran12400d82021-03-04 17:04:34 +0000498 let service_ibinder = BnTest::new_binder(TestService {
499 s: service_name.to_string(),
500 })
501 .as_binder();
Stephen Crane669deb62020-09-10 17:31:39 -0700502
Andrew Walbran12400d82021-03-04 17:04:34 +0000503 let service: Strong<dyn ITest> = service_ibinder
504 .into_interface()
Stephen Crane669deb62020-09-10 17:31:39 -0700505 .expect("Could not reassociate the generic ibinder");
506
507 assert_eq!(service.test().unwrap(), service_name);
508 }
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800509
510 #[test]
511 fn weak_binder_upgrade() {
512 let service_name = "testing_service";
Andrew Walbran12400d82021-03-04 17:04:34 +0000513 let service = BnTest::new_binder(TestService {
514 s: service_name.to_string(),
515 });
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800516
517 let weak = Strong::downgrade(&service);
518
519 let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
520
521 assert_eq!(service, upgraded);
522 }
523
524 #[test]
525 fn weak_binder_upgrade_dead() {
526 let service_name = "testing_service";
527 let weak = {
Andrew Walbran12400d82021-03-04 17:04:34 +0000528 let service = BnTest::new_binder(TestService {
529 s: service_name.to_string(),
530 });
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800531
532 Strong::downgrade(&service)
533 };
534
535 assert_eq!(weak.upgrade(), Err(StatusCode::DEAD_OBJECT));
536 }
537
538 #[test]
539 fn weak_binder_clone() {
540 let service_name = "testing_service";
Andrew Walbran12400d82021-03-04 17:04:34 +0000541 let service = BnTest::new_binder(TestService {
542 s: service_name.to_string(),
543 });
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800544
545 let weak = Strong::downgrade(&service);
546 let cloned = weak.clone();
547 assert_eq!(weak, cloned);
548
549 let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
550 let clone_upgraded = cloned.upgrade().expect("Could not upgrade weak binder");
551
552 assert_eq!(service, upgraded);
553 assert_eq!(service, clone_upgraded);
554 }
555
556 #[test]
557 #[allow(clippy::eq_op)]
558 fn binder_ord() {
Andrew Walbran12400d82021-03-04 17:04:34 +0000559 let service1 = BnTest::new_binder(TestService {
560 s: "testing_service1".to_string(),
561 });
562 let service2 = BnTest::new_binder(TestService {
563 s: "testing_service2".to_string(),
564 });
Stephen Craneddb3e6d2020-12-18 13:27:22 -0800565
566 assert!(!(service1 < service1));
567 assert!(!(service1 > service1));
568 assert_eq!(service1 < service2, !(service2 < service1));
569 }
Stephen Crane2a3c2502020-06-16 17:48:35 -0700570}