• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_interface;
20 use binder::parcel::Parcel;
21 use binder::{
22     Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
23     FIRST_CALL_TRANSACTION,
24 };
25 use std::convert::{TryFrom, TryInto};
26 
27 /// Name of service runner.
28 ///
29 /// Must match the binary name in Android.bp
30 const 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.
main() -> Result<(), &'static str>36 fn 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         })));
56         service.set_requesting_sid(true);
57         if let Some(extension_name) = extension_name {
58             let extension =
59                 BnTest::new_binder(TestService { s: extension_name }, BinderFeatures::default());
60             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 
print_usage()72 fn 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)]
84 struct TestService {
85     s: String,
86 }
87 
88 #[repr(u32)]
89 enum TestTransactionCode {
90     Test = FIRST_CALL_TRANSACTION,
91     GetSelinuxContext,
92 }
93 
94 impl TryFrom<u32> for TestTransactionCode {
95     type Error = StatusCode;
96 
try_from(c: u32) -> Result<Self, Self::Error>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 
108 impl Interface for TestService {}
109 
110 impl ITest for TestService {
test(&self) -> binder::Result<String>111     fn test(&self) -> binder::Result<String> {
112         Ok(self.s.clone())
113     }
114 
get_selinux_context(&self) -> binder::Result<String>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     }
120 }
121 
122 /// Trivial testing binder interface
123 pub trait ITest: Interface {
124     /// Returns a test string
test(&self) -> binder::Result<String>125     fn test(&self) -> binder::Result<String>;
126 
127     /// Returns the caller's SELinux context
get_selinux_context(&self) -> binder::Result<String>128     fn get_selinux_context(&self) -> binder::Result<String>;
129 }
130 
131 declare_binder_interface! {
132     ITest["android.os.ITest"] {
133         native: BnTest(on_transact),
134         proxy: BpTest {
135             x: i32 = 100
136         },
137     }
138 }
139 
on_transact( service: &dyn ITest, code: TransactionCode, _data: &Parcel, reply: &mut Parcel, ) -> binder::Result<()>140 fn on_transact(
141     service: &dyn ITest,
142     code: TransactionCode,
143     _data: &Parcel,
144     reply: &mut Parcel,
145 ) -> binder::Result<()> {
146     match code.try_into()? {
147         TestTransactionCode::Test => reply.write(&service.test()?),
148         TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
149     }
150 }
151 
152 impl ITest for BpTest {
test(&self) -> binder::Result<String>153     fn test(&self) -> binder::Result<String> {
154         let reply =
155             self.binder
156                 .transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
157         reply.read()
158     }
159 
get_selinux_context(&self) -> binder::Result<String>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         )?;
166         reply.read()
167     }
168 }
169 
170 impl ITest for Binder<BnTest> {
test(&self) -> binder::Result<String>171     fn test(&self) -> binder::Result<String> {
172         self.0.test()
173     }
174 
get_selinux_context(&self) -> binder::Result<String>175     fn get_selinux_context(&self) -> binder::Result<String> {
176         self.0.get_selinux_context()
177     }
178 }
179 
180 /// Trivial testing binder interface
181 pub trait ITestSameDescriptor: Interface {}
182 
183 declare_binder_interface! {
184     ITestSameDescriptor["android.os.ITest"] {
185         native: BnTestSameDescriptor(on_transact_same_descriptor),
186         proxy: BpTestSameDescriptor,
187     }
188 }
189 
on_transact_same_descriptor( _service: &dyn ITestSameDescriptor, _code: TransactionCode, _data: &Parcel, _reply: &mut Parcel, ) -> binder::Result<()>190 fn 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 
199 impl ITestSameDescriptor for BpTestSameDescriptor {}
200 
201 impl ITestSameDescriptor for Binder<BnTestSameDescriptor> {}
202 
203 #[cfg(test)]
204 mod tests {
205     use selinux_bindgen as selinux_sys;
206     use std::ffi::CStr;
207     use std::fs::File;
208     use std::process::{Child, Command};
209     use std::ptr;
210     use std::sync::atomic::{AtomicBool, Ordering};
211     use std::sync::Arc;
212     use std::thread;
213     use std::time::Duration;
214 
215     use binder::{
216         Binder, BinderFeatures, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface,
217         SpIBinder, StatusCode, Strong,
218     };
219 
220     use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
221 
222     pub struct ScopedServiceProcess(Child);
223 
224     impl ScopedServiceProcess {
new(identifier: &str) -> Self225         pub fn new(identifier: &str) -> Self {
226             Self::new_internal(identifier, None)
227         }
228 
new_with_extension(identifier: &str, extension: &str) -> Self229         pub fn new_with_extension(identifier: &str, extension: &str) -> Self {
230             Self::new_internal(identifier, Some(extension))
231         }
232 
new_internal(identifier: &str, extension: Option<&str>) -> Self233         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 {
drop(&mut self)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]
check_services()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]
trivial_client()277     fn trivial_client() {
278         let service_name = "trivial_client_test";
279         let _process = ScopedServiceProcess::new(service_name);
280         let test_client: Strong<dyn ITest> =
281             binder::get_interface(service_name).expect("Did not get manager binder service");
282         assert_eq!(test_client.test().unwrap(), "trivial_client_test");
283     }
284 
285     #[test]
get_selinux_context()286     fn get_selinux_context() {
287         let service_name = "get_selinux_context";
288         let _process = ScopedServiceProcess::new(service_name);
289         let test_client: Strong<dyn ITest> =
290             binder::get_interface(service_name).expect("Did not get manager binder service");
291         let expected_context = unsafe {
292             let mut out_ptr = ptr::null_mut();
293             assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
294             assert!(!out_ptr.is_null());
295             CStr::from_ptr(out_ptr)
296         };
297         assert_eq!(
298             test_client.get_selinux_context().unwrap(),
299             expected_context
300                 .to_str()
301                 .expect("context was invalid UTF-8"),
302         );
303     }
304 
register_death_notification(binder: &mut SpIBinder) -> (Arc<AtomicBool>, DeathRecipient)305     fn register_death_notification(binder: &mut SpIBinder) -> (Arc<AtomicBool>, DeathRecipient) {
306         let binder_died = Arc::new(AtomicBool::new(false));
307 
308         let mut death_recipient = {
309             let flag = binder_died.clone();
310             DeathRecipient::new(move || {
311                 flag.store(true, Ordering::Relaxed);
312             })
313         };
314 
315         binder
316             .link_to_death(&mut death_recipient)
317             .expect("link_to_death failed");
318 
319         (binder_died, death_recipient)
320     }
321 
322     /// Killing a remote service should unregister the service and trigger
323     /// death notifications.
324     #[test]
test_death_notifications()325     fn test_death_notifications() {
326         binder::ProcessState::start_thread_pool();
327 
328         let service_name = "test_death_notifications";
329         let service_process = ScopedServiceProcess::new(service_name);
330         let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
331 
332         let (binder_died, _recipient) = register_death_notification(&mut remote);
333 
334         drop(service_process);
335         remote
336             .ping_binder()
337             .expect_err("Service should have died already");
338 
339         // Pause to ensure any death notifications get delivered
340         thread::sleep(Duration::from_secs(1));
341 
342         assert!(
343             binder_died.load(Ordering::Relaxed),
344             "Did not receive death notification"
345         );
346     }
347 
348     /// Test unregistering death notifications.
349     #[test]
test_unregister_death_notifications()350     fn test_unregister_death_notifications() {
351         binder::ProcessState::start_thread_pool();
352 
353         let service_name = "test_unregister_death_notifications";
354         let service_process = ScopedServiceProcess::new(service_name);
355         let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
356 
357         let (binder_died, mut recipient) = register_death_notification(&mut remote);
358 
359         remote
360             .unlink_to_death(&mut recipient)
361             .expect("Could not unlink death notifications");
362 
363         drop(service_process);
364         remote
365             .ping_binder()
366             .expect_err("Service should have died already");
367 
368         // Pause to ensure any death notifications get delivered
369         thread::sleep(Duration::from_secs(1));
370 
371         assert!(
372             !binder_died.load(Ordering::Relaxed),
373             "Received unexpected death notification after unlinking",
374         );
375     }
376 
377     /// Dropping a remote handle should unregister any death notifications.
378     #[test]
test_death_notification_registration_lifetime()379     fn test_death_notification_registration_lifetime() {
380         binder::ProcessState::start_thread_pool();
381 
382         let service_name = "test_death_notification_registration_lifetime";
383         let service_process = ScopedServiceProcess::new(service_name);
384         let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
385 
386         let (binder_died, _recipient) = register_death_notification(&mut remote);
387 
388         // This should automatically unregister our death notification.
389         drop(remote);
390 
391         drop(service_process);
392 
393         // Pause to ensure any death notifications get delivered
394         thread::sleep(Duration::from_secs(1));
395 
396         // We dropped the remote handle, so we should not receive the death
397         // notification when the remote process dies here.
398         assert!(
399             !binder_died.load(Ordering::Relaxed),
400             "Received unexpected death notification after dropping remote handle"
401         );
402     }
403 
404     /// Test IBinder interface methods not exercised elsewhere.
405     #[test]
test_misc_ibinder()406     fn test_misc_ibinder() {
407         let service_name = "rust_test_ibinder";
408 
409         {
410             let _process = ScopedServiceProcess::new(service_name);
411 
412             let mut remote = binder::get_service(service_name);
413             assert!(remote.is_binder_alive());
414             remote.ping_binder().expect("Could not ping remote service");
415 
416             // We're not testing the output of dump here, as that's really a
417             // property of the C++ implementation. There is the risk that the
418             // method just does nothing, but we don't want to depend on any
419             // particular output from the underlying library.
420             let null_out = File::open("/dev/null").expect("Could not open /dev/null");
421             remote
422                 .dump(&null_out, &[])
423                 .expect("Could not dump remote service");
424         }
425 
426         // get/set_extensions is tested in test_extensions()
427 
428         // transact is tested everywhere else, and we can't make raw
429         // transactions outside the [FIRST_CALL_TRANSACTION,
430         // LAST_CALL_TRANSACTION] range from the NDK anyway.
431 
432         // link_to_death is tested in test_*_death_notification* tests.
433     }
434 
435     #[test]
test_extensions()436     fn test_extensions() {
437         let service_name = "rust_test_extensions";
438         let extension_name = "rust_test_extensions_ext";
439 
440         {
441             let _process = ScopedServiceProcess::new(service_name);
442 
443             let mut remote = binder::get_service(service_name);
444             assert!(remote.is_binder_alive());
445 
446             let extension = remote
447                 .get_extension()
448                 .expect("Could not check for an extension");
449             assert!(extension.is_none());
450         }
451 
452         {
453             let _process = ScopedServiceProcess::new_with_extension(service_name, extension_name);
454 
455             let mut remote = binder::get_service(service_name);
456             assert!(remote.is_binder_alive());
457 
458             let maybe_extension = remote
459                 .get_extension()
460                 .expect("Could not check for an extension");
461 
462             let extension = maybe_extension.expect("Remote binder did not have an extension");
463 
464             let extension: Strong<dyn ITest> = FromIBinder::try_from(extension)
465                 .expect("Extension could not be converted to the expected interface");
466 
467             assert_eq!(extension.test().unwrap(), extension_name);
468         }
469     }
470 
471     /// Test re-associating a local binder object with a different class.
472     ///
473     /// This is needed because different binder service (e.g. NDK vs Rust)
474     /// implementations are incompatible and must not be interchanged. A local
475     /// service with the same descriptor string but a different class pointer
476     /// may have been created by an NDK service and is therefore incompatible
477     /// with the Rust service implementation. It must be treated as remote and
478     /// all API calls parceled and sent through transactions.
479     ///
480     /// Further tests of this behavior with the C NDK and Rust API are in
481     /// rust_ndk_interop.rs
482     #[test]
associate_existing_class()483     fn associate_existing_class() {
484         let service = Binder::new(BnTest(Box::new(TestService {
485             s: "testing_service".to_string(),
486         })));
487 
488         // This should succeed although we will have to treat the service as
489         // remote.
490         let _interface: Strong<dyn ITestSameDescriptor> =
491             FromIBinder::try_from(service.as_binder())
492                 .expect("Could not re-interpret service as the ITestSameDescriptor interface");
493     }
494 
495     /// Test that we can round-trip a rust service through a generic IBinder
496     #[test]
reassociate_rust_binder()497     fn reassociate_rust_binder() {
498         let service_name = "testing_service";
499         let service_ibinder = BnTest::new_binder(
500             TestService {
501                 s: service_name.to_string(),
502             },
503             BinderFeatures::default(),
504         )
505         .as_binder();
506 
507         let service: Strong<dyn ITest> = service_ibinder
508             .into_interface()
509             .expect("Could not reassociate the generic ibinder");
510 
511         assert_eq!(service.test().unwrap(), service_name);
512     }
513 
514     #[test]
weak_binder_upgrade()515     fn weak_binder_upgrade() {
516         let service_name = "testing_service";
517         let service = BnTest::new_binder(
518             TestService {
519                 s: service_name.to_string(),
520             },
521             BinderFeatures::default(),
522         );
523 
524         let weak = Strong::downgrade(&service);
525 
526         let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
527 
528         assert_eq!(service, upgraded);
529     }
530 
531     #[test]
weak_binder_upgrade_dead()532     fn weak_binder_upgrade_dead() {
533         let service_name = "testing_service";
534         let weak = {
535             let service = BnTest::new_binder(
536                 TestService {
537                     s: service_name.to_string(),
538                 },
539                 BinderFeatures::default(),
540             );
541 
542             Strong::downgrade(&service)
543         };
544 
545         assert_eq!(weak.upgrade(), Err(StatusCode::DEAD_OBJECT));
546     }
547 
548     #[test]
weak_binder_clone()549     fn weak_binder_clone() {
550         let service_name = "testing_service";
551         let service = BnTest::new_binder(
552             TestService {
553                 s: service_name.to_string(),
554             },
555             BinderFeatures::default(),
556         );
557 
558         let weak = Strong::downgrade(&service);
559         let cloned = weak.clone();
560         assert_eq!(weak, cloned);
561 
562         let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
563         let clone_upgraded = cloned.upgrade().expect("Could not upgrade weak binder");
564 
565         assert_eq!(service, upgraded);
566         assert_eq!(service, clone_upgraded);
567     }
568 
569     #[test]
570     #[allow(clippy::eq_op)]
binder_ord()571     fn binder_ord() {
572         let service1 = BnTest::new_binder(
573             TestService {
574                 s: "testing_service1".to_string(),
575             },
576             BinderFeatures::default(),
577         );
578         let service2 = BnTest::new_binder(
579             TestService {
580                 s: "testing_service2".to_string(),
581             },
582             BinderFeatures::default(),
583         );
584 
585         assert!(!(service1 < service1));
586         assert!(!(service1 > service1));
587         assert_eq!(service1 < service2, !(service2 < service1));
588     }
589 }
590