binder-rust 0.1.2

An implementatoin of Android Binder API for rust
Documentation
use crate::{
    binder::{Binder, BinderFlatObject, Transaction, TransactionFlags},
    parcel::Parcel,
};

use std::ffi::c_void;
use std::marker::PhantomData;

use num_traits::FromPrimitive;

const SERVICE_MANAGER_HANDLE: i32 = 0;
const SERVICE_MANAGER_INTERFACE_TOKEN: &str = "android.os.IServiceManager";

enum ServiceManagerFunctions {
    GetService = 1,
    CheckService = 2,
    AddService = 3,
    ListServices = 4,
}

pub struct Service<'a> {
    service_manager: &'a mut ServiceManager<'a>,
    handle: i32,
    name: &'a str,
    interface_name: &'a str,
}

impl<'a> Service<'a> {
    pub fn new(service_manager: &'a mut ServiceManager<'a>, name: &'a str, interface_name: &'a str, handle: i32) -> Self {
        Self {
            service_manager,
            name,
            interface_name,
            handle,
        }
    }
    pub fn call(&mut self, function_index: u32, data: &mut Parcel) -> Parcel {
        let mut parcel = Parcel::empty();
        parcel.write_interface_token(self.interface_name);
        if data.len() > 0 {
            parcel.append_parcel(data);
        };

        let (_, mut parcel) = self
            .service_manager
            .binder
            .transact(self.handle, function_index, TransactionFlags::AcceptFds, &mut parcel);

        let status = parcel.read_u32();
        if status != 0 {
            panic!(
                "service call failed with status: {:x}, {} - {}\n{}",
                status,
                parcel.read_str16(),
                parcel.read_u32(),
                parcel.read_str16()
            );
        };

        parcel
    }
}

pub trait BinderService {
    fn process_request(&self, code: u32, data: &mut Parcel) -> Parcel;
}

pub struct ServiceListener<'a, BS>
where
    BS: BinderService,
{
    service_delegate: &'a BS,
    service_manager: &'a mut ServiceManager<'a>,
    name: &'a str,
    interface_name: &'a str,
}

impl<'a, BS> ServiceListener<'a, BS>
where
    BS: BinderService,
{
    pub fn new(service_delegate: &'a BS, service_manager: &'a mut ServiceManager<'a>, name: &'a str, interface_name: &'a str) -> Self {
        Self {
            service_delegate,
            service_manager,
            name,
            interface_name,
        }
    }

    pub fn run(&mut self){
        loop {

            let (transaction, mut parcel) = self.service_manager.binder.do_write_read(&mut Parcel::empty());
            match transaction {
                Some(transaction) => {
                    if transaction.code() >= Transaction::FirstCall as u32 && transaction.code() <= Transaction::LastCall as u32 {
                        assert!(&parcel.read_interface_token() == self.interface_name);
                        self.service_manager.binder.reply(&mut self.service_delegate.process_request(transaction.code(), &mut parcel), transaction.flags());
                    } else {
                        match Transaction::from_u32(transaction.code()) {
                            Interface => {
                                let mut parcel = Parcel::empty();
                                parcel.write_u32(0);
                                parcel.write_str16(self.interface_name);
                                self.service_manager.binder.reply(&mut parcel, transaction.flags() | TransactionFlags::AcceptFds);
                            }
                            _ => {}
                        }
                    }
                },
                None => {}
            }
        }
        }
}

pub struct ServiceManager<'a> {
    binder: Binder,
    phantom: &'a PhantomData<Binder>
}

impl<'a> ServiceManager<'a> {
    pub fn new() -> Self {
        let mut service_manager = Self {
            binder: Binder::new(),
            phantom: &PhantomData,
        };

        service_manager.ping();

        service_manager
    }

    fn ping(&mut self) {
        let mut parcel = Parcel::empty();
        self.binder.transact(
            SERVICE_MANAGER_HANDLE,
            Transaction::Ping as u32,
            TransactionFlags::empty(),
            &mut parcel,
        );
    }

    pub fn get_service(&'a mut self, service_name: &'a str, interface_name: &'a str) -> Service<'a> {
        let mut parcel = Parcel::empty();
        parcel.write_interface_token(SERVICE_MANAGER_INTERFACE_TOKEN);
        parcel.write_str16(service_name);
        let (transaction, mut parcel) = self.binder.transact(
            SERVICE_MANAGER_HANDLE,
            ServiceManagerFunctions::GetService as u32,
            TransactionFlags::empty(),
            &mut parcel,
        );
        parcel.read_u32();
        let flat_object: BinderFlatObject = parcel.read_object();

        self.binder.add_ref(flat_object.handle as i32);
        self.binder.acquire(flat_object.handle as i32);

        Service::new(self, service_name, interface_name, flat_object.handle as i32)
    }

    pub fn register_service<BS: BinderService>(
        &'a mut self,
        service_delegate: &'a BS,
        name: &'a str,
        interface_name: &'a str,
        allow_isolated: bool,
        dump_priority: u32,
    ) -> ServiceListener<'a, BS> {

        self.binder.enter_looper();

        let mut parcel = Parcel::empty();
        parcel.write_interface_token(SERVICE_MANAGER_INTERFACE_TOKEN);
        parcel.write_str16(name);
        parcel.write_binder(self as *const _ as *const c_void);
        parcel.write_bool(allow_isolated);
        parcel.write_u32(dump_priority);

        let (transaction, mut parcel) = self.binder.transact(
            SERVICE_MANAGER_HANDLE,
            ServiceManagerFunctions::AddService as u32,
            TransactionFlags::empty(),
            &mut parcel,
        );

        ServiceListener::new(service_delegate, self, name, interface_name)
    }
}