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