1 /* 2 * Copyright (C) 2023 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, RawData, IpcResult, IpcStatusCode, BorrowedMsgParcel, status_result, 18 AsRawPtr 19 }; 20 use crate::ipc_binding::CAshmem; 21 use std::ffi::{CString, c_char}; 22 use crate::parcel::parcelable::{Serialize, Deserialize}; 23 use hilog_rust::{error, hilog, HiLogLabel, LogType}; 24 25 const LOG_LABEL: HiLogLabel = HiLogLabel { 26 log_type: LogType::LogCore, 27 domain: 0xd001510, 28 tag: "RustAshmem" 29 }; 30 31 /// Ashmem packed the native CAshmem 32 #[repr(C)] 33 pub struct Ashmem(*mut CAshmem); 34 35 impl Ashmem { 36 /// Create a Ashmem object new(name: &str, size: i32) -> Option<Self>37 pub fn new(name: &str, size: i32) -> Option<Self> { 38 if size <= 0 { 39 return None; 40 } 41 let c_name = CString::new(name).expect("ashmem name is invalid!"); 42 // SAFETY: 43 let native = unsafe { 44 ipc_binding::CreateCAshmem(c_name.as_ptr(), size) 45 }; 46 if native.is_null() { 47 None 48 } else { 49 Some(Self(native)) 50 } 51 } 52 53 /// Extract a raw `CAshmem` pointer from this wrapper. 54 /// # Safety as_inner(&self) -> *mut CAshmem55 pub unsafe fn as_inner(&self) -> *mut CAshmem { 56 self.0 57 } 58 59 /// Create an `Ashmem` wrapper object from a raw `CAshmem` pointer. 60 /// # Safety from_raw(cashmem: *mut CAshmem) -> Option<Self>61 pub unsafe fn from_raw(cashmem: *mut CAshmem) -> Option<Self> { 62 if cashmem.is_null() { 63 None 64 } else { 65 Some(Self(cashmem)) 66 } 67 } 68 } 69 70 /// Memory protection for mmap() PROT_NONE 71 pub const PROT_NONE: i32 = 0; 72 /// Memory protection for mmap() PROT_READ 73 pub const PROT_READ: i32 = 1; 74 /// Memory protection for mmap() PROT_WRITE 75 pub const PROT_WRITE: i32 = 2; 76 /// Memory protection for mmap() PROT_EXEC 77 pub const PROT_EXEC: i32 = 4; 78 79 impl Ashmem { 80 /// Close Ashmem, the ashmem becomes invalid after closing. close(&self)81 pub fn close(&self) { 82 // SAFETY: 83 // Rust Ashmem always hold a valid native CAshmem. 84 unsafe { 85 ipc_binding::CloseCAshmem(self.as_inner()); 86 } 87 } 88 89 /// Set ashmem map type with above PROT_XXX by mmap() map(&self, map_type: i32) -> bool90 pub fn map(&self, map_type: i32) -> bool { 91 // SAFETY: 92 // Rust Ashmem always hold a valid native CAshmem. 93 unsafe { 94 ipc_binding::MapCAshmem(self.as_inner(), map_type) 95 } 96 } 97 98 /// Set ashmem map type with `PROT_READ | PROT_WRITE` by mmap() map_read_write(&self) -> bool99 pub fn map_read_write(&self) -> bool { 100 // SAFETY: 101 // Rust Ashmem always hold a valid native CAshmem. 102 unsafe { 103 ipc_binding::MapReadAndWriteCAshmem(self.as_inner()) 104 } 105 } 106 107 /// Set ashmem map type with `PROT_READ` by mmap() map_readonly(&self) -> bool108 pub fn map_readonly(&self) -> bool { 109 // SAFETY: 110 // Rust Ashmem always hold a valid native CAshmem. 111 unsafe { 112 ipc_binding::MapReadOnlyCAshmem(self.as_inner()) 113 } 114 } 115 116 /// unmap ashmem unmap(&self)117 pub fn unmap(&self) { 118 // SAFETY: 119 // Rust Ashmem always hold a valid native CAshmem. 120 unsafe { 121 ipc_binding::UnmapCAshmem(self.as_inner()); 122 } 123 } 124 125 /// Set ashmem map type with above PROT_XXX by ioctl() set_protection(&self, protection: i32) -> bool126 pub fn set_protection(&self, protection: i32) -> bool { 127 // SAFETY: 128 // Rust Ashmem always hold a valid native CAshmem. 129 unsafe { 130 ipc_binding::SetCAshmemProtection(self.as_inner(), protection) 131 } 132 } 133 134 /// Get ashmem map type get_protection(&self) -> i32135 pub fn get_protection(&self) -> i32 { 136 // SAFETY: 137 // Rust Ashmem always hold a valid native CAshmem. 138 unsafe { 139 ipc_binding::GetCAshmemProtection(self.as_inner()) 140 } 141 } 142 143 /// Get ashmem size get_size(&self) -> i32144 pub fn get_size(&self) -> i32 { 145 // SAFETY: 146 // Rust Ashmem always hold a valid native CAshmem. 147 unsafe { 148 ipc_binding::GetCAshmemSize(self.as_inner()) 149 } 150 } 151 152 /// Write data to ashmem write(&self, data: &[u8], offset: i32) -> bool153 pub fn write(&self, data: &[u8], offset: i32) -> bool { 154 let len = data.len() as i32; 155 if offset < 0 || offset >= len { 156 error!(LOG_LABEL, "invalid offset: {}, len: {}", offset, len); 157 return false; 158 } 159 // SAFETY: 160 // Rust Ashmem always hold a valid native CAshmem. 161 unsafe { 162 ipc_binding::WriteToCAshmem(self.as_inner(), 163 data.as_ptr(), len, offset) 164 } 165 } 166 167 /// Read ashmem read(&self, size: i32, offset: i32) -> IpcResult<RawData>168 pub fn read(&self, size: i32, offset: i32) -> IpcResult<RawData> { 169 // SAFETY: 170 // Rust Ashmem always hold a valid native CAshmem. 171 let raw_ptr = unsafe { 172 ipc_binding::ReadFromCAshmem(self.as_inner(), size, offset) 173 }; 174 if raw_ptr.is_null() { 175 Err(IpcStatusCode::Failed) 176 } else { 177 Ok(RawData::new(raw_ptr, size as u32)) 178 } 179 } 180 181 /// Get ashmem inner file descriptor get_fd(&self) -> i32182 pub fn get_fd(&self) -> i32 { 183 // SAFETY: 184 // Rust Ashmem always hold a valid native CAshmem. 185 unsafe { 186 ipc_binding::GetCAshmemFd(self.as_inner()) 187 } 188 } 189 } 190 191 impl Clone for Ashmem { clone(&self) -> Self192 fn clone(&self) -> Self { 193 // SAFETY: 194 unsafe { 195 ipc_binding::CAshmemIncStrongRef(self.as_inner()); 196 } 197 // SAFETY: no `None` here, cause `self` is valid 198 Self(self.0) 199 } 200 } 201 202 impl Drop for Ashmem { drop(&mut self)203 fn drop(&mut self) { 204 // SAFETY: 205 unsafe { 206 ipc_binding::CAshmemDecStrongRef(self.as_inner()); 207 } 208 } 209 } 210 211 /// Write a ashmem 212 impl Serialize for Ashmem { serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()>213 fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { 214 // SAFETY: 215 let ret = unsafe { 216 ipc_binding::CParcelWriteAshmem(parcel.as_mut_raw(), self.as_inner()) 217 }; 218 status_result::<()>(ret as i32, ()) 219 } 220 } 221 222 /// read a ashmem 223 impl Deserialize for Ashmem { deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self>224 fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self> { 225 // SAFETY: 226 let ptr = unsafe { 227 ipc_binding::CParcelReadAshmem(parcel.as_raw()) 228 }; 229 if ptr.is_null() { 230 Err(IpcStatusCode::Failed) 231 } else { 232 // SAFETY: 233 unsafe { 234 let ashmem = Ashmem::from_raw(ptr).unwrap(); 235 Ok(ashmem) 236 } 237 } 238 } 239 }