• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, request_fd: impl FnMut() -> Option<RawFd>, ) -> Result<Strong<T>, StatusCode>196     pub fn setup_preconnected_client<T: FromIBinder + ?Sized>(
197         &self,
198         request_fd: impl FnMut() -> Option<RawFd>,
199     ) -> Result<Strong<T>, StatusCode> {
200         // Trait objects aren't FFI safe, so *mut c_void can't be converted back to
201         // *mut dyn FnMut() -> Option<RawFd>>. Double box the factory to make it possible to get
202         // the factory from *mut c_void (to *mut Box<dyn<...>>) in the callbacks.
203         let request_fd_box: Box<dyn FnMut() -> Option<RawFd>> = Box::new(request_fd);
204         let param = Box::into_raw(Box::new(request_fd_box)) as *mut c_void;
205 
206         // SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
207         // ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
208         // of param, only passing it to request_fd_wrapper.
209         let service = unsafe {
210             new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupPreconnectedClient(
211                 self.as_ptr(),
212                 Some(request_fd_wrapper),
213                 param,
214                 Some(param_delete_fd_wrapper),
215             ))
216         };
217         Self::get_interface(service)
218     }
219 
get_interface<T: FromIBinder + ?Sized>( service: Option<SpIBinder>, ) -> Result<Strong<T>, StatusCode>220     fn get_interface<T: FromIBinder + ?Sized>(
221         service: Option<SpIBinder>,
222     ) -> Result<Strong<T>, StatusCode> {
223         if let Some(service) = service {
224             FromIBinder::try_from(service)
225         } else {
226             Err(StatusCode::NAME_NOT_FOUND)
227         }
228     }
229 }
230 
request_fd_wrapper(param: *mut c_void) -> c_int231 unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
232     let request_fd_ptr = param as *mut Box<dyn FnMut() -> Option<RawFd>>;
233     // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
234     // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
235     // initialized instance.
236     let request_fd = unsafe { request_fd_ptr.as_mut().unwrap() };
237     request_fd().unwrap_or(-1)
238 }
239 
param_delete_fd_wrapper(param: *mut c_void)240 unsafe extern "C" fn param_delete_fd_wrapper(param: *mut c_void) {
241     // SAFETY: This is only ever called by RpcPreconnectedClient, with param being the
242     // pointer returned from Box::into_raw.
243     let request_fd_box = unsafe { Box::from_raw(param as *mut Box<dyn FnMut() -> Option<RawFd>>) };
244     drop(request_fd_box);
245 }
246