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

Commit 7a821197 authored by Andrew Walbran's avatar Andrew Walbran Committed by Gerrit Code Review
Browse files

Merge "Add Rust API for RPC binder."

parents 62bb50a6 c4d1cbde
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -446,6 +446,7 @@ cc_library {
    // This library is intentionally limited to these targets, and it will be removed later.
    // Do not expand the visibility.
    visibility: [
        ":__subpackages__",
        "//packages/modules/Virtualization:__subpackages__",
    ],
}
+0 −28
Original line number Diff line number Diff line
@@ -144,24 +144,6 @@ rust_bindgen {
    min_sdk_version: "Tiramisu",
}

// TODO(b/184872979): remove once the Rust API is created.
rust_bindgen {
    name: "libbinder_rpc_unstable_bindgen",
    wrapper_src: ":libbinder_rpc_unstable_header",
    crate_name: "binder_rpc_unstable_bindgen",
    visibility: ["//packages/modules/Virtualization:__subpackages__"],
    source_stem: "bindings",
    shared_libs: [
        "libutils",
    ],
    apex_available: [
        "com.android.compos",
        "com.android.uwb",
        "com.android.virt",
    ],
    min_sdk_version: "Tiramisu",
}

rust_test {
    name: "libbinder_rs-internal_test",
    crate_name: "binder",
@@ -188,13 +170,3 @@ rust_test {
    clippy_lints: "none",
    lints: "none",
}

rust_test {
    name: "libbinder_rpc_unstable_bindgen_test",
    srcs: [":libbinder_rpc_unstable_bindgen"],
    crate_name: "binder_rpc_unstable_bindgen",
    test_suites: ["general-tests"],
    auto_gen_config: true,
    clippy_lints: "none",
    lints: "none",
}
+50 −0
Original line number Diff line number Diff line
rust_library {
    name: "librpcbinder_rs",
    crate_name: "rpcbinder",
    srcs: ["src/lib.rs"],
    shared_libs: [
        "libutils",
    ],
    rustlibs: [
        "libbinder_ndk_sys",
        "libbinder_rpc_unstable_bindgen",
        "libbinder_rs",
        "libdowncast_rs",
        "liblibc",
    ],
    apex_available: [
        "com.android.compos",
        "com.android.uwb",
        "com.android.virt",
    ],
    min_sdk_version: "Tiramisu",
}

// TODO(b/184872979): remove once the RPC Binder API is stabilised.
rust_bindgen {
    name: "libbinder_rpc_unstable_bindgen",
    wrapper_src: ":libbinder_rpc_unstable_header",
    crate_name: "binder_rpc_unstable_bindgen",
    visibility: [":__subpackages__"],
    source_stem: "bindings",
    shared_libs: [
        "libbinder_rpc_unstable",
        "libutils",
    ],
    apex_available: [
        "com.android.compos",
        "com.android.uwb",
        "com.android.virt",
    ],
    min_sdk_version: "Tiramisu",
}

rust_test {
    name: "libbinder_rpc_unstable_bindgen_test",
    srcs: [":libbinder_rpc_unstable_bindgen"],
    crate_name: "binder_rpc_unstable_bindgen",
    test_suites: ["general-tests"],
    auto_gen_config: true,
    clippy_lints: "none",
    lints: "none",
}
+92 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use binder::{
    unstable_api::{new_spibinder, AIBinder},
    FromIBinder, SpIBinder, StatusCode, Strong,
};
use std::os::{
    raw::{c_int, c_void},
    unix::io::RawFd,
};

/// Connects to an RPC Binder server over vsock.
pub fn get_vsock_rpc_service(cid: u32, port: u32) -> Option<SpIBinder> {
    // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can
    // safely be taken by new_spibinder.
    unsafe { new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, port) as *mut AIBinder) }
}

/// Connects to an RPC Binder server for a particular interface over vsock.
pub fn get_vsock_rpc_interface<T: FromIBinder + ?Sized>(
    cid: u32,
    port: u32,
) -> Result<Strong<T>, StatusCode> {
    interface_cast(get_vsock_rpc_service(cid, port))
}

/// Connects to an RPC Binder server, using the given callback to get (and take ownership of)
/// file descriptors already connected to it.
pub fn get_preconnected_rpc_service(
    mut request_fd: impl FnMut() -> Option<RawFd>,
) -> Option<SpIBinder> {
    // Double reference the factory because trait objects aren't FFI safe.
    let mut request_fd_ref: RequestFd = &mut request_fd;
    let param = &mut request_fd_ref as *mut RequestFd as *mut c_void;

    // SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
    // ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
    // of param, only passing it to request_fd_wrapper.
    unsafe {
        new_spibinder(binder_rpc_unstable_bindgen::RpcPreconnectedClient(
            Some(request_fd_wrapper),
            param,
        ) as *mut AIBinder)
    }
}

type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;

unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
    // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
    // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
    // initialized instance.
    let request_fd_ptr = param as *mut RequestFd;
    let request_fd = request_fd_ptr.as_mut().unwrap();
    if let Some(fd) = request_fd() {
        fd
    } else {
        -1
    }
}

/// Connects to an RPC Binder server for a particular interface, using the given callback to get
/// (and take ownership of) file descriptors already connected to it.
pub fn get_preconnected_rpc_interface<T: FromIBinder + ?Sized>(
    request_fd: impl FnMut() -> Option<RawFd>,
) -> Result<Strong<T>, StatusCode> {
    interface_cast(get_preconnected_rpc_service(request_fd))
}

fn interface_cast<T: FromIBinder + ?Sized>(
    service: Option<SpIBinder>,
) -> Result<Strong<T>, StatusCode> {
    if let Some(service) = service {
        FromIBinder::try_from(service)
    } else {
        Err(StatusCode::NAME_NOT_FOUND)
    }
}
+26 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! API for RPC Binder services.

mod client;
mod server;

pub use client::{
    get_preconnected_rpc_interface, get_preconnected_rpc_service, get_vsock_rpc_interface,
    get_vsock_rpc_service,
};
pub use server::{run_rpc_server, run_rpc_server_with_factory};
Loading