13f4cbf05Sopenharmony_ci/* 23f4cbf05Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 33f4cbf05Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43f4cbf05Sopenharmony_ci * you may not use this file except in compliance with the License. 53f4cbf05Sopenharmony_ci * You may obtain a copy of the License at 63f4cbf05Sopenharmony_ci * 73f4cbf05Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83f4cbf05Sopenharmony_ci * 93f4cbf05Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103f4cbf05Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113f4cbf05Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123f4cbf05Sopenharmony_ci * See the License for the specific language governing permissions and 133f4cbf05Sopenharmony_ci * limitations under the License. 143f4cbf05Sopenharmony_ci */ 153f4cbf05Sopenharmony_ci 163f4cbf05Sopenharmony_ci#include "ashmem.h" 173f4cbf05Sopenharmony_ci 183f4cbf05Sopenharmony_ci#include <cerrno> 193f4cbf05Sopenharmony_ci#include <cstdio> 203f4cbf05Sopenharmony_ci#include <string> 213f4cbf05Sopenharmony_ci#include <fcntl.h> 223f4cbf05Sopenharmony_ci#include <linux/ashmem.h> 233f4cbf05Sopenharmony_ci#include <pthread.h> 243f4cbf05Sopenharmony_ci#include <sys/ioctl.h> 253f4cbf05Sopenharmony_ci#include <sys/mman.h> 263f4cbf05Sopenharmony_ci#include <sys/stat.h> 273f4cbf05Sopenharmony_ci#include <sys/syscall.h> 283f4cbf05Sopenharmony_ci#include <sys/sysmacros.h> 293f4cbf05Sopenharmony_ci#include <sys/types.h> 303f4cbf05Sopenharmony_ci#include <unistd.h> 313f4cbf05Sopenharmony_ci#include <dlfcn.h> 323f4cbf05Sopenharmony_ci#include "securec.h" 333f4cbf05Sopenharmony_ci#include "utils_log.h" 343f4cbf05Sopenharmony_ci 353f4cbf05Sopenharmony_cinamespace OHOS { 363f4cbf05Sopenharmony_cistatic pthread_mutex_t g_ashmemLock = PTHREAD_MUTEX_INITIALIZER; 373f4cbf05Sopenharmony_ci 383f4cbf05Sopenharmony_ci#ifdef UTILS_CXX_RUST 393f4cbf05Sopenharmony_cistd::shared_ptr<Ashmem> CreateAshmemStd(const char *name, int32_t size) 403f4cbf05Sopenharmony_ci{ 413f4cbf05Sopenharmony_ci if ((name == nullptr) || (size <= 0)) { 423f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Parameter is invalid, size= %{public}d", __func__, size); 433f4cbf05Sopenharmony_ci return std::shared_ptr<Ashmem>{}; 443f4cbf05Sopenharmony_ci } 453f4cbf05Sopenharmony_ci 463f4cbf05Sopenharmony_ci int fd = AshmemCreate(name, size); 473f4cbf05Sopenharmony_ci if (fd < 0) { 483f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed to exec AshmemCreate, fd= %{public}d", __func__, size); 493f4cbf05Sopenharmony_ci return std::shared_ptr<Ashmem>{}; 503f4cbf05Sopenharmony_ci } 513f4cbf05Sopenharmony_ci 523f4cbf05Sopenharmony_ci return std::make_shared<Ashmem>(fd, size); 533f4cbf05Sopenharmony_ci} 543f4cbf05Sopenharmony_ci 553f4cbf05Sopenharmony_ciconst c_void* AsVoidPtr(const char* inPtr) 563f4cbf05Sopenharmony_ci{ 573f4cbf05Sopenharmony_ci return static_cast<const c_void*>(inPtr); 583f4cbf05Sopenharmony_ci} 593f4cbf05Sopenharmony_ci 603f4cbf05Sopenharmony_ciconst char* AsCharPtr(const c_void* inPtr) 613f4cbf05Sopenharmony_ci{ 623f4cbf05Sopenharmony_ci return static_cast<const char*>(inPtr); 633f4cbf05Sopenharmony_ci} 643f4cbf05Sopenharmony_ci#endif 653f4cbf05Sopenharmony_ci 663f4cbf05Sopenharmony_cistatic int AshmemOpenLocked() 673f4cbf05Sopenharmony_ci{ 683f4cbf05Sopenharmony_ci int fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDWR | O_CLOEXEC)); 693f4cbf05Sopenharmony_ci if (fd < 0) { 703f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: fd is invalid, fd = %{public}d, errno = %{public}d", __func__, fd, errno); 713f4cbf05Sopenharmony_ci return fd; 723f4cbf05Sopenharmony_ci } 733f4cbf05Sopenharmony_ci 743f4cbf05Sopenharmony_ci struct stat st; 753f4cbf05Sopenharmony_ci int ret = TEMP_FAILURE_RETRY(fstat(fd, &st)); 763f4cbf05Sopenharmony_ci if (ret < 0) { 773f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed to exec fstat, ret = %{public}d, errno = %{public}d", __func__, ret, errno); 783f4cbf05Sopenharmony_ci close(fd); 793f4cbf05Sopenharmony_ci return ret; 803f4cbf05Sopenharmony_ci } 813f4cbf05Sopenharmony_ci 823f4cbf05Sopenharmony_ci if (!S_ISCHR(st.st_mode) || !st.st_rdev) { 833f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: stat status is invalid, st_mode = %{public}u", __func__, st.st_mode); 843f4cbf05Sopenharmony_ci close(fd); 853f4cbf05Sopenharmony_ci return -1; 863f4cbf05Sopenharmony_ci } 873f4cbf05Sopenharmony_ci return fd; 883f4cbf05Sopenharmony_ci} 893f4cbf05Sopenharmony_ci 903f4cbf05Sopenharmony_cistatic int AshmemOpen() 913f4cbf05Sopenharmony_ci{ 923f4cbf05Sopenharmony_ci pthread_mutex_lock(&g_ashmemLock); 933f4cbf05Sopenharmony_ci int fd = AshmemOpenLocked(); 943f4cbf05Sopenharmony_ci pthread_mutex_unlock(&g_ashmemLock); 953f4cbf05Sopenharmony_ci return fd; 963f4cbf05Sopenharmony_ci} 973f4cbf05Sopenharmony_ci 983f4cbf05Sopenharmony_ci/* 993f4cbf05Sopenharmony_ci * AshmemCreate - create a new ashmem region and returns the file descriptor 1003f4cbf05Sopenharmony_ci * fd < 0 means failed 1013f4cbf05Sopenharmony_ci * 1023f4cbf05Sopenharmony_ci */ 1033f4cbf05Sopenharmony_ciint AshmemCreate(const char *name, size_t size) 1043f4cbf05Sopenharmony_ci{ 1053f4cbf05Sopenharmony_ci int ret; 1063f4cbf05Sopenharmony_ci int fd = AshmemOpen(); 1073f4cbf05Sopenharmony_ci if (fd < 0) { 1083f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed to exec AshmemOpen fd = %{public}d", __func__, fd); 1093f4cbf05Sopenharmony_ci return fd; 1103f4cbf05Sopenharmony_ci } 1113f4cbf05Sopenharmony_ci 1123f4cbf05Sopenharmony_ci if (name != nullptr) { 1133f4cbf05Sopenharmony_ci char buf[ASHMEM_NAME_LEN] = {0}; 1143f4cbf05Sopenharmony_ci ret = strcpy_s(buf, sizeof(buf), name); 1153f4cbf05Sopenharmony_ci if (ret != EOK) { 1163f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed to exec strcpy_s, name= %{public}s, ret= %{public}d", __func__, name, ret); 1173f4cbf05Sopenharmony_ci close(fd); 1183f4cbf05Sopenharmony_ci return -1; 1193f4cbf05Sopenharmony_ci } 1203f4cbf05Sopenharmony_ci ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_NAME, buf)); 1213f4cbf05Sopenharmony_ci if (ret < 0) { 1223f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed to set name, name= %{public}s, ret= %{public}d, errno = %{public}d", 1233f4cbf05Sopenharmony_ci __func__, name, ret, errno); 1243f4cbf05Sopenharmony_ci close(fd); 1253f4cbf05Sopenharmony_ci return ret; 1263f4cbf05Sopenharmony_ci } 1273f4cbf05Sopenharmony_ci } 1283f4cbf05Sopenharmony_ci 1293f4cbf05Sopenharmony_ci ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_SIZE, size)); 1303f4cbf05Sopenharmony_ci if (ret < 0) { 1313f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed to set size, size= %{public}zu, errno = %{public}d", __func__, size, errno); 1323f4cbf05Sopenharmony_ci close(fd); 1333f4cbf05Sopenharmony_ci return ret; 1343f4cbf05Sopenharmony_ci } 1353f4cbf05Sopenharmony_ci return fd; 1363f4cbf05Sopenharmony_ci} 1373f4cbf05Sopenharmony_ci 1383f4cbf05Sopenharmony_ciint AshmemSetProt(int fd, int prot) 1393f4cbf05Sopenharmony_ci{ 1403f4cbf05Sopenharmony_ci return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot)); 1413f4cbf05Sopenharmony_ci} 1423f4cbf05Sopenharmony_ci 1433f4cbf05Sopenharmony_ciint AshmemGetSize(int fd) 1443f4cbf05Sopenharmony_ci{ 1453f4cbf05Sopenharmony_ci return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)); 1463f4cbf05Sopenharmony_ci} 1473f4cbf05Sopenharmony_ci 1483f4cbf05Sopenharmony_ciAshmem::Ashmem(int fd, int32_t size) : memoryFd_(fd), memorySize_(size), flag_(0), startAddr_(nullptr) 1493f4cbf05Sopenharmony_ci{ 1503f4cbf05Sopenharmony_ci} 1513f4cbf05Sopenharmony_ci 1523f4cbf05Sopenharmony_ciAshmem::~Ashmem() 1533f4cbf05Sopenharmony_ci{ 1543f4cbf05Sopenharmony_ci UnmapAshmem(); 1553f4cbf05Sopenharmony_ci CloseAshmem(); 1563f4cbf05Sopenharmony_ci} 1573f4cbf05Sopenharmony_ci 1583f4cbf05Sopenharmony_cisptr<Ashmem> Ashmem::CreateAshmem(const char *name, int32_t size) 1593f4cbf05Sopenharmony_ci{ 1603f4cbf05Sopenharmony_ci if ((name == nullptr) || (size <= 0)) { 1613f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Parameter is invalid, size= %{public}d", __func__, size); 1623f4cbf05Sopenharmony_ci return nullptr; 1633f4cbf05Sopenharmony_ci } 1643f4cbf05Sopenharmony_ci 1653f4cbf05Sopenharmony_ci int fd = AshmemCreate(name, size); 1663f4cbf05Sopenharmony_ci if (fd < 0) { 1673f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed to exec AshmemCreate, fd= %{public}d", __func__, size); 1683f4cbf05Sopenharmony_ci return nullptr; 1693f4cbf05Sopenharmony_ci } 1703f4cbf05Sopenharmony_ci 1713f4cbf05Sopenharmony_ci return new Ashmem(fd, size); 1723f4cbf05Sopenharmony_ci} 1733f4cbf05Sopenharmony_ci 1743f4cbf05Sopenharmony_cibool Ashmem::SetProtection(int protectionType) const 1753f4cbf05Sopenharmony_ci{ 1763f4cbf05Sopenharmony_ci int result = AshmemSetProt(memoryFd_, protectionType); 1773f4cbf05Sopenharmony_ci return result >= 0; 1783f4cbf05Sopenharmony_ci} 1793f4cbf05Sopenharmony_ci 1803f4cbf05Sopenharmony_ciint Ashmem::GetProtection() const 1813f4cbf05Sopenharmony_ci{ 1823f4cbf05Sopenharmony_ci return TEMP_FAILURE_RETRY(ioctl(memoryFd_, ASHMEM_GET_PROT_MASK)); 1833f4cbf05Sopenharmony_ci} 1843f4cbf05Sopenharmony_ci 1853f4cbf05Sopenharmony_ciint32_t Ashmem::GetAshmemSize() const 1863f4cbf05Sopenharmony_ci{ 1873f4cbf05Sopenharmony_ci return AshmemGetSize(memoryFd_); 1883f4cbf05Sopenharmony_ci} 1893f4cbf05Sopenharmony_ci 1903f4cbf05Sopenharmony_ci#ifdef UTILS_CXX_RUST 1913f4cbf05Sopenharmony_civoid Ashmem::CloseAshmem() const 1923f4cbf05Sopenharmony_ci#else 1933f4cbf05Sopenharmony_civoid Ashmem::CloseAshmem() 1943f4cbf05Sopenharmony_ci#endif 1953f4cbf05Sopenharmony_ci{ 1963f4cbf05Sopenharmony_ci if (memoryFd_ > 0) { 1973f4cbf05Sopenharmony_ci ::close(memoryFd_); 1983f4cbf05Sopenharmony_ci memoryFd_ = -1; 1993f4cbf05Sopenharmony_ci } 2003f4cbf05Sopenharmony_ci memorySize_ = 0; 2013f4cbf05Sopenharmony_ci flag_ = 0; 2023f4cbf05Sopenharmony_ci startAddr_ = nullptr; 2033f4cbf05Sopenharmony_ci} 2043f4cbf05Sopenharmony_ci 2053f4cbf05Sopenharmony_ci#ifdef UTILS_CXX_RUST 2063f4cbf05Sopenharmony_cibool Ashmem::MapAshmem(int mapType) const 2073f4cbf05Sopenharmony_ci#else 2083f4cbf05Sopenharmony_cibool Ashmem::MapAshmem(int mapType) 2093f4cbf05Sopenharmony_ci#endif 2103f4cbf05Sopenharmony_ci{ 2113f4cbf05Sopenharmony_ci void *startAddr = ::mmap(nullptr, memorySize_, mapType, MAP_SHARED, memoryFd_, 0); 2123f4cbf05Sopenharmony_ci if (startAddr == MAP_FAILED) { 2133f4cbf05Sopenharmony_ci UTILS_LOGE("Failed to exec mmap, errno = %{public}d", errno); 2143f4cbf05Sopenharmony_ci return false; 2153f4cbf05Sopenharmony_ci } 2163f4cbf05Sopenharmony_ci 2173f4cbf05Sopenharmony_ci startAddr_ = startAddr; 2183f4cbf05Sopenharmony_ci flag_ = mapType; 2193f4cbf05Sopenharmony_ci 2203f4cbf05Sopenharmony_ci return true; 2213f4cbf05Sopenharmony_ci} 2223f4cbf05Sopenharmony_ci 2233f4cbf05Sopenharmony_ci#ifdef UTILS_CXX_RUST 2243f4cbf05Sopenharmony_cibool Ashmem::MapReadAndWriteAshmem() const 2253f4cbf05Sopenharmony_ci#else 2263f4cbf05Sopenharmony_cibool Ashmem::MapReadAndWriteAshmem() 2273f4cbf05Sopenharmony_ci#endif 2283f4cbf05Sopenharmony_ci{ 2293f4cbf05Sopenharmony_ci return MapAshmem(PROT_READ | PROT_WRITE); 2303f4cbf05Sopenharmony_ci} 2313f4cbf05Sopenharmony_ci 2323f4cbf05Sopenharmony_ci#ifdef UTILS_CXX_RUST 2333f4cbf05Sopenharmony_cibool Ashmem::MapReadOnlyAshmem() const 2343f4cbf05Sopenharmony_ci#else 2353f4cbf05Sopenharmony_cibool Ashmem::MapReadOnlyAshmem() 2363f4cbf05Sopenharmony_ci#endif 2373f4cbf05Sopenharmony_ci{ 2383f4cbf05Sopenharmony_ci return MapAshmem(PROT_READ); 2393f4cbf05Sopenharmony_ci} 2403f4cbf05Sopenharmony_ci 2413f4cbf05Sopenharmony_ci#ifdef UTILS_CXX_RUST 2423f4cbf05Sopenharmony_civoid Ashmem::UnmapAshmem() const 2433f4cbf05Sopenharmony_ci#else 2443f4cbf05Sopenharmony_civoid Ashmem::UnmapAshmem() 2453f4cbf05Sopenharmony_ci#endif 2463f4cbf05Sopenharmony_ci{ 2473f4cbf05Sopenharmony_ci if (startAddr_ != nullptr) { 2483f4cbf05Sopenharmony_ci ::munmap(startAddr_, memorySize_); 2493f4cbf05Sopenharmony_ci startAddr_ = nullptr; 2503f4cbf05Sopenharmony_ci } 2513f4cbf05Sopenharmony_ci flag_ = 0; 2523f4cbf05Sopenharmony_ci} 2533f4cbf05Sopenharmony_ci 2543f4cbf05Sopenharmony_ci#ifdef UTILS_CXX_RUST 2553f4cbf05Sopenharmony_cibool Ashmem::WriteToAshmem(const void *data, int32_t size, int32_t offset) const 2563f4cbf05Sopenharmony_ci#else 2573f4cbf05Sopenharmony_cibool Ashmem::WriteToAshmem(const void *data, int32_t size, int32_t offset) 2583f4cbf05Sopenharmony_ci#endif 2593f4cbf05Sopenharmony_ci{ 2603f4cbf05Sopenharmony_ci if (data == nullptr) { 2613f4cbf05Sopenharmony_ci return false; 2623f4cbf05Sopenharmony_ci } 2633f4cbf05Sopenharmony_ci 2643f4cbf05Sopenharmony_ci if (!CheckValid(size, offset, PROT_WRITE)) { 2653f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: invalid input or not map", __func__); 2663f4cbf05Sopenharmony_ci return false; 2673f4cbf05Sopenharmony_ci } 2683f4cbf05Sopenharmony_ci 2693f4cbf05Sopenharmony_ci auto tmpData = reinterpret_cast<char *>(startAddr_); 2703f4cbf05Sopenharmony_ci int ret = memcpy_s(tmpData + offset, memorySize_ - offset, reinterpret_cast<const char *>(data), size); 2713f4cbf05Sopenharmony_ci if (ret != EOK) { 2723f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed to memcpy, ret = %{public}d", __func__, ret); 2733f4cbf05Sopenharmony_ci return false; 2743f4cbf05Sopenharmony_ci } 2753f4cbf05Sopenharmony_ci 2763f4cbf05Sopenharmony_ci return true; 2773f4cbf05Sopenharmony_ci} 2783f4cbf05Sopenharmony_ci 2793f4cbf05Sopenharmony_ci#ifdef UTILS_CXX_RUST 2803f4cbf05Sopenharmony_ciconst void *Ashmem::ReadFromAshmem(int32_t size, int32_t offset) const 2813f4cbf05Sopenharmony_ci#else 2823f4cbf05Sopenharmony_ciconst void *Ashmem::ReadFromAshmem(int32_t size, int32_t offset) 2833f4cbf05Sopenharmony_ci#endif 2843f4cbf05Sopenharmony_ci{ 2853f4cbf05Sopenharmony_ci if (!CheckValid(size, offset, PROT_READ)) { 2863f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: invalid input or not map", __func__); 2873f4cbf05Sopenharmony_ci return nullptr; 2883f4cbf05Sopenharmony_ci } 2893f4cbf05Sopenharmony_ci 2903f4cbf05Sopenharmony_ci return reinterpret_cast<const char *>(startAddr_) + offset; 2913f4cbf05Sopenharmony_ci} 2923f4cbf05Sopenharmony_ci 2933f4cbf05Sopenharmony_cibool Ashmem::CheckValid(int32_t size, int32_t offset, int cmd) const 2943f4cbf05Sopenharmony_ci{ 2953f4cbf05Sopenharmony_ci if (startAddr_ == nullptr) { 2963f4cbf05Sopenharmony_ci return false; 2973f4cbf05Sopenharmony_ci } 2983f4cbf05Sopenharmony_ci if ((size < 0) || (size > memorySize_) || (offset < 0) || (offset > memorySize_)) { 2993f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: , invalid parameter, size = %{public}d, memorySize_ = %{public}d, offset = %{public}d", 3003f4cbf05Sopenharmony_ci __func__, size, memorySize_, offset); 3013f4cbf05Sopenharmony_ci return false; 3023f4cbf05Sopenharmony_ci } 3033f4cbf05Sopenharmony_ci if (offset + size > memorySize_) { 3043f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: , invalid parameter, size = %{public}d, memorySize_ = %{public}d, offset = %{public}d", 3053f4cbf05Sopenharmony_ci __func__, size, memorySize_, offset); 3063f4cbf05Sopenharmony_ci return false; 3073f4cbf05Sopenharmony_ci } 3083f4cbf05Sopenharmony_ci if (!(static_cast<uint32_t>(GetProtection()) & static_cast<uint32_t>(cmd)) || 3093f4cbf05Sopenharmony_ci !(static_cast<uint32_t>(flag_) & static_cast<uint32_t>(cmd))) { 3103f4cbf05Sopenharmony_ci return false; 3113f4cbf05Sopenharmony_ci } 3123f4cbf05Sopenharmony_ci 3133f4cbf05Sopenharmony_ci return true; 3143f4cbf05Sopenharmony_ci} 3153f4cbf05Sopenharmony_ci} 316