AIDL Server

Finally, we can create a server which exposes the service:

birthday_service/src/server.rs:

//! Birthday service. use birthdayservice::BirthdayService; use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayService::BnBirthdayService; use com_example_birthdayservice::binder; const SERVICE_IDENTIFIER: &str = "birthdayservice"; /// Entry point for birthday service. fn main() { let birthday_service = BirthdayService; let birthday_service_binder = BnBirthdayService::new_binder( birthday_service, binder::BinderFeatures::default(), ); binder::add_service(SERVICE_IDENTIFIER, birthday_service_binder.as_binder()) .expect("Failed to register service"); binder::ProcessState::join_thread_pool(); }

birthday_service/Android.bp:

rust_binary { name: "birthday_server", crate_name: "birthday_server", srcs: ["src/server.rs"], rustlibs: [ "com.example.birthdayservice-rust", "libbinder_rs", "libbirthdayservice", ], prefer_rlib: true, // To avoid dynamic link error. }

Speaker Notes

The process for taking a user-defined service implementation (in this case the BirthdayService type, which implements the IBirthdayService) and starting it as a Binder service has multiple steps, and may appear more complicated than students are used to if they've used Binder from C++ or another language. Explain to students why each step is necessary.

  1. Create an instance of your service type (BirthdayService).
  2. Wrap the service object in corresponding Bn* type (BnBirthdayService in this case). This type is generated by Binder and provides the common Binder functionality that would be provided by the BnBinder base class in C++. We don't have inheritance in Rust, so instead we use composition, putting our BirthdayService within the generated BnBinderService.
  3. Call add_service, giving it a service identifier and your service object (the BnBirthdayService object in the example).
  4. Call join_thread_pool to add the current thread to Binder's thread pool and start listening for connections.