AIDL Client

Finally, we can create a Rust client for our new service.

birthday_service/src/client.rs:

  1. use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayService::IBirthdayService;
  2. use com_example_birthdayservice::binder;
  3. const SERVICE_IDENTIFIER: &str = "birthdayservice";
  4. /// Call the birthday service.
  5. fn main() -> Result<(), Box<dyn Error>> {
  6. let name = std::env::args().nth(1).unwrap_or_else(|| String::from("Bob"));
  7. let years = std::env::args()
  8. .nth(2)
  9. .and_then(|arg| arg.parse::<i32>().ok())
  10. .unwrap_or(42);
  11. binder::ProcessState::start_thread_pool();
  12. let service = binder::get_interface::<dyn IBirthdayService>(SERVICE_IDENTIFIER)
  13. .map_err(|_| "Failed to connect to BirthdayService")?;
  14. // Call the service.
  15. let msg = service.wishHappyBirthday(&name, years)?;
  16. println!("{msg}");
  17. }

birthday_service/Android.bp:

  1. rust_binary {
  2. name: "birthday_client",
  3. crate_name: "birthday_client",
  4. srcs: ["src/client.rs"],
  5. rustlibs: [
  6. "com.example.birthdayservice-rust",
  7. "libbinder_rs",
  8. ],
  9. prefer_rlib: true, // To avoid dynamic link error.
  10. }

Notice that the client does not depend on libbirthdayservice.

Build, push, and run the client on your device:

  1. m birthday_client
  2. adb push "$ANDROID_PRODUCT_OUT/system/bin/birthday_client" /data/local/tmp
  3. adb shell /data/local/tmp/birthday_client Charlie 60
  1. Happy Birthday Charlie, congratulations with the 60 years!
  • Strong<dyn IBirthdayService> is the trait object representing the service that the client has connected to.
    • Strong is a custom smart pointer type for Binder. It handles both an in-process ref count for the service trait object, and the global Binder ref count that tracks how many processes have a reference to the object.
    • Note that the trait object that the client uses to talk to the service uses the exact same trait that the server implements. For a given Binder interface, there is a single Rust trait generated that both client and server use.
  • Use the same service identifier used when registering the service. This should ideally be defined in a common crate that both the client and server can depend on.