Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b3382ff authored by Hasini Gunasinghe's avatar Hasini Gunasinghe Committed by Android (Google) Code Review
Browse files

Merge "Add support for Trusty RpcServer to accept three types of client ids" into main

parents 3400a6eb 233b105e
Loading
Loading
Loading
Loading
+80 −15
Original line number Diff line number Diff line
@@ -14,14 +14,28 @@
 * limitations under the License.
 */

use alloc::boxed::Box;
use binder::{unstable_api::AsNative, SpIBinder};
use libc::size_t;
use log::error;
use std::ffi::{c_char, c_void};
use std::ptr;
use tipc::{ConnectResult, Handle, MessageResult, PortCfg, TipcError, UnbufferedService, Uuid};
use tipc::{
    ClientIdentifier, ConnectResult, Handle, MessageResult, PortCfg, TipcError, UnbufferedService,
    Uuid,
};

pub trait PerSessionCallback: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {}
impl<T> PerSessionCallback for T where T: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {}
/// Trait alias for the callback passed into the per-session constructor of the RpcServer.
/// Note: this is used in this file only, although it is marked as pub to be able to be used in
/// the definition of the pub constructor.
pub trait PerSessionCallback:
    Fn(ClientIdentifier) -> Option<SpIBinder> + Send + Sync + 'static
{
}
impl<T> PerSessionCallback for T where
    T: Fn(ClientIdentifier) -> Option<SpIBinder> + Send + Sync + 'static
{
}

pub struct RpcServer {
    inner: *mut binder_rpc_server_bindgen::ARpcServerTrusty,
@@ -52,7 +66,7 @@ impl RpcServer {
    /// Allocates a new per-session RpcServer object.
    ///
    /// Per-session objects take a closure that gets called once
    /// for every new connection. The closure gets the UUID of
    /// for every new connection. The closure gets the `ClientIdentifier` of
    /// the peer and can accept or reject that connection.
    pub fn new_per_session<F: PerSessionCallback>(f: F) -> RpcServer {
        // SAFETY: Takes ownership of the returned handle, which has correct refcount.
@@ -68,25 +82,35 @@ impl RpcServer {
}

unsafe extern "C" fn per_session_callback_wrapper<F: PerSessionCallback>(
    uuid_ptr: *const c_void,
    client_id_ptr: *const c_void,
    len: size_t,
    cb_ptr: *mut c_char,
) -> *mut binder_rpc_server_bindgen::AIBinder {
    // SAFETY: This callback should only get called while the RpcServer is alive.
    let cb = unsafe { &mut *cb_ptr.cast::<F>() };

    if len != std::mem::size_of::<Uuid>() {
    if len < 1 {
        return ptr::null_mut();
    }
    // SAFETY: We have checked that the length is at least 1
    // We know that the pointer has not been freed at this point, because:
    // 1) The pointer is allocated in the call to: `on_connect` or `on_new_connection` in the
    //    implementation of the `UnbufferredService` trait for `RpcServer`.
    // 2) `on_connect` and `on_new_connection` invokes `ARpcServerTrusty_handleConnect`, immediately
    //    after the allocation.
    // 3) this callback is invoked in the callpath of `ARpcServerTrusty_handleConnect`.
    // We know that there is no concurrent mutable access to the pointer because it is allocated
    // and accessed in the same (single) process as per the callpath described above.
    let client_id_data = unsafe { std::slice::from_raw_parts(client_id_ptr.cast(), len) };
    let client_id = match ClientIdentifier::from_tagged_bytes(client_id_data) {
        Ok(c) => c,
        Err(_) => {
            error!("error in reconstructing the ClientIdentifier from pointer and length");
            return ptr::null_mut();
        }

    // SAFETY: On the previous lines we check that we got exactly the right amount of bytes.
    let uuid = unsafe {
        let mut uuid = std::mem::MaybeUninit::<Uuid>::uninit();
        uuid.as_mut_ptr().copy_from(uuid_ptr.cast(), 1);
        uuid.assume_init()
    };

    cb(uuid).map_or_else(ptr::null_mut, |b| {
    cb(client_id).map_or_else(ptr::null_mut, |b| {
        // Prevent AIBinder_decStrong from being called before AIBinder_toPlatformBinder.
        // The per-session callback in C++ is supposed to call AIBinder_decStrong on the
        // pointer we return here.
@@ -129,11 +153,21 @@ impl UnbufferedService for RpcServer {
        peer: &Uuid,
    ) -> tipc::Result<ConnectResult<Self::Connection>> {
        let mut conn = RpcServerConnection { ctx: std::ptr::null_mut() };
        let client_identifier = ClientIdentifier::UUID(peer.clone());
        let mut data = client_identifier.as_tagged_bytes();
        let len = data.len();
        // SAFETY: This unsafe block calls into a C++ function, which is considered safe, i.e. it
        // does not cause undefined behavior for valid inputs (see below), returns an integer which
        // indicates success or error, does not allocate or deallocate memory that Rust owns.
        // The inputs passed into the C++ function are valid: Trusty is single threaded, so there is
        // no concurrent access to `sef.inner`` and other inputs are not freed/deallocated until the
        // function returns. Correct length of the data pointed to by the pointer is passed in.
        let rc = unsafe {
            binder_rpc_server_bindgen::ARpcServerTrusty_handleConnect(
                self.inner,
                handle.as_raw_fd(),
                peer.as_ptr().cast(),
                data.as_mut_ptr() as *const c_void,
                len,
                &mut conn.ctx,
            )
        };
@@ -161,4 +195,35 @@ impl UnbufferedService for RpcServer {
    fn on_disconnect(&self, conn: &Self::Connection) {
        unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleDisconnect(conn.ctx) };
    }

    fn on_new_connection(
        &self,
        _port: &PortCfg,
        handle: &Handle,
        client_identifier: &ClientIdentifier,
    ) -> tipc::Result<ConnectResult<Self::Connection>> {
        let mut conn = RpcServerConnection { ctx: std::ptr::null_mut() };
        let mut data = client_identifier.as_tagged_bytes();
        let len = data.len();
        // SAFETY: This unsafe block calls into a C++ function, which is considered safe, i.e. it
        // does not cause undefined behavior for valid inputs (see below), returns an integer which
        // indicates success or error, does not allocate or deallocate memory that Rust owns.
        // The inputs passed into the C++ function are valid: Trusty is single threaded, so there is
        // no concurrent access to `sef.inner`` and other inputs are not freed/deallocated until the
        // function returns. Correct length of the data pointed to by the pointer is passed in.
        let rc = unsafe {
            binder_rpc_server_bindgen::ARpcServerTrusty_handleConnect(
                self.inner,
                handle.as_raw_fd(),
                data.as_mut_ptr() as *const c_void,
                len,
                &mut conn.ctx,
            )
        };
        if rc < 0 {
            Err(TipcError::from_uapi(rc.into()))
        } else {
            Ok(ConnectResult::Accept(conn))
        }
    }
}
+10 −6
Original line number Diff line number Diff line
@@ -97,11 +97,13 @@ RpcServerTrusty::RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::stri
int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const uuid* peer,
                                   void** ctx_p) {
    auto* server = reinterpret_cast<RpcServerTrusty*>(const_cast<void*>(port->priv));
    return handleConnectInternal(server->mRpcServer.get(), chan, peer, ctx_p);
    const void* uuid_ptr = static_cast<const void*>(peer);
    constexpr size_t uuidLen = sizeof(*peer);
    return handleConnectInternal(server->mRpcServer.get(), chan, uuid_ptr, uuidLen, ctx_p);
}

int RpcServerTrusty::handleConnectInternal(RpcServer* rpcServer, handle_t chan, const uuid* peer,
                                           void** ctx_p) {
int RpcServerTrusty::handleConnectInternal(RpcServer* rpcServer, handle_t chan,
                                           const void* addrData, size_t addrDataLen, void** ctx_p) {
    rpcServer->mShutdownTrigger = FdTrigger::make();
    rpcServer->mConnectingThreads[rpc_this_thread::get_id()] = RpcMaybeThread();

@@ -137,10 +139,12 @@ int RpcServerTrusty::handleConnectInternal(RpcServer* rpcServer, handle_t chan,
    android::RpcTransportFd transportFd(std::move(clientFd));

    std::array<uint8_t, RpcServer::kRpcAddressSize> addr;
    constexpr size_t addrLen = sizeof(*peer);
    memcpy(addr.data(), peer, addrLen);
    if (addrDataLen > RpcServer::kRpcAddressSize) {
        return ERR_BAD_LEN;
    }
    memcpy(addr.data(), addrData, addrDataLen);
    RpcServer::establishConnection(sp<RpcServer>::fromExisting(rpcServer), std::move(transportFd),
                                   addr, addrLen, joinFn);
                                   addr, addrDataLen, joinFn);

    return rc;
}
+1 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ struct ARpcServerTrusty* ARpcServerTrusty_newPerSession(struct AIBinder* (*)(con
                                                                             char*),
                                                        char*, void (*)(char*));
void ARpcServerTrusty_delete(struct ARpcServerTrusty*);
int ARpcServerTrusty_handleConnect(struct ARpcServerTrusty*, handle_t, const struct uuid*, void**);
int ARpcServerTrusty_handleConnect(struct ARpcServerTrusty*, handle_t, const void*, size_t, void**);
int ARpcServerTrusty_handleMessage(void*);
void ARpcServerTrusty_handleDisconnect(void*);
void ARpcServerTrusty_handleChannelCleanup(void*);
+15 −3
Original line number Diff line number Diff line
@@ -114,7 +114,19 @@ private:
                                                                                char*),
                                                                char*, void (*)(char*));
    friend void ::ARpcServerTrusty_delete(::ARpcServerTrusty*);
    friend int ::ARpcServerTrusty_handleConnect(::ARpcServerTrusty*, handle_t, const uuid*, void**);
    /**
     * @brief Handle the binder RPC connection.
     *
     * @param rstr  - RpcServer object
     * @param chan - handle to the connection
     * @param clientId - identifier of the client as tagged data
     * @param clientIdLen - length of the client identifier
     * @param ctx_p - connection context
     * @return int - error code
     */
    friend int ::ARpcServerTrusty_handleConnect(struct ARpcServerTrusty* rstr, handle_t chan,
                                                const void* clientId, size_t clientIdLen,
                                                void** ctx_p);
    friend int ::ARpcServerTrusty_handleMessage(void*);
    friend void ::ARpcServerTrusty_handleDisconnect(void*);
    friend void ::ARpcServerTrusty_handleChannelCleanup(void*);
@@ -130,8 +142,8 @@ private:
    static void handleDisconnect(const tipc_port* port, handle_t chan, void* ctx);
    static void handleChannelCleanup(void* ctx);

    static int handleConnectInternal(RpcServer* rpcServer, handle_t chan, const uuid* peer,
                                     void** ctx_p);
    static int handleConnectInternal(RpcServer* rpcServer, handle_t chan, const void* addrData,
                                     size_t addrDataLen, void** ctx_p);
    static int handleMessageInternal(void* ctx);
    static void handleDisconnectInternal(void* ctx);

+4 −3
Original line number Diff line number Diff line
@@ -72,9 +72,10 @@ void ARpcServerTrusty_delete(ARpcServerTrusty* rstr) {
    delete rstr;
}

int ARpcServerTrusty_handleConnect(ARpcServerTrusty* rstr, handle_t chan, const uuid* peer,
                                   void** ctx_p) {
    return RpcServerTrusty::handleConnectInternal(rstr->mRpcServer.get(), chan, peer, ctx_p);
int ARpcServerTrusty_handleConnect(ARpcServerTrusty* rstr, handle_t chan, const void* clientId,
                                   size_t clientIdLen, void** ctx_p) {
    return RpcServerTrusty::handleConnectInternal(rstr->mRpcServer.get(), chan, clientId,
                                                  clientIdLen, ctx_p);
}

int ARpcServerTrusty_handleMessage(void* ctx) {