1 /*
2 * Copyright (C) 2022 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
17 use binder::unstable_api::new_spibinder;
18 use binder::{FromIBinder, SpIBinder, StatusCode, Strong};
19 use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
20 use std::os::fd::RawFd;
21 use std::os::raw::{c_int, c_void};
22
23 pub use binder_rpc_unstable_bindgen::ARpcSession_FileDescriptorTransportMode as FileDescriptorTransportMode;
24
25 foreign_type! {
26 type CType = binder_rpc_unstable_bindgen::ARpcSession;
27 fn drop = binder_rpc_unstable_bindgen::ARpcSession_free;
28
29 /// A type that represents a foreign instance of RpcSession.
30 #[derive(Debug)]
31 pub struct RpcSession;
32 /// A borrowed RpcSession.
33 pub struct RpcSessionRef;
34 }
35
36 /// SAFETY: The opaque handle can be cloned freely.
37 unsafe impl Send for RpcSession {}
38 /// SAFETY: The underlying C++ RpcSession class is thread-safe.
39 unsafe impl Sync for RpcSession {}
40
41 impl RpcSession {
42 /// Allocates a new RpcSession object.
new() -> RpcSession43 pub fn new() -> RpcSession {
44 // SAFETY: Takes ownership of the returned handle, which has correct refcount.
45 unsafe { RpcSession::from_ptr(binder_rpc_unstable_bindgen::ARpcSession_new()) }
46 }
47 }
48
49 impl Default for RpcSession {
default() -> Self50 fn default() -> Self {
51 Self::new()
52 }
53 }
54
55 impl RpcSessionRef {
56 /// Sets the file descriptor transport mode for this session.
set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode)57 pub fn set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode) {
58 // SAFETY: Only passes the 'self' pointer as an opaque handle.
59 unsafe {
60 binder_rpc_unstable_bindgen::ARpcSession_setFileDescriptorTransportMode(
61 self.as_ptr(),
62 mode,
63 )
64 };
65 }
66
67 /// Sets the maximum number of incoming threads.
set_max_incoming_threads(&self, threads: usize)68 pub fn set_max_incoming_threads(&self, threads: usize) {
69 // SAFETY: Only passes the 'self' pointer as an opaque handle.
70 unsafe {
71 binder_rpc_unstable_bindgen::ARpcSession_setMaxIncomingThreads(self.as_ptr(), threads)
72 };
73 }
74
75 /// Sets the maximum number of outgoing connections.
set_max_outgoing_connections(&self, connections: usize)76 pub fn set_max_outgoing_connections(&self, connections: usize) {
77 // SAFETY: Only passes the 'self' pointer as an opaque handle.
78 unsafe {
79 binder_rpc_unstable_bindgen::ARpcSession_setMaxOutgoingConnections(
80 self.as_ptr(),
81 connections,
82 )
83 };
84 }
85
86 /// Connects to an RPC Binder server over vsock for a particular interface.
87 #[cfg(not(target_os = "trusty"))]
setup_vsock_client<T: FromIBinder + ?Sized>( &self, cid: u32, port: u32, ) -> Result<Strong<T>, StatusCode>88 pub fn setup_vsock_client<T: FromIBinder + ?Sized>(
89 &self,
90 cid: u32,
91 port: u32,
92 ) -> Result<Strong<T>, StatusCode> {
93 // SAFETY: AIBinder returned by ARpcSession_setupVsockClient has correct
94 // reference count, and the ownership can safely be taken by new_spibinder.
95 let service = unsafe {
96 new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupVsockClient(
97 self.as_ptr(),
98 cid,
99 port,
100 ))
101 };
102 Self::get_interface(service)
103 }
104
105 /// Connects to an RPC Binder server over a names Unix Domain Socket for
106 /// a particular interface.
107 #[cfg(not(target_os = "trusty"))]
setup_unix_domain_client<T: FromIBinder + ?Sized>( &self, socket_name: &str, ) -> Result<Strong<T>, StatusCode>108 pub fn setup_unix_domain_client<T: FromIBinder + ?Sized>(
109 &self,
110 socket_name: &str,
111 ) -> Result<Strong<T>, StatusCode> {
112 let socket_name = match std::ffi::CString::new(socket_name) {
113 Ok(s) => s,
114 Err(e) => {
115 log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
116 return Err(StatusCode::NAME_NOT_FOUND);
117 }
118 };
119
120 // SAFETY: AIBinder returned by ARpcSession_setupUnixDomainClient has correct
121 // reference count, and the ownership can safely be taken by new_spibinder.
122 let service = unsafe {
123 new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainClient(
124 self.as_ptr(),
125 socket_name.as_ptr(),
126 ))
127 };
128 Self::get_interface(service)
129 }
130
131 /// Connects to an RPC Binder server over a bootstrap Unix Domain Socket
132 /// for a particular interface.
133 #[cfg(not(target_os = "trusty"))]
setup_unix_domain_bootstrap_client<T: FromIBinder + ?Sized>( &self, bootstrap_fd: std::os::fd::BorrowedFd, ) -> Result<Strong<T>, StatusCode>134 pub fn setup_unix_domain_bootstrap_client<T: FromIBinder + ?Sized>(
135 &self,
136 bootstrap_fd: std::os::fd::BorrowedFd,
137 ) -> Result<Strong<T>, StatusCode> {
138 use std::os::fd::AsRawFd;
139 // SAFETY: ARpcSession_setupUnixDomainBootstrapClient does not take
140 // ownership of bootstrap_fd. The returned AIBinder has correct
141 // reference count, and the ownership can safely be taken by new_spibinder.
142 let service = unsafe {
143 new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainBootstrapClient(
144 self.as_ptr(),
145 bootstrap_fd.as_raw_fd(),
146 ))
147 };
148 Self::get_interface(service)
149 }
150
151 /// Connects to an RPC Binder server over inet socket at the given address and port.
152 #[cfg(not(target_os = "trusty"))]
setup_inet_client<T: FromIBinder + ?Sized>( &self, address: &str, port: u32, ) -> Result<Strong<T>, StatusCode>153 pub fn setup_inet_client<T: FromIBinder + ?Sized>(
154 &self,
155 address: &str,
156 port: u32,
157 ) -> Result<Strong<T>, StatusCode> {
158 let address = match std::ffi::CString::new(address) {
159 Ok(s) => s,
160 Err(e) => {
161 log::error!("Cannot convert {} to CString. Error: {:?}", address, e);
162 return Err(StatusCode::BAD_VALUE);
163 }
164 };
165
166 // SAFETY: AIBinder returned by ARpcSession_setupInet has correct reference
167 // count, and the ownership can safely be taken by new_spibinder.
168 let service = unsafe {
169 new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupInet(
170 self.as_ptr(),
171 address.as_ptr(),
172 port,
173 ))
174 };
175 Self::get_interface(service)
176 }
177
178 #[cfg(target_os = "trusty")]
setup_trusty_client<T: FromIBinder + ?Sized>( &self, port: &std::ffi::CStr, ) -> Result<Strong<T>, StatusCode>179 pub fn setup_trusty_client<T: FromIBinder + ?Sized>(
180 &self,
181 port: &std::ffi::CStr,
182 ) -> Result<Strong<T>, StatusCode> {
183 self.setup_preconnected_client(|| {
184 let h = tipc::Handle::connect(port)
185 .expect("Failed to connect to service port {SERVICE_PORT}");
186
187 // Do not close the handle at the end of the scope
188 let fd = h.as_raw_fd();
189 core::mem::forget(h);
190 Some(fd)
191 })
192 }
193
194 /// Connects to an RPC Binder server, using the given callback to get (and
195 /// take ownership of) file descriptors already connected to it.
setup_preconnected_client<T: FromIBinder + ?Sized>( &self, mut request_fd: impl FnMut() -> Option<RawFd>, ) -> Result<Strong<T>, StatusCode>196 pub fn setup_preconnected_client<T: FromIBinder + ?Sized>(
197 &self,
198 mut request_fd: impl FnMut() -> Option<RawFd>,
199 ) -> Result<Strong<T>, StatusCode> {
200 // Double reference the factory because trait objects aren't FFI safe.
201 let mut request_fd_ref: RequestFd = &mut request_fd;
202 let param = &mut request_fd_ref as *mut RequestFd as *mut c_void;
203
204 // SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
205 // ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
206 // of param, only passing it to request_fd_wrapper.
207 let service = unsafe {
208 new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupPreconnectedClient(
209 self.as_ptr(),
210 Some(request_fd_wrapper),
211 param,
212 ))
213 };
214 Self::get_interface(service)
215 }
216
get_interface<T: FromIBinder + ?Sized>( service: Option<SpIBinder>, ) -> Result<Strong<T>, StatusCode>217 fn get_interface<T: FromIBinder + ?Sized>(
218 service: Option<SpIBinder>,
219 ) -> Result<Strong<T>, StatusCode> {
220 if let Some(service) = service {
221 FromIBinder::try_from(service)
222 } else {
223 Err(StatusCode::NAME_NOT_FOUND)
224 }
225 }
226 }
227
228 type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
229
request_fd_wrapper(param: *mut c_void) -> c_int230 unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
231 let request_fd_ptr = param as *mut RequestFd;
232 // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
233 // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
234 // initialized instance.
235 let request_fd = unsafe { request_fd_ptr.as_mut().unwrap() };
236 request_fd().unwrap_or(-1)
237 }
238