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