1 /* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 use crate::{ 17 ipc_binding, IRemoteStub, IRemoteBroker, IpcStatusCode, 18 RemoteObj, BorrowedMsgParcel, FileDesc, String16, 19 }; 20 use crate::ipc_binding::{CRemoteObject, CParcel}; 21 use std::ffi::{c_void, CString, c_char}; 22 use std::ops::Deref; 23 use hilog_rust::{ 24 info, error, hilog, HiLogLabel, 25 LogType 26 }; 27 28 const LOG_LABEL: HiLogLabel = HiLogLabel { 29 log_type: LogType::LogCore, 30 domain: 0xD0057CA, 31 tag: "RustRemoteStub" 32 }; 33 34 /// RemoteStub packed the native CRemoteObject and the rust stub object T 35 /// which must implement IRemoteStub trait. 36 /// Safety Invariant: The native pointer must be a valid pointer and cannot be null. 37 /// The native is guaranteed by the c interface 38 /// FFI Safety : Ensure stable memory layout C-ABI compatibility 39 #[repr(C)] 40 pub struct RemoteStub<T: IRemoteStub> { 41 native: *mut CRemoteObject, 42 rust: *mut T, 43 } 44 45 impl<T: IRemoteStub> RemoteStub<T> { 46 /// Create a RemoteStub object new(rust: T) -> Option<Self>47 pub fn new(rust: T) -> Option<Self> { 48 let rust = Box::into_raw(Box::new(rust)); 49 let descripor = CString::new(T::get_descriptor()).expect("descripor must be valid!"); 50 // SAFETY: The incoming parameters are FFI safety 51 // Descripor is converted to a string type compatible with the c interface through CString. 52 // on_remote_request and on_destroy callback function has been checked for security, 53 // and the parameter type is FFI safety 54 let native = unsafe { 55 // set rust object pointer to native, so we can figure out who deal 56 // the request during on_remote_request(). 57 ipc_binding::CreateRemoteStub(descripor.as_ptr(), Self::on_remote_request, 58 Self::on_destroy, rust as *mut c_void, Self::on_dump) 59 }; 60 61 if native.is_null() { 62 None 63 } else { 64 Some( RemoteStub { native, rust } ) 65 } 66 } 67 } 68 69 impl<T: IRemoteStub> IRemoteBroker for RemoteStub<T> { as_object(&self) -> Option<RemoteObj>70 fn as_object(&self) -> Option<RemoteObj> { 71 // SAFETY: 72 // Validate and ensure the validity of all pointers before using them. 73 // Be mindful of potential memory leaks and manage reference counts carefully. 74 unsafe { 75 // add remote object reference count 76 ipc_binding::RemoteObjectIncStrongRef(self.native); 77 // construct a new RemoteObject from a native pointer 78 RemoteObj::from_raw(self.native) 79 } 80 } 81 } 82 83 unsafe impl<T: IRemoteStub> Send for RemoteStub<T> {} 84 /// # Safety 85 /// 86 /// RemoteSub thread safety. Multi-thread access and sharing have been considered inside the C-side code 87 unsafe impl<T: IRemoteStub> Sync for RemoteStub<T> {} 88 89 impl<T: IRemoteStub> Deref for RemoteStub<T> { 90 type Target = T; 91 deref(&self) -> &Self::Target92 fn deref(&self) -> &Self::Target { 93 // SAFETY: 94 // Rust `Box::into_raw` poiter, so is valid 95 unsafe { 96 &*self.rust 97 } 98 } 99 } 100 101 impl<T: IRemoteStub> Drop for RemoteStub<T> { drop(&mut self)102 fn drop(&mut self) { 103 // SAFETY: 104 // Because self is valid, its internal native pointer is valid. 105 unsafe { 106 ipc_binding::RemoteObjectDecStrongRef(self.native); 107 } 108 } 109 } 110 111 /// C call Rust 112 impl<T: IRemoteStub> RemoteStub<T> { 113 /// # Safety 114 /// 115 /// The parameters passed in should ensure FFI safety 116 /// user_data pointer, data pointer and reply pointer on the c side must be guaranteed not to be null on_remote_request(user_data: *mut c_void, code: u32, data: *const CParcel, reply: *mut CParcel) -> i32117 unsafe extern "C" fn on_remote_request(user_data: *mut c_void, code: u32, 118 data: *const CParcel, reply: *mut CParcel) -> i32 { 119 let res = { 120 // BorrowedMsgParcel calls the correlation function from_raw must return as Some, 121 // direct deconstruction will not crash. 122 let mut reply = BorrowedMsgParcel::from_raw(reply).expect("MsgParcel should success"); 123 let data = match BorrowedMsgParcel::from_raw(data as *mut CParcel) { 124 Some(data) => data, 125 _ => { 126 error!(LOG_LABEL, "Failed to create BorrowedMsgParcel from raw pointer"); 127 return IpcStatusCode::Failed as i32; 128 } 129 }; 130 let rust_object: &T = &*(user_data as *mut T); 131 rust_object.on_remote_request(code, &data, &mut reply) 132 }; 133 res 134 } 135 /// # Safety 136 /// 137 /// The parameters passed in should ensure FFI safety 138 /// user_data pointer, data pointer and reply pointer on the c side must be guaranteed not to be null on_dump(user_data: *mut c_void, data: *const CParcel) -> i32139 unsafe extern "C" fn on_dump(user_data: *mut c_void, data: *const CParcel) -> i32 { 140 let res = { 141 let rust_object: &T = &*(user_data as *mut T); 142 // BorrowedMsgParcel calls the correlation functio from_raw must return as Some, 143 // direct deconstruction will not crash. 144 let data = match BorrowedMsgParcel::from_raw(data as *mut CParcel) { 145 Some(data) => data, 146 _ => { 147 error!(LOG_LABEL, "Failed to create BorrowedMsgParcel from raw pointer"); 148 return IpcStatusCode::Failed as i32; 149 } 150 }; 151 let file: FileDesc = match data.read::<FileDesc>() { 152 Ok(file) => file, 153 _ => { 154 error!(LOG_LABEL, "read FileDesc failed"); 155 return IpcStatusCode::Failed as i32; 156 } 157 }; 158 let mut args: Vec<String16> = match data.read::<Vec<String16>>() { 159 Ok(args) => args, 160 _ => { 161 error!(LOG_LABEL, "read String16 array failed"); 162 return IpcStatusCode::Failed as i32; 163 } 164 }; 165 rust_object.on_dump(&file, &mut args) 166 }; 167 res 168 } 169 /// # Safety 170 /// 171 /// The parameters passed in should ensure FFI safety 172 /// user_data pointer, data pointer and reply pointer on the c side must be guaranteed not to be null on_destroy(user_data: *mut c_void)173 unsafe extern "C" fn on_destroy(user_data: *mut c_void) { 174 info!(LOG_LABEL, "RemoteStub<T> on_destroy in Rust"); 175 // T will be freed by Box after this function end. 176 drop(Box::from_raw(user_data as *mut T)); 177 } 178 }