• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }