1/* 2 * Copyright (c) 2021 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#include "ashmem.h" 17 18#include <cerrno> 19#include <cstdio> 20#include <string> 21#include <fcntl.h> 22#include <linux/ashmem.h> 23#include <pthread.h> 24#include <sys/ioctl.h> 25#include <sys/mman.h> 26#include <sys/stat.h> 27#include <sys/syscall.h> 28#include <sys/sysmacros.h> 29#include <sys/types.h> 30#include <unistd.h> 31#include <dlfcn.h> 32#include "securec.h" 33#include "utils_log.h" 34 35namespace OHOS { 36static pthread_mutex_t g_ashmemLock = PTHREAD_MUTEX_INITIALIZER; 37 38#ifdef UTILS_CXX_RUST 39std::shared_ptr<Ashmem> CreateAshmemStd(const char *name, int32_t size) 40{ 41 if ((name == nullptr) || (size <= 0)) { 42 UTILS_LOGE("%{public}s: Parameter is invalid, size= %{public}d", __func__, size); 43 return std::shared_ptr<Ashmem>{}; 44 } 45 46 int fd = AshmemCreate(name, size); 47 if (fd < 0) { 48 UTILS_LOGE("%{public}s: Failed to exec AshmemCreate, fd= %{public}d", __func__, size); 49 return std::shared_ptr<Ashmem>{}; 50 } 51 52 return std::make_shared<Ashmem>(fd, size); 53} 54 55const c_void* AsVoidPtr(const char* inPtr) 56{ 57 return static_cast<const c_void*>(inPtr); 58} 59 60const char* AsCharPtr(const c_void* inPtr) 61{ 62 return static_cast<const char*>(inPtr); 63} 64#endif 65 66static int AshmemOpenLocked() 67{ 68 int fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDWR | O_CLOEXEC)); 69 if (fd < 0) { 70 UTILS_LOGE("%{public}s: fd is invalid, fd = %{public}d, errno = %{public}d", __func__, fd, errno); 71 return fd; 72 } 73 74 struct stat st; 75 int ret = TEMP_FAILURE_RETRY(fstat(fd, &st)); 76 if (ret < 0) { 77 UTILS_LOGE("%{public}s: Failed to exec fstat, ret = %{public}d, errno = %{public}d", __func__, ret, errno); 78 close(fd); 79 return ret; 80 } 81 82 if (!S_ISCHR(st.st_mode) || !st.st_rdev) { 83 UTILS_LOGE("%{public}s: stat status is invalid, st_mode = %{public}u", __func__, st.st_mode); 84 close(fd); 85 return -1; 86 } 87 return fd; 88} 89 90static int AshmemOpen() 91{ 92 pthread_mutex_lock(&g_ashmemLock); 93 int fd = AshmemOpenLocked(); 94 pthread_mutex_unlock(&g_ashmemLock); 95 return fd; 96} 97 98/* 99 * AshmemCreate - create a new ashmem region and returns the file descriptor 100 * fd < 0 means failed 101 * 102 */ 103int AshmemCreate(const char *name, size_t size) 104{ 105 int ret; 106 int fd = AshmemOpen(); 107 if (fd < 0) { 108 UTILS_LOGE("%{public}s: Failed to exec AshmemOpen fd = %{public}d", __func__, fd); 109 return fd; 110 } 111 112 if (name != nullptr) { 113 char buf[ASHMEM_NAME_LEN] = {0}; 114 ret = strcpy_s(buf, sizeof(buf), name); 115 if (ret != EOK) { 116 UTILS_LOGE("%{public}s: Failed to exec strcpy_s, name= %{public}s, ret= %{public}d", __func__, name, ret); 117 close(fd); 118 return -1; 119 } 120 ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_NAME, buf)); 121 if (ret < 0) { 122 UTILS_LOGE("%{public}s: Failed to set name, name= %{public}s, ret= %{public}d, errno = %{public}d", 123 __func__, name, ret, errno); 124 close(fd); 125 return ret; 126 } 127 } 128 129 ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_SIZE, size)); 130 if (ret < 0) { 131 UTILS_LOGE("%{public}s: Failed to set size, size= %{public}zu, errno = %{public}d", __func__, size, errno); 132 close(fd); 133 return ret; 134 } 135 return fd; 136} 137 138int AshmemSetProt(int fd, int prot) 139{ 140 return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot)); 141} 142 143int AshmemGetSize(int fd) 144{ 145 return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)); 146} 147 148Ashmem::Ashmem(int fd, int32_t size) : memoryFd_(fd), memorySize_(size), flag_(0), startAddr_(nullptr) 149{ 150} 151 152Ashmem::~Ashmem() 153{ 154 UnmapAshmem(); 155 CloseAshmem(); 156} 157 158sptr<Ashmem> Ashmem::CreateAshmem(const char *name, int32_t size) 159{ 160 if ((name == nullptr) || (size <= 0)) { 161 UTILS_LOGE("%{public}s: Parameter is invalid, size= %{public}d", __func__, size); 162 return nullptr; 163 } 164 165 int fd = AshmemCreate(name, size); 166 if (fd < 0) { 167 UTILS_LOGE("%{public}s: Failed to exec AshmemCreate, fd= %{public}d", __func__, size); 168 return nullptr; 169 } 170 171 return new Ashmem(fd, size); 172} 173 174bool Ashmem::SetProtection(int protectionType) const 175{ 176 int result = AshmemSetProt(memoryFd_, protectionType); 177 return result >= 0; 178} 179 180int Ashmem::GetProtection() const 181{ 182 return TEMP_FAILURE_RETRY(ioctl(memoryFd_, ASHMEM_GET_PROT_MASK)); 183} 184 185int32_t Ashmem::GetAshmemSize() const 186{ 187 return AshmemGetSize(memoryFd_); 188} 189 190#ifdef UTILS_CXX_RUST 191void Ashmem::CloseAshmem() const 192#else 193void Ashmem::CloseAshmem() 194#endif 195{ 196 if (memoryFd_ > 0) { 197 ::close(memoryFd_); 198 memoryFd_ = -1; 199 } 200 memorySize_ = 0; 201 flag_ = 0; 202 startAddr_ = nullptr; 203} 204 205#ifdef UTILS_CXX_RUST 206bool Ashmem::MapAshmem(int mapType) const 207#else 208bool Ashmem::MapAshmem(int mapType) 209#endif 210{ 211 void *startAddr = ::mmap(nullptr, memorySize_, mapType, MAP_SHARED, memoryFd_, 0); 212 if (startAddr == MAP_FAILED) { 213 UTILS_LOGE("Failed to exec mmap, errno = %{public}d", errno); 214 return false; 215 } 216 217 startAddr_ = startAddr; 218 flag_ = mapType; 219 220 return true; 221} 222 223#ifdef UTILS_CXX_RUST 224bool Ashmem::MapReadAndWriteAshmem() const 225#else 226bool Ashmem::MapReadAndWriteAshmem() 227#endif 228{ 229 return MapAshmem(PROT_READ | PROT_WRITE); 230} 231 232#ifdef UTILS_CXX_RUST 233bool Ashmem::MapReadOnlyAshmem() const 234#else 235bool Ashmem::MapReadOnlyAshmem() 236#endif 237{ 238 return MapAshmem(PROT_READ); 239} 240 241#ifdef UTILS_CXX_RUST 242void Ashmem::UnmapAshmem() const 243#else 244void Ashmem::UnmapAshmem() 245#endif 246{ 247 if (startAddr_ != nullptr) { 248 ::munmap(startAddr_, memorySize_); 249 startAddr_ = nullptr; 250 } 251 flag_ = 0; 252} 253 254#ifdef UTILS_CXX_RUST 255bool Ashmem::WriteToAshmem(const void *data, int32_t size, int32_t offset) const 256#else 257bool Ashmem::WriteToAshmem(const void *data, int32_t size, int32_t offset) 258#endif 259{ 260 if (data == nullptr) { 261 return false; 262 } 263 264 if (!CheckValid(size, offset, PROT_WRITE)) { 265 UTILS_LOGE("%{public}s: invalid input or not map", __func__); 266 return false; 267 } 268 269 auto tmpData = reinterpret_cast<char *>(startAddr_); 270 int ret = memcpy_s(tmpData + offset, memorySize_ - offset, reinterpret_cast<const char *>(data), size); 271 if (ret != EOK) { 272 UTILS_LOGE("%{public}s: Failed to memcpy, ret = %{public}d", __func__, ret); 273 return false; 274 } 275 276 return true; 277} 278 279#ifdef UTILS_CXX_RUST 280const void *Ashmem::ReadFromAshmem(int32_t size, int32_t offset) const 281#else 282const void *Ashmem::ReadFromAshmem(int32_t size, int32_t offset) 283#endif 284{ 285 if (!CheckValid(size, offset, PROT_READ)) { 286 UTILS_LOGE("%{public}s: invalid input or not map", __func__); 287 return nullptr; 288 } 289 290 return reinterpret_cast<const char *>(startAddr_) + offset; 291} 292 293bool Ashmem::CheckValid(int32_t size, int32_t offset, int cmd) const 294{ 295 if (startAddr_ == nullptr) { 296 return false; 297 } 298 if ((size < 0) || (size > memorySize_) || (offset < 0) || (offset > memorySize_)) { 299 UTILS_LOGE("%{public}s: , invalid parameter, size = %{public}d, memorySize_ = %{public}d, offset = %{public}d", 300 __func__, size, memorySize_, offset); 301 return false; 302 } 303 if (offset + size > memorySize_) { 304 UTILS_LOGE("%{public}s: , invalid parameter, size = %{public}d, memorySize_ = %{public}d, offset = %{public}d", 305 __func__, size, memorySize_, offset); 306 return false; 307 } 308 if (!(static_cast<uint32_t>(GetProtection()) & static_cast<uint32_t>(cmd)) || 309 !(static_cast<uint32_t>(flag_) & static_cast<uint32_t>(cmd))) { 310 return false; 311 } 312 313 return true; 314} 315} 316