1 /*
2  * Copyright (C) 2023 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::AsNative, SpIBinder};
18 use libc::size_t;
19 use std::ffi::{c_char, c_void};
20 use std::ptr;
21 use tipc::{ConnectResult, Handle, MessageResult, PortCfg, TipcError, UnbufferedService, Uuid};
22 
23 pub trait PerSessionCallback: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {}
24 impl<T> PerSessionCallback for T where T: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {}
25 
26 pub struct RpcServer {
27     inner: *mut binder_rpc_server_bindgen::ARpcServerTrusty,
28 }
29 
30 /// SAFETY: The opaque handle points to a heap allocation
31 /// that should be process-wide and not tied to the current thread.
32 unsafe impl Send for RpcServer {}
33 /// SAFETY: The underlying C++ RpcServer class is thread-safe.
34 unsafe impl Sync for RpcServer {}
35 
36 impl Drop for RpcServer {
drop(&mut self)37     fn drop(&mut self) {
38         // SAFETY: `ARpcServerTrusty_delete` is the correct destructor to call
39         // on pointers returned by `ARpcServerTrusty_new`.
40         unsafe {
41             binder_rpc_server_bindgen::ARpcServerTrusty_delete(self.inner);
42         }
43     }
44 }
45 
46 impl RpcServer {
47     /// Allocates a new RpcServer object.
new(service: SpIBinder) -> RpcServer48     pub fn new(service: SpIBinder) -> RpcServer {
49         Self::new_per_session(move |_uuid| Some(service.clone()))
50     }
51 
52     /// Allocates a new per-session RpcServer object.
53     ///
54     /// Per-session objects take a closure that gets called once
55     /// for every new connection. The closure gets the UUID of
56     /// the peer and can accept or reject that connection.
new_per_session<F: PerSessionCallback>(f: F) -> RpcServer57     pub fn new_per_session<F: PerSessionCallback>(f: F) -> RpcServer {
58         // SAFETY: Takes ownership of the returned handle, which has correct refcount.
59         let inner = unsafe {
60             binder_rpc_server_bindgen::ARpcServerTrusty_newPerSession(
61                 Some(per_session_callback_wrapper::<F>),
62                 Box::into_raw(Box::new(f)).cast(),
63                 Some(per_session_callback_deleter::<F>),
64             )
65         };
66         RpcServer { inner }
67     }
68 }
69 
per_session_callback_wrapper<F: PerSessionCallback>( uuid_ptr: *const c_void, len: size_t, cb_ptr: *mut c_char, ) -> *mut binder_rpc_server_bindgen::AIBinder70 unsafe extern "C" fn per_session_callback_wrapper<F: PerSessionCallback>(
71     uuid_ptr: *const c_void,
72     len: size_t,
73     cb_ptr: *mut c_char,
74 ) -> *mut binder_rpc_server_bindgen::AIBinder {
75     // SAFETY: This callback should only get called while the RpcServer is alive.
76     let cb = unsafe { &mut *cb_ptr.cast::<F>() };
77 
78     if len != std::mem::size_of::<Uuid>() {
79         return ptr::null_mut();
80     }
81 
82     // SAFETY: On the previous lines we check that we got exactly the right amount of bytes.
83     let uuid = unsafe {
84         let mut uuid = std::mem::MaybeUninit::<Uuid>::uninit();
85         uuid.as_mut_ptr().copy_from(uuid_ptr.cast(), 1);
86         uuid.assume_init()
87     };
88 
89     cb(uuid).map_or_else(ptr::null_mut, |b| {
90         // Prevent AIBinder_decStrong from being called before AIBinder_toPlatformBinder.
91         // The per-session callback in C++ is supposed to call AIBinder_decStrong on the
92         // pointer we return here.
93         std::mem::ManuallyDrop::new(b).as_native_mut().cast()
94     })
95 }
96 
per_session_callback_deleter<F: PerSessionCallback>(cb: *mut c_char)97 unsafe extern "C" fn per_session_callback_deleter<F: PerSessionCallback>(cb: *mut c_char) {
98     // SAFETY: shared_ptr calls this to delete the pointer we gave it.
99     // It should only get called once the last shared reference goes away.
100     unsafe {
101         drop(Box::<F>::from_raw(cb.cast()));
102     }
103 }
104 
105 pub struct RpcServerConnection {
106     ctx: *mut c_void,
107 }
108 
109 impl Drop for RpcServerConnection {
drop(&mut self)110     fn drop(&mut self) {
111         // We do not need to close handle_fd since we do not own it.
112         unsafe {
113             binder_rpc_server_bindgen::ARpcServerTrusty_handleChannelCleanup(self.ctx);
114         }
115     }
116 }
117 
118 impl UnbufferedService for RpcServer {
119     type Connection = RpcServerConnection;
120 
on_connect( &self, _port: &PortCfg, handle: &Handle, peer: &Uuid, ) -> tipc::Result<ConnectResult<Self::Connection>>121     fn on_connect(
122         &self,
123         _port: &PortCfg,
124         handle: &Handle,
125         peer: &Uuid,
126     ) -> tipc::Result<ConnectResult<Self::Connection>> {
127         let mut conn = RpcServerConnection { ctx: std::ptr::null_mut() };
128         let rc = unsafe {
129             binder_rpc_server_bindgen::ARpcServerTrusty_handleConnect(
130                 self.inner,
131                 handle.as_raw_fd(),
132                 peer.as_ptr().cast(),
133                 &mut conn.ctx,
134             )
135         };
136         if rc < 0 {
137             Err(TipcError::from_uapi(rc.into()))
138         } else {
139             Ok(ConnectResult::Accept(conn))
140         }
141     }
142 
on_message( &self, conn: &Self::Connection, _handle: &Handle, buffer: &mut [u8], ) -> tipc::Result<MessageResult>143     fn on_message(
144         &self,
145         conn: &Self::Connection,
146         _handle: &Handle,
147         buffer: &mut [u8],
148     ) -> tipc::Result<MessageResult> {
149         assert!(buffer.is_empty());
150         let rc = unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleMessage(conn.ctx) };
151         if rc < 0 {
152             Err(TipcError::from_uapi(rc.into()))
153         } else {
154             Ok(MessageResult::MaintainConnection)
155         }
156     }
157 
on_disconnect(&self, conn: &Self::Connection)158     fn on_disconnect(&self, conn: &Self::Connection) {
159         unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleDisconnect(conn.ctx) };
160     }
161 }
162