### Unified Service and Client Example Commands Source: https://github.com/hiking90/rsbinder/blob/master/book/src/cross-transport-services.md Commands to build and run the unified service and client examples with RPC features enabled. ```text cargo run -p example-hello --features rpc --bin unified_service rpc cargo run -p example-hello --features rpc --bin unified_client rpc ``` -------------------------------- ### Install rsbinder-tools from crates.io Source: https://github.com/hiking90/rsbinder/blob/master/rsbinder-tools/README.md Install the rsbinder-tools package using cargo. ```bash $ cargo install rsbinder-tools ``` -------------------------------- ### Install rsbinder-tools and Create Binder Device Source: https://github.com/hiking90/rsbinder/blob/master/book/src/ubuntu-linux.md Installs the rsbinder-tools using Cargo and then creates a binder device node. Requires root privileges for device creation. ```bash # Test creating a binder device (requires rsbinder-tools) $ cargo install rsbinder-tools $ sudo rsb_device binder ``` -------------------------------- ### Run Example Services Source: https://github.com/hiking90/rsbinder/blob/master/README.md Quickly run example services and clients without needing kernel configuration or root privileges. These commands are useful for initial testing and demonstration. ```bash $ cargo run -p example-hello --features rpc --bin rpc_hello_service $ cargo run -p example-hello --features rpc --bin rpc_hello_client ``` -------------------------------- ### Troubleshooting: Install cargo-ndk Source: https://github.com/hiking90/rsbinder/blob/master/book/src/android-build.md If 'cargo-ndk not found' error occurs, install the tool using this command. ```bash # Install cargo-ndk $ cargo install cargo-ndk ``` -------------------------------- ### Install rsbinder-tools from crates.io Source: https://github.com/hiking90/rsbinder/blob/master/book/src/installation.md Installs the rsbinder-tools package from crates.io, which includes the rsb_device utility for creating binder device files. ```bash $ cargo install rsbinder-tools $ sudo rsb_device binder ``` -------------------------------- ### Emulator Setup and Build Source: https://github.com/hiking90/rsbinder/blob/master/book/src/android-build.md Steps to create and launch an Android emulator, followed by building your project specifically for the emulator target. ```bash # Create and start an emulator $ avdmanager create avd -n test_device -k "system-images;android-34;google_apis;x86_64" $ emulator -avd test_device # Build for emulator target $ cargo ndk -t x86_64-linux-android build --release ``` -------------------------------- ### Install Development Tools and Kernel Headers (Fedora) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Installs necessary tools and kernel development files for building a custom kernel on Fedora. ```bash # Install development tools $ sudo dnf groupinstall "Development Tools" $ sudo dnf install fedora-packager fedpkg $ sudo dnf install kernel-devel kernel-headers # Install kernel build dependencies $ sudo dnf builddep kernel ``` -------------------------------- ### Install ELRepo and Search for Modules (CentOS/RHEL) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Installs the ELRepo repository and searches for available kernel modules related to binder. ```bash # Install ELRepo $ sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org $ sudo dnf install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm # Search for kernel modules $ dnf --enablerepo=elrepo search kernel-ml ``` -------------------------------- ### Install Android SDK Components Source: https://github.com/hiking90/rsbinder/blob/master/book/src/android-build.md Use the `sdkmanager` command-line tool to install necessary Android SDK components like platform-tools, emulator, and system images for testing. ```bash $ sdkmanager "platform-tools" $ sdkmanager "emulator" $ sdkmanager "system-images;android-30;google_apis;x86_64" $ sdkmanager "system-images;android-34;google_apis;x86_64" ``` -------------------------------- ### Verification: List Installed SDK Components Source: https://github.com/hiking90/rsbinder/blob/master/book/src/android-build.md Check which Android SDK components are currently installed on your system. ```bash # Check SDK installation $ sdkmanager --list_installed ``` -------------------------------- ### Build and Install Custom Kernel Source: https://github.com/hiking90/rsbinder/blob/master/book/src/ubuntu-linux.md Compiles the configured kernel, installs modules, updates the bootloader, and reboots the system. This process can take a significant amount of time. ```bash # Build and install $ make -j$(nproc) $ sudo make modules_install $ sudo make install $ sudo update-grub $ sudo reboot ``` -------------------------------- ### Install rsbinder-tools Source: https://github.com/hiking90/rsbinder/blob/master/book/src/arch-linux.md Installs the Rust programming language toolchain and the rsbinder-tools package from crates.io. Ensure Rust is set to the stable channel. ```bash # Install Rust (if not already installed) $ sudo pacman -S rustup $ rustup default stable # Install rsbinder-tools from crates.io $ cargo install rsbinder-tools ``` -------------------------------- ### Build and Install Custom Kernel (Fedora) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Compiles the modified kernel, installs modules, and updates the bootloader. ```bash # Build the kernel $ make -j$(nproc) $ sudo make modules_install $ sudo make install # Update bootloader $ sudo grub2-mkconfig -o /boot/grub2/grub.cfg $ sudo reboot ``` -------------------------------- ### Install Development Tools (RHEL/CentOS) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Installs essential development tools and libraries required for kernel compilation on RHEL/CentOS. ```bash # Install EPEL repository (CentOS/RHEL 8+) $ sudo dnf install epel-release # Install development tools $ sudo dnf groupinstall "Development Tools" $ sudo dnf install rpm-build rpm-devel libtool # Install kernel build dependencies $ sudo dnf install kernel-devel kernel-headers $ sudo dnf install elfutils-libelf-devel openssl-devel ``` -------------------------------- ### Install Build Dependencies for Custom Kernel Source: https://github.com/hiking90/rsbinder/blob/master/book/src/ubuntu-linux.md Installs essential packages required for building a Linux kernel on Ubuntu. ```bash # Install build dependencies $ sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev ``` -------------------------------- ### Minimal RPC Client Setup Source: https://github.com/hiking90/rsbinder/blob/master/book/src/rpc-transport.md Sets up a basic RPC client to connect to a server via a Unix domain socket. It fetches the root binder and calls a method on the remote service. ```rust use rsbinder::rpc::RpcSession; use rsbinder::{FromIBinder, Strong}; use example_hello::*; const RPC_SOCKET: &str = "/tmp/rsb_hello_rpc.sock"; fn main() -> std::result::Result<(), Box> { let session = RpcSession::setup_unix_client(RPC_SOCKET)?; let root = session.get_root()?; // Same generated stub as the kernel path — try_from picks the // RPC proxy under the hood. let hello: Strong = ::try_from(root)?; let reply = hello.echo("Hello over RPC!")?; println!("server replied {reply:?}"); Ok(()) } ``` -------------------------------- ### Install cargo-ndk Source: https://github.com/hiking90/rsbinder/blob/master/book/src/android-build.md Install the `cargo-ndk` utility, which simplifies building Rust projects for Android, by specifying the desired version. ```bash $ cargo install cargo-ndk --version "^3.0" ``` -------------------------------- ### Run rsb_hub Source: https://github.com/hiking90/rsbinder/blob/master/tests/README.md Start the rsb_hub service. This is a prerequisite for running test cases. ```bash $ cargo run --bin rsb_hub ``` -------------------------------- ### Create and Test Binder Device Source: https://github.com/hiking90/rsbinder/blob/master/book/src/arch-linux.md Creates a binder device using `rsb_device`, verifies its creation, and then clones the rsbinder repository to run a simple hello service and client example. Note that binderfs devices are not persistent and must be recreated after a reboot. ```bash # Create binder device (binderfs devices are not persistent -- # re-run this after each reboot) $ sudo rsb_device binder # Verify device creation $ ls -la /dev/binderfs/binder # Test with a simple example $ git clone https://github.com/hiking90/rsbinder.git $ cd rsbinder # Start service manager in one terminal $ rsb_hub # In another terminal, run the example $ cargo run --bin hello_service & $ cargo run --bin hello_client ``` -------------------------------- ### Get and Verify Callback Arrays in Rust Source: https://github.com/hiking90/rsbinder/blob/master/book/src/callbacks-and-interfaces.md Demonstrates how to send an array of names to a service to get corresponding callback interfaces and then verify them. ```rust let names = vec!["Fizz".into(), "Buzz".into()]; let service = get_test_service(); let got = service .GetInterfaceArray(&names) .expect("error calling GetInterfaceArray"); // Each callback has the correct name assert_eq!( got.iter() .map(|s| s.GetName()) .collect::, _>>(), Ok(names.clone()) ); // Verify all names in a single call assert_eq!( service.VerifyNamesWithInterfaceArray(&got, &names), Ok(true) ); ``` -------------------------------- ### Search for Binder Packages (Fedora) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Installs RPM Fusion repositories and searches for available binder-related packages. ```bash # Enable RPM Fusion repositories $ sudo dnf install https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm # Look for available binder-related packages $ dnf search binder android-tools ``` -------------------------------- ### Minimal RPC Server Setup Source: https://github.com/hiking90/rsbinder/blob/master/book/src/rpc-transport.md Sets up a basic RPC server using a Unix domain socket. The server publishes a root binder for clients to connect to. No kernel binder or service manager is involved. ```rust use rsbinder::rpc::RpcServer; use rsbinder::*; use example_hello::*; const RPC_SOCKET: &str = "/tmp/rsb_hello_rpc.sock"; struct IHelloService; impl Interface for IHelloService {} impl IHello for IHelloService { fn echo(&self, echo: &str) -> rsbinder::status::Result { Ok(echo.to_owned()) } } fn main() -> std::result::Result<(), Box> { // No ProcessState, no hub. RPC never touches the kernel binder. let _ = std::fs::remove_file(RPC_SOCKET); let server = RpcServer::setup_unix_server(RPC_SOCKET)?; // Publish a root binder. Clients fetch this via get_root(). server.set_root(BnHello::new_binder(IHelloService {}).as_binder()); // Accept loop runs on this thread until shutdown(). server.run()?; Ok(()) } ``` -------------------------------- ### Build and Run Kernel Binder Services Source: https://github.com/hiking90/rsbinder/blob/master/README.md Build the rsbinder project, set up the binder device, and run the service manager along with example services and clients using the kernel binder transport. ```bash $ cargo build $ sudo target/debug/rsb_device binder # create /dev/binder $ cargo run --bin rsb_hub # service manager $ cargo run --bin hello_service $ cargo run --bin hello_client ``` -------------------------------- ### Run test_service Source: https://github.com/hiking90/rsbinder/blob/master/tests/README.md Start the test_service. This service is required for the test cases to interact with. ```bash $ cargo run --bin test_service ``` -------------------------------- ### Build and Install Custom Kernel (RHEL/CentOS) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Compiles the modified kernel, installs modules, updates the bootloader, and reboots the system. ```bash # Build and install $ make -j$(nproc) $ sudo make modules_install $ sudo make install # Update GRUB $ sudo grub2-mkconfig -o /boot/grub2/grub.cfg $ sudo reboot ``` -------------------------------- ### Get and Prepare Kernel Source (Fedora) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Clones the Fedora kernel source and prepares it for modification. ```bash # Get kernel source $ fedpkg clone -a kernel $ cd kernel $ fedpkg switch-branch f$(rpm -E %fedora) $ fedpkg prep ``` -------------------------------- ### Run rsb_hub with Custom Device Path Source: https://github.com/hiking90/rsbinder/blob/master/book/src/installation.md Starts the rsb_hub service manager, specifying a custom path for the binder device using the --device or -d option. ```bash $ rsb_hub --device custom_binder # or $ rsb_hub -d custom_binder ``` -------------------------------- ### Build rsbinder from Source Source: https://github.com/hiking90/rsbinder/blob/master/book/src/installation.md Clones the rsbinder repository and builds the rsb_device tool from source. This method is an alternative to installing from crates.io. ```bash $ git clone https://github.com/hiking90/rsbinder.git $ cd rsbinder $ cargo build --release $ sudo target/release/rsb_device binder ``` -------------------------------- ### Verify BinderFS and Create Binder Device Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Checks if binderfs is available in the system's file systems and installs 'rsbinder-tools' to create a binder device. ```bash # Check if binderfs is available $ grep binderfs /proc/filesystems # Install rsbinder-tools and create binder device $ cargo install rsbinder-tools $ sudo rsb_device binder # Verify device creation $ ls -la /dev/binderfs/binder ``` -------------------------------- ### Rust Binder Service Implementation Source: https://github.com/hiking90/rsbinder/blob/master/book/src/hello-world.md Implements the IHello interface for a Rust Binder service. Includes initialization of ProcessState, starting a thread pool, and registering the service with the hub. ```rust use env_logger::Env; use rsbinder::*; use hello::*; // Define a struct that implements the IHello interface. struct IHelloService; // Implement the IHello interface for the IHelloService. impl Interface for IHelloService { // Reimplement the dump method. This is optional. fn dump(&self, writer: &mut dyn std::io::Write, _args: &[String]) -> Result<()> { writeln!(writer, "Dump IHelloService")?; Ok(()) } } // Implement the IHello interface for the IHelloService. impl IHello for IHelloService { // Implement the echo method. fn echo(&self, echo: &str) -> rsbinder::status::Result { Ok(echo.to_owned()) } } fn main() -> std::result::Result<(), Box> { env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init(); // Initialize ProcessState with the default binder path and the default max threads. println!("Initializing ProcessState..."); ProcessState::init_default()?; // Start the thread pool. // This is optional. If you don't call this, only one thread will be created to handle the binder transactions. println!("Starting thread pool..."); ProcessState::start_thread_pool(); // Create a binder service. println!("Creating service..."); let service = BnHello::new_binder(IHelloService{}); // Add the service to binder service manager. println!("Adding service to hub..."); hub::add_service(SERVICE_NAME, service.as_binder())?; // Join the thread pool. // This is a blocking call. It will return when the thread pool is terminated. Ok(ProcessState::join_thread_pool()?) } ``` -------------------------------- ### Install linux-zen Kernel on Arch Linux Source: https://github.com/hiking90/rsbinder/blob/master/book/src/arch-linux.md Installs the linux-zen kernel and headers, updates the bootloader, and requires a reboot. Ensure your system is up-to-date before proceeding. ```bash # Update system packages $ sudo pacman -Syu # Install linux-zen kernel and headers $ sudo pacman -S linux-zen linux-zen-headers # Update bootloader configuration $ sudo grub-mkconfig -o /boot/grub/grub.cfg # Reboot to use the new kernel $ sudo reboot ``` -------------------------------- ### Create and Publish IAccessor for RPC Source: https://github.com/hiking90/rsbinder/blob/master/book/src/rpc-transport.md This snippet demonstrates how to set up an RPC server, create an IAccessor that provides a connection to the RPC socket, and publish it via the system service manager. It requires initializing and starting the process state thread pool. ```rust use rsbinder::hub::{self, android_16::{create_accessor, AccessorSockAddr}}; use rsbinder::rpc::RpcServer; use rsbinder::ProcessState; use std::path::PathBuf; // 0. The kernel-binder side needs ProcessState to publish the // accessor through the system service manager. The RPC server // itself does NOT (it runs entirely in user space). ProcessState::init_default()?; ProcessState::start_thread_pool(); // 1. Run a regular RPC server on a UDS. let sock = PathBuf::from("/data/local/tmp/my.sock"); let server = RpcServer::setup_unix_server(&sock)?; server.set_android13plus(2); server.set_root(my_root); let _bg = server.run_background(); // 2. Vend an IAccessor that hands clients an fd connected to // `sock`, and publish it through the kernel service manager. let path = sock.clone(); let accessor = create_accessor("my.service", Box::new(move |_name| { Ok(AccessorSockAddr::Unix(path.clone())) })); hub::add_service("my.service", accessor)?; // 3. Block on the kernel binder thread pool so the accessor stays // reachable for the lifetime of the process. ProcessState::join_thread_pool()?; ``` -------------------------------- ### AIDL Interface for 'out' Parameter Example Source: https://github.com/hiking90/rsbinder/blob/master/book/src/aidl-data-types.md Illustrates the 'out' parameter direction in AIDL for an integer array. ```aidl void GetData(out int[] result); ``` -------------------------------- ### Testing Service Liveness with ping_binder() Source: https://github.com/hiking90/rsbinder/blob/master/book/src/service-patterns.md Provides a simple example of using ping_binder() to check if a service is reachable and responsive. It returns Ok(()) on success and is useful for health checks. ```rust let service = get_service(); assert_eq!(service.as_binder().ping_binder(), Ok(())); ``` -------------------------------- ### Run rsbinder Test Suite Source: https://github.com/hiking90/rsbinder/blob/master/book/src/hello-world.md Execute the rsbinder test suite by starting the service manager, the test service, and then running the client tests in separate terminals. ```bash # Terminal 1: Start service manager $ cargo run --bin rsb_hub # Terminal 2: Start test service $ cargo run --bin test_service # Terminal 3: Run tests $ cargo test -p tests test_client:: ``` -------------------------------- ### Run rsb_hub Service Manager Source: https://github.com/hiking90/rsbinder/blob/master/book/src/installation.md Starts the rsb_hub service manager, which is essential for service registration, discovery, and lifecycle management. ```bash $ rsb_hub ``` -------------------------------- ### Async Service Implementation and Registration Source: https://github.com/hiking90/rsbinder/blob/master/book/src/async-service.md Defines an asynchronous service interface and registers it with a registry. This example shows how to implement an async trait and register an async binder using `new_async_binder`. The registration function is generic over the registry type, making it reusable for different transports. ```rust use async_trait::async_trait; use rsbinder::service::{rpc, Registry, Broker}; use rsbinder::*; struct IHelloService; impl Interface for IHelloService {} #[async_trait] impl IHelloAsyncService for IHelloService { async fn echo(&self, echo: &str) -> rsbinder::status::Result { Ok(echo.to_owned()) } } /// Registration is written once, generic over the transport — identical to the /// sync facade example in "Cross-Transport Services". Only the binder /// constructor differs (`new_async_binder` instead of `new_binder`). fn register( reg: &R, rt: TokioRuntime, ) -> rsbinder::Result<()> { let binder = BnHello::new_async_binder(IHelloService {}, rt).as_binder(); reg.add_service("hello", binder) } ``` -------------------------------- ### rsbinder Service Registration and Main Loop Source: https://github.com/hiking90/rsbinder/blob/master/book/src/service-patterns.md Standard lifecycle for an rsbinder service binary: initialize ProcessState, start the thread pool, create and register the service with the service manager, and block on the thread pool to process transactions. ```rust fn main() -> std::result::Result<(), Box> { // Initialize ProcessState. This opens the Binder device and configures // the process for Binder IPC. Must be called before any Binder operations. // `init_default()` returns `Result<&'static ProcessState, ...>`; use `?` // to surface device-open or initialization failures. ProcessState::init_default()?; // Start additional threads for handling concurrent Binder transactions. // Optional but recommended for services that handle multiple clients. ProcessState::start_thread_pool(); // Create a Binder object from your service implementation. // BnMyService is the server-side stub generated by the AIDL compiler. let service = BnMyService::new_binder(MyService::default()); // Register the service with the service manager (hub). // The first argument is the service name used by clients to find it. hub::add_service("com.example.myservice", service.as_binder())?; // Block the main thread and process incoming Binder transactions. // This call does not return under normal operation. Ok(ProcessState::join_thread_pool()?) } ``` -------------------------------- ### Build rsbinder with mdBook Source: https://github.com/hiking90/rsbinder/blob/master/README.md To build the documentation locally, navigate to the book directory and serve it using mdBook. ```bash cd book mdbook serve ``` -------------------------------- ### Setting Up a Default Implementation for Forward Compatibility Source: https://github.com/hiking90/rsbinder/blob/master/book/src/service-patterns.md Illustrates how to set up a default implementation for an interface, providing fallback behavior when a method is not implemented by the remote service. This enhances forward compatibility. ```rust // Define a default implementation for methods the server may not support. struct MyDefaultImpl; impl rsbinder::Interface for MyDefaultImpl {} impl IMyServiceDefault for MyDefaultImpl { fn UnimplementedMethod(&self, arg: i32) -> std::result::Result { // Provide fallback logic. Ok(arg * 2) } } // Register the default implementation globally for this interface. let di: IMyServiceDefaultRef = Arc::new(MyDefaultImpl); ::setDefaultImpl(di); // When the remote service does not implement UnimplementedMethod, // the default implementation is used transparently. let result = service.UnimplementedMethod(100); assert_eq!(result, Ok(200)); ``` -------------------------------- ### Execute ndk_prepare Function Source: https://github.com/hiking90/rsbinder/blob/master/book/src/android-build.md Use the `ndk_prepare` function from `envsetup.sh` to root the Android device, create a remote directory, and prepare for file synchronization. ```bash $ ndk_prepare ``` -------------------------------- ### Initialize Linux binder environment Source: https://github.com/hiking90/rsbinder/blob/master/rsbinder-tools/README.md Use rsb_device to initialize the Linux binder environment and create binder device files. Requires root privileges. ```bash $ sudo rsb_device binder $ sudo rsb_device test_device ``` -------------------------------- ### Configure Kernel for Binder Support (Fedora) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Navigates to the kernel build directory and uses 'make menuconfig' to enable Binder IPC and BinderFS. ```bash # Modify kernel config to enable binder $ cd ~/rpmbuild/BUILD/kernel-*/linux-* $ make menuconfig # Enable the following options: # General setup -> Android support (CONFIG_ANDROID=y) # CONFIG_ANDROID_BINDER_IPC=y # CONFIG_ANDROID_BINDERFS=y ``` -------------------------------- ### Install Android NDK Version Source: https://github.com/hiking90/rsbinder/blob/master/book/src/android-build.md Install a specific Android NDK version using `sdkmanager`. You can list available NDK versions using `sdkmanager --list`. ```bash # Install specific NDK version $ sdkmanager "ndk;26.1.10909125" # Check for the latest available version: $ sdkmanager --list | grep ndk ``` -------------------------------- ### Configure Persistent Binder Module Loading Source: https://github.com/hiking90/rsbinder/blob/master/book/src/arch-linux.md Sets up configuration files to ensure the binder kernel module is loaded automatically on boot and to specify module parameters for binder devices. ```bash # Create module loading configuration $ echo "binder_linux" | sudo tee /etc/modules-load.d/binder.conf # Set module parameters $ echo "options binder_linux devices=binder,hwbinder,vndbinder" | sudo tee /etc/modprobe.d/binder.conf ``` -------------------------------- ### Download and Prepare Kernel Source Source: https://github.com/hiking90/rsbinder/blob/master/book/src/ubuntu-linux.md Downloads the Linux kernel source code and prepares it for configuration. Replace the version number as needed. ```bash # Download kernel source (replace version as needed) $ wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.tar.xz $ tar -xf linux-6.12.tar.xz $ cd linux-6.12 # Use current kernel config as base $ cp /boot/config-$(uname -r) .config ``` -------------------------------- ### Build rsbinder-tools from source Source: https://github.com/hiking90/rsbinder/blob/master/rsbinder-tools/README.md Clone the rsbinder repository and build the tools from source using cargo. ```bash $ git clone https://github.com/hiking90/rsbinder.git $ cd rsbinder $ cargo build --release ``` -------------------------------- ### Verification: Check cargo-ndk Version Source: https://github.com/hiking90/rsbinder/blob/master/book/src/android-build.md Confirm that cargo-ndk is installed and accessible by checking its version. ```bash # Test cargo-ndk installation $ cargo ndk --version ``` -------------------------------- ### Update Rust Toolchain Source: https://github.com/hiking90/rsbinder/blob/master/book/src/installation.md Ensures you have the latest stable Rust toolchain installed, which is a prerequisite for rsbinder. ```bash $ rustup update stable $ rustc --version # Should be 1.85+ ``` -------------------------------- ### Registering Multiple Services in One Process Source: https://github.com/hiking90/rsbinder/blob/master/book/src/service-patterns.md Demonstrates how to register multiple distinct Binder services within a single process. Each service requires its own implementation and registration call, but they all share the same process state and thread pool. ```rust fn main() -> std::result::Result<(), Box> { ProcessState::init_default()?; ProcessState::start_thread_pool(); // Register the primary test service. let service = BnTestService::new_binder(TestService::default()); hub::add_service(test_service_name, service.as_binder())?; // Register a versioned interface service. let versioned_service = BnFooInterface::new_binder(FooInterface); hub::add_service(versioned_service_name, versioned_service.as_binder())?; // Register a nested service. let nested_service = INestedService::BnNestedService::new_binder(NestedService); hub::add_service(nested_service_name, nested_service.as_binder())?; // Register a fixed-size array service. let fixed_size_array_service = IRepeatFixedSizeArray::BnRepeatFixedSizeArray::new_binder(FixedSizeArrayService); hub::add_service(fixed_size_array_service_name, fixed_size_array_service.as_binder())?; // All services share the same thread pool and process state. Ok(ProcessState::join_thread_pool()?) } ``` -------------------------------- ### AIDL Interface for 'in' Parameter Example Source: https://github.com/hiking90/rsbinder/blob/master/book/src/aidl-data-types.md Illustrates the 'in' parameter direction in AIDL for an integer array. ```aidl void Process(in int[] data); // explicit 'in' void Process(int[] data); // same as above, 'in' is the default ``` -------------------------------- ### RPC Host Initialization and Serving (Unix Socket) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/cross-transport-services.md Initializes and serves a service using RPC over a Unix domain socket. This drives a specific socket and can be run in the background. ```rust use rsbinder::service::{kernel, rpc, Registry, Broker}; use rsbinder::{SIBinder, Strong}; // let host = rpc::Host::unix("/tmp/x.sock")?; // register_all(&host, BnHello::new_binder(MyService).as_binder())?; // host.serve()?; ``` -------------------------------- ### Configure Kernel for Binder Support (RHEL/CentOS) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Uses the current kernel's configuration as a base and enables Binder IPC and BinderFS via 'make menuconfig'. ```bash # Use current kernel config as base $ zcat /proc/config.gz > .config # or $ cp /boot/config-$(uname -r) .config # Modify config to enable binder $ make menuconfig # Enable CONFIG_ANDROID=y, CONFIG_ANDROID_BINDER_IPC=y, CONFIG_ANDROID_BINDERFS=y ``` -------------------------------- ### AIDL Definition for Nested Interface Source: https://github.com/hiking90/rsbinder/blob/master/book/src/callbacks-and-interfaces.md Example AIDL definition of a nested interface 'INestedService' with a nested parcelable and callback interface. ```aidl interface INestedService { @RustDerive(PartialEq=true) parcelable Result { ParcelableWithNested.Status status = ParcelableWithNested.Status.OK; } Result flipStatus(in ParcelableWithNested p); interface ICallback { void done(ParcelableWithNested.Status status); } void flipStatusWithCallback(ParcelableWithNested.Status status, ICallback cb); } ``` -------------------------------- ### Source envsetup.sh Script Source: https://github.com/hiking90/rsbinder/blob/master/book/src/android-build.md Source the `envsetup.sh` script provided by the rsbinder project to load helpful functions for Android development. ```bash # Source the environment setup $ source ./envsetup.sh ``` -------------------------------- ### Get ServiceManager Instance Source: https://github.com/hiking90/rsbinder/blob/master/book/src/service-manager.md Obtain the ServiceManager instance directly for more control over service operations. Initialization can fail, so handle potential errors. ```rust use rsbinder::hub; // `hub::default()` returns `Result, StatusCode>` because // initialization can fail (e.g., binder device unavailable, unsupported SDK). // Propagate the error with `?` or handle it with `match`. let sm = hub::default()?; // Use methods on the ServiceManager instance let service = sm.get_service("com.example.myservice"); let services = sm.list_services(hub::DUMP_FLAG_PRIORITY_ALL); ``` -------------------------------- ### Get Service Proxy Source: https://github.com/hiking90/rsbinder/blob/master/book/src/service-patterns.md Obtain a strongly-typed proxy to a remote service using its unique name. Ensure ProcessState is initialized before calling this. ```rust fn main() -> std::result::Result<(), Box> { // ProcessState must be initialized before any Binder operations. ProcessState::init_default()?; // Obtain a strongly-typed proxy for the service. // hub::get_interface returns a Strong on success. let service: rsbinder::Strong = hub::get_interface("com.example.myservice")?; // Call service methods through the proxy. let result = service.echo("hello")?; println!("Got: {result}"); Ok(()) } ``` -------------------------------- ### Rust Binder Client Implementation Source: https://github.com/hiking90/rsbinder/blob/master/book/src/hello-world.md Implements a Rust Binder client to interact with the IHello service. Demonstrates service discovery, registering for notifications, linking to death recipients, and making remote procedure calls. ```rust #![allow(non_snake_case)] use env_logger::Env; use rsbinder::*; use hello::*; use hub::{BnServiceCallback, IServiceCallback}; use std::sync::Arc; struct MyServiceCallback {} impl Interface for MyServiceCallback {} impl IServiceCallback for MyServiceCallback { fn onRegistration(&self, name: &str, _service: &SIBinder) -> rsbinder::status::Result<()> { println!("MyServiceCallback: {name}"); Ok(()) } } struct MyDeathRecipient {} impl DeathRecipient for MyDeathRecipient { fn binder_died(&self, _who: &WIBinder) { println!("MyDeathRecipient"); } } fn main() -> std::result::Result<(), Box> { env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init(); // Initialize ProcessState with the default binder path and the default max threads. ProcessState::init_default()?; println!("list services:"); // This is an example of how to use service manager. for name in hub::list_services(hub::DUMP_FLAG_PRIORITY_DEFAULT) { println!("{name}"); } let service_callback = BnServiceCallback::new_binder(MyServiceCallback {}); hub::register_for_notifications(SERVICE_NAME, &service_callback)?; // Create a Hello proxy from binder service manager. let hello: rsbinder::Strong = hub::get_interface(SERVICE_NAME) .unwrap_or_else(|_| panic!("Can't find {SERVICE_NAME}")); let recipient = Arc::new(MyDeathRecipient {}); hello .as_binder() .link_to_death(Arc::downgrade(&(recipient as Arc)))?; // Call echo method of Hello proxy. let echo = hello.echo("Hello World!")?; println!("Result: {echo}"); Ok(ProcessState::join_thread_pool()?) } ``` -------------------------------- ### Get Service Debug Information Source: https://github.com/hiking90/rsbinder/blob/master/book/src/service-manager.md Retrieves metadata about every registered service, including its name and the PID of the process hosting it. This feature is available on Android 12 and above. ```rust let debug_info = hub::get_service_debug_info()?; for info in &debug_info { println!("Service: {} (pid: {})", info.name, info.debugPid); } ``` -------------------------------- ### Defining Extendable Parcelable and MyExt Source: https://github.com/hiking90/rsbinder/blob/master/book/src/aidl-parcelable.md Defines AIDL parcelables for the ExtendableParcelable pattern, which uses ParcelableHolder for type-safe, extensible data. MyExt is an example extension type. ```aidl parcelable ExtendableParcelable { int a; @utf8InCpp String b; ParcelableHolder ext; long c; ParcelableHolder ext2; } parcelable MyExt { int a; @utf8InCpp String b; } ``` -------------------------------- ### Load Binder Modules and Configure Persistence Source: https://github.com/hiking90/rsbinder/blob/master/book/src/redhat-linux.md Loads the binder kernel modules and configures them to load automatically on boot, including setting module parameters. ```bash # Load binder modules $ sudo modprobe binder_linux devices="binder,hwbinder,vndbinder" # Verify modules are loaded $ lsmod | grep binder # Create persistent module loading $ echo "binder_linux" | sudo tee /etc/modules-load.d/binder.conf # Set module parameters $ echo "options binder_linux devices=binder,hwbinder,vndbinder" | sudo tee /etc/modprobe.d/binder.conf ``` -------------------------------- ### Set Android Environment Variables Source: https://github.com/hiking90/rsbinder/blob/master/book/src/android-build.md Configure essential environment variables for the Android SDK and NDK in your shell profile. Ensure to replace `` with your installed NDK version. ```bash # Android SDK export ANDROID_HOME=$HOME/Android/Sdk # Linux # export ANDROID_HOME=$HOME/Library/Android/sdk # macOS # Android NDK (replace with your installed version) export ANDROID_NDK_ROOT=$ANDROID_HOME/ndk/ export NDK_HOME=$ANDROID_NDK_ROOT # Add tools to PATH export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin export PATH=$PATH:$ANDROID_HOME/platform-tools export PATH=$PATH:$ANDROID_HOME/emulator ``` -------------------------------- ### Iterate AIDL Enum Values in Rust Source: https://github.com/hiking90/rsbinder/blob/master/book/src/aidl-enum-union.md Illustrates using the `enum_values()` method on generated Rust enum types to get all defined values, useful for iteration and validation. ```rust // enum_values() returns all defined values let all_values = ByteEnum::enum_values(); ``` -------------------------------- ### Configure Kernel for Binder Support Source: https://github.com/hiking90/rsbinder/blob/master/book/src/ubuntu-linux.md Navigates the kernel configuration menu to enable Android Binder IPC and BinderFS. Requires manual interaction via 'make menuconfig'. ```bash # Configure kernel with binder support $ make menuconfig # Navigate to: General setup -> Enable Android support # Enable: # CONFIG_ANDROID=y # CONFIG_ANDROID_BINDER_IPC=y # CONFIG_ANDROID_BINDERFS=y ``` -------------------------------- ### Registering an Async Binder Service Source: https://github.com/hiking90/rsbinder/blob/master/book/src/async-service.md Create and register an asynchronous Binder service using `BnXxx::new_async_binder`. Ensure the `rt()` helper is used to provide the runtime context. ```rust BnXxx::new_async_binder(impl, rt()) ``` -------------------------------- ### Generate Documentation Source: https://github.com/hiking90/rsbinder/blob/master/CONTRIBUTING.md Generate workspace documentation with all features enabled, excluding dependencies. ```bash cargo doc --workspace --all-features --no-deps ``` -------------------------------- ### AIDL 'inout' parameter example Source: https://github.com/hiking90/rsbinder/blob/master/book/src/aidl-data-types.md Demonstrates the AIDL syntax for an 'inout' parameter, where data flows in both directions. This is used when a service needs to read and modify data in place. ```aidl void Transform(inout int[] data); ``` -------------------------------- ### Initialize Tokio Runtime for Kernel Binder Service Source: https://github.com/hiking90/rsbinder/blob/master/book/src/async-service.md Sets up a single-threaded Tokio runtime for a kernel Binder service. This pattern is suitable when the Binder thread pool manages concurrency. It initializes the Binder process, builds the runtime, registers an async service, and then yields to the runtime to keep the process alive. ```rust use rsbinder::*; fn rt() -> TokioRuntime { TokioRuntime(tokio::runtime::Handle::current()) } fn main() -> std::result::Result<(), Box> { // Initialize Binder -- same as the sync case. ProcessState::init_default()?; ProcessState::start_thread_pool(); // Build a single-threaded Tokio runtime. let runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap(); runtime.block_on(async { // Create and register the async service (see next section). let service = BnMyService::new_async_binder( MyAsyncService::default(), rt(), ); hub::add_service("com.example.myservice", service.as_binder()) .expect("Could not register service"); // Yield to the runtime. This keeps the process alive and // drives the Tokio event loop on the current thread. std::future::pending().await }) } ``` -------------------------------- ### Get Caller Identity in Handler Source: https://github.com/hiking90/rsbinder/blob/master/book/src/security.md Read the caller's effective UID within a service handler using `rsbinder::get_calling_uid()`. This accessor is available on the dispatching thread during a transaction. ```rust use rsbinder::{Caller, ExceptionCode, Status}; impl IExample for MyService { fn do_thing(&self, arg: i32) -> rsbinder::status::Result<()> { let uid = rsbinder::get_calling_uid(); // who is calling, right now // ... authorize, then act ... Ok(()) } } ``` -------------------------------- ### Service State with Mutex Source: https://github.com/hiking90/rsbinder/blob/master/book/src/service-patterns.md Example of using a Mutex to protect mutable service state (a HashMap) within a service struct, as Binder methods typically receive immutable references (&self). ```rust #[derive(Default)] struct TestService { service_map: Mutex>>, } ``` -------------------------------- ### Reverse Array of ParcelFileDescriptors Source: https://github.com/hiking90/rsbinder/blob/master/book/src/parcel-file-descriptor.md Demonstrates handling arrays of ParcelFileDescriptors in AIDL interfaces. This example reverses an input array while also populating an output parameter with duplicated descriptors in the original order. ```rust fn ReverseParcelFileDescriptorArray( &self, input: &[ParcelFileDescriptor], repeated: &mut Vec>, ) -> rsbinder::status::Result> { repeated.clear(); repeated.extend(input.iter().map(dup_fd).map(Some)); Ok(input.iter().rev().map(dup_fd).collect()) } ``` -------------------------------- ### Enable Fancy Error Reporting with Miette Source: https://github.com/hiking90/rsbinder/blob/master/rsbinder-aidl/README.md Call miette::set_hook() at the start of your main function to enable colored and Unicode error output. This snippet also includes the AIDL generation. ```rust fn main() -> miette::Result<()> { miette::set_hook(Box::new(|_| { Box::new(miette::MietteHandlerOpts::new().build()) }))?; rsbinder_aidl::Builder::new() .source(std::path::PathBuf::from("aidl/IMyService.aidl")) .output(std::path::PathBuf::from("my_service.rs")) .generate()?; Ok(()) } ``` -------------------------------- ### RPC Broker Initialization and Service Call (Unix Socket) Source: https://github.com/hiking90/rsbinder/blob/master/book/src/cross-transport-services.md Initializes a broker for RPC over a Unix domain socket and calls a remote service. ```rust use rsbinder::service::{kernel, rpc, Registry, Broker}; use rsbinder::{SIBinder, Strong}; // or rpc::Broker::unix("/tmp/x.sock")? // let broker = rpc::Broker::unix("/tmp/x.sock")?; // let hello = talk(&broker)?; // hello.echo("hi")?; ``` -------------------------------- ### Run the rsbinder Service Manager (HUB) on Linux Source: https://github.com/hiking90/rsbinder/blob/master/book/src/service-manager.md This command builds and runs the `rsb_hub` binary, which acts as the service manager. It must be running for services to register and clients to perform lookups. ```bash # Build and run the service manager $ cargo run --bin rsb_hub ``` -------------------------------- ### Get Caller Identity with CallingContext Source: https://github.com/hiking90/rsbinder/blob/master/book/src/hello-world.md Access the UID, PID, and SELinux context of the calling process within a service method. Services must implement their own access control policies based on this information. ```rust use rsbinder::thread_state::CallingContext; fn echo(&self, echo: &str) -> rsbinder::status::Result { let caller = CallingContext::default(); let caller_uid = caller.uid; let caller_pid = caller.pid; let caller_sid = caller.sid; // Optional SELinux context // Enforce your own access control policy if caller_uid != expected_uid { return Err(rsbinder::Status::from(rsbinder::StatusCode::PermissionDenied)); } Ok(echo.to_owned()) } ``` -------------------------------- ### Async Trait Implementation with Macros Source: https://github.com/hiking90/rsbinder/blob/master/book/src/async-service.md Example of implementing async trait methods using declarative macros for repeat and reverse operations, alongside a standard async function. Lifetime annotations are crucial here. ```rust #[async_trait] impl ITestService::ITestServiceAsyncService for TestService { impl_repeat! {RepeatInt, i32} impl_reverse! {ReverseInt, i32} async fn RepeatString(&self, input: &str) -> rsbinder::status::Result { Ok(input.into()) } // ... other methods } ```