rpcbinder/server/
android.rs

1/*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::session::FileDescriptorTransportMode;
18use binder::{unstable_api::AsNative, SpIBinder};
19use binder_rpc_unstable_bindgen::ARpcServer;
20use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
21use std::ffi::{c_uint, CString};
22use std::io::{Error, ErrorKind};
23use std::os::unix::io::{IntoRawFd, OwnedFd};
24
25foreign_type! {
26    type CType = binder_rpc_unstable_bindgen::ARpcServer;
27    fn drop = binder_rpc_unstable_bindgen::ARpcServer_free;
28
29    /// A type that represents a foreign instance of RpcServer.
30    #[derive(Debug)]
31    pub struct RpcServer;
32    /// A borrowed RpcServer.
33    pub struct RpcServerRef;
34}
35
36/// SAFETY: The opaque handle can be cloned freely.
37unsafe impl Send for RpcServer {}
38/// SAFETY: The underlying C++ RpcServer class is thread-safe.
39unsafe impl Sync for RpcServer {}
40
41impl RpcServer {
42    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
43    /// vsock port. Only connections from the given CID are accepted.
44    ///
45    /// Set `cid` to [`libc::VMADDR_CID_ANY`] to accept connections from any client.
46    /// Set `cid` to [`libc::VMADDR_CID_LOCAL`] to only bind to the local vsock interface.
47    /// Set `port` to [`libc::VMADDR_PORT_ANY`] to pick an ephemeral port.
48    /// The assigned port is returned with RpcServer.
49    pub fn new_vsock(
50        mut service: SpIBinder,
51        cid: u32,
52        port: u32,
53    ) -> Result<(RpcServer, u32 /* assigned_port */), Error> {
54        let service = service.as_native_mut();
55
56        let mut assigned_port: c_uint = 0;
57        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
58        // Plus the binder objects are threadsafe.
59        let server = unsafe {
60            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(
61                service,
62                cid,
63                port,
64                &mut assigned_port,
65            ))?
66        };
67        Ok((server, assigned_port as _))
68    }
69
70    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
71    /// socket file descriptor. The socket should be bound to an address before calling this
72    /// function.
73    pub fn new_bound_socket(
74        mut service: SpIBinder,
75        socket_fd: OwnedFd,
76    ) -> Result<RpcServer, Error> {
77        let service = service.as_native_mut();
78
79        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
80        // Plus the binder objects are threadsafe.
81        // The server takes ownership of the socket FD.
82        unsafe {
83            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket(
84                service,
85                socket_fd.into_raw_fd(),
86            ))
87        }
88    }
89
90    /// Creates a binder RPC server that bootstraps sessions using an existing Unix domain socket
91    /// pair, with a given root IBinder object. Callers should create a pair of SOCK_STREAM Unix
92    /// domain sockets, pass one to the server and the other to the client. Multiple client session
93    /// can be created from the client end of the pair.
94    pub fn new_unix_domain_bootstrap(
95        mut service: SpIBinder,
96        bootstrap_fd: OwnedFd,
97    ) -> Result<RpcServer, Error> {
98        let service = service.as_native_mut();
99
100        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
101        // Plus the binder objects are threadsafe.
102        // The server takes ownership of the bootstrap FD.
103        unsafe {
104            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newUnixDomainBootstrap(
105                service,
106                bootstrap_fd.into_raw_fd(),
107            ))
108        }
109    }
110
111    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
112    /// IP address and port.
113    pub fn new_inet(mut service: SpIBinder, address: &str, port: u32) -> Result<RpcServer, Error> {
114        let address = match CString::new(address) {
115            Ok(s) => s,
116            Err(e) => {
117                log::error!("Cannot convert {} to CString. Error: {:?}", address, e);
118                return Err(Error::from(ErrorKind::InvalidInput));
119            }
120        };
121        let service = service.as_native_mut();
122
123        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
124        // Plus the binder objects are threadsafe.
125        unsafe {
126            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInet(
127                service,
128                address.as_ptr(),
129                port,
130            ))
131        }
132    }
133
134    unsafe fn checked_from_ptr(ptr: *mut ARpcServer) -> Result<RpcServer, Error> {
135        if ptr.is_null() {
136            return Err(Error::new(ErrorKind::Other, "Failed to start server"));
137        }
138        // SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not
139        // null.
140        Ok(unsafe { RpcServer::from_ptr(ptr) })
141    }
142}
143
144impl RpcServerRef {
145    /// Sets the list of file descriptor transport modes supported by this server.
146    pub fn set_supported_file_descriptor_transport_modes(
147        &self,
148        modes: &[FileDescriptorTransportMode],
149    ) {
150        // SAFETY: Does not keep the pointer after returning does, nor does it
151        // read past its boundary. Only passes the 'self' pointer as an opaque handle.
152        unsafe {
153            binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
154                self.as_ptr(),
155                modes.as_ptr(),
156                modes.len(),
157            )
158        }
159    }
160
161    /// Sets the max number of threads this Server uses for incoming client connections.
162    ///
163    /// This must be called before adding a client session. This corresponds
164    /// to the number of incoming connections to RpcSession objects in the
165    /// server, which will correspond to the number of outgoing connections
166    /// in client RpcSession objects. Specifically this is useful for handling
167    /// client-side callback connections.
168    ///
169    /// If this is not specified, this will be a single-threaded server.
170    pub fn set_max_threads(&self, count: usize) {
171        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
172        unsafe { binder_rpc_unstable_bindgen::ARpcServer_setMaxThreads(self.as_ptr(), count) };
173    }
174
175    /// Starts a new background thread and calls join(). Returns immediately.
176    pub fn start(&self) {
177        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
178        unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
179    }
180
181    /// Joins the RpcServer thread. The call blocks until the server terminates.
182    /// This must be called from exactly one thread.
183    pub fn join(&self) {
184        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
185        unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
186    }
187
188    /// Shuts down the running RpcServer. Can be called multiple times and from
189    /// multiple threads. Called automatically during drop().
190    pub fn shutdown(&self) -> Result<(), Error> {
191        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
192        if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
193            Ok(())
194        } else {
195            Err(Error::from(ErrorKind::UnexpectedEof))
196        }
197    }
198}