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#include "buffer/avsharedmemorybase.h"
17#include <sys/mman.h>
18#include <unistd.h>
19#include "ashmem.h"
20#include "common/status.h"
21#include "common/log.h"
22#include "scope_guard.h"
23#include "securec.h"
24
25namespace {
26constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "AVSharedMemoryBase" };
27}
28
29namespace OHOS {
30namespace Media {
31struct AVSharedMemoryBaseImpl : public AVSharedMemoryBase {
32public:
33    AVSharedMemoryBaseImpl(int32_t fd, int32_t size, uint32_t flags, const std::string &name)
34        : AVSharedMemoryBase(fd, size, flags, name) {}
35};
36
37std::shared_ptr<AVSharedMemory> AVSharedMemoryBase::CreateFromLocal(
38    int32_t size, uint32_t flags, const std::string &name)
39{
40    std::shared_ptr<AVSharedMemoryBase> memory = std::make_shared<AVSharedMemoryBase>(size, flags, name);
41    int32_t ret = memory->Init();
42    if (ret != static_cast<int32_t>(Status::OK)) {
43        MEDIA_LOG_E("Create avsharedmemory failed, ret = %{public}d", ret);
44        return nullptr;
45    }
46
47    return memory;
48}
49
50std::shared_ptr<AVSharedMemory> AVSharedMemoryBase::CreateFromRemote(
51    int32_t fd, int32_t size, uint32_t flags, const std::string &name)
52{
53    std::shared_ptr<AVSharedMemoryBase> memory = std::make_shared<AVSharedMemoryBaseImpl>(fd, size, flags, name);
54    int32_t ret = memory->Init();
55    if (ret != static_cast<int32_t>(Status::OK)) {
56        MEDIA_LOG_E("Create avsharedmemory failed, ret = %{public}d", ret);
57        return nullptr;
58    }
59
60    return memory;
61}
62
63AVSharedMemoryBase::AVSharedMemoryBase(int32_t size, uint32_t flags, const std::string &name)
64    : base_(nullptr), capacity_(size), flags_(flags), name_(name), fd_(-1), size_(0)
65{
66    MEDIA_LOG_DD(LOGD_FREQUENCY, "enter ctor, instance: 0x%{public}06" PRIXPTR ", name = %{public}s",
67               FAKE_POINTER(this), name_.c_str());
68}
69
70AVSharedMemoryBase::AVSharedMemoryBase(int32_t fd, int32_t size, uint32_t flags, const std::string &name)
71    : base_(nullptr), capacity_(size), flags_(flags), name_(name), fd_(dup(fd)), size_(0)
72{
73    MEDIA_LOG_DD(LOGD_FREQUENCY, "enter ctor, instance: 0x%{public}06" PRIXPTR ", name = %{public}s",
74               FAKE_POINTER(this), name_.c_str());
75}
76
77AVSharedMemoryBase::~AVSharedMemoryBase()
78{
79    MEDIA_LOG_DD(LOGD_FREQUENCY, "enter dtor, instance: 0x%{public}06" PRIXPTR ", name = %{public}s",
80               FAKE_POINTER(this), name_.c_str());
81    Close();
82}
83
84int32_t AVSharedMemoryBase::Init(bool isMapVirAddr)
85{
86    ON_SCOPE_EXIT(0) {
87        MEDIA_LOG_E("create avsharedmemory failed, name = %{public}s, size = %{public}d, "
88                    "flags = 0x%{public}x, fd = %{public}d",
89                    name_.c_str(), capacity_, flags_, fd_);
90        Close();
91    };
92
93    FALSE_RETURN_V_MSG_E(capacity_ > 0, static_cast<int32_t>(Status::ERROR_INVALID_PARAMETER),
94                         "size is invalid, size = %{public}d", capacity_);
95
96    bool isRemote = false;
97    if (fd_ > 0) {
98        int size = AshmemGetSize(fd_);
99        FALSE_RETURN_V_MSG_E(size == capacity_, static_cast<int32_t>(Status::ERROR_INVALID_PARAMETER),
100            "size not equal capacity_, size = %{public}d, capacity_ = %{public}d", size, capacity_);
101        isRemote = true;
102    } else {
103        fd_ = AshmemCreate(name_.c_str(), static_cast<size_t>(capacity_));
104        FALSE_RETURN_V_MSG_E(fd_ > 0, static_cast<int32_t>(Status::ERROR_INVALID_PARAMETER),
105                             "fd is invalid, fd = %{public}d", fd_);
106    }
107    if (isMapVirAddr) {
108        int32_t ret = MapMemory(isRemote);
109        FALSE_RETURN_V_MSG_E(ret == static_cast<int32_t>(Status::OK),
110                             static_cast<int32_t>(Status::ERROR_INVALID_PARAMETER),
111                             "MapMemory failed, ret = %{plublic}d", ret);
112    }
113    CANCEL_SCOPE_EXIT_GUARD(0);
114    return static_cast<int32_t>(Status::OK);
115}
116
117int32_t AVSharedMemoryBase::MapMemory(bool isRemote)
118{
119#ifdef MEDIA_OHOS
120    unsigned int prot = PROT_READ | PROT_WRITE;
121    if (isRemote && (flags_ & FLAGS_READ_ONLY)) {
122        prot &= ~PROT_WRITE;
123    }
124
125    int result = AshmemSetProt(fd_, static_cast<int>(prot));
126    FALSE_RETURN_V_MSG_E(result >= 0, static_cast<int32_t>(Status::ERROR_INVALID_OPERATION),
127        "AshmemSetProt failed, result = %{public}d", result);
128
129    void *addr = ::mmap(nullptr, static_cast<size_t>(capacity_), static_cast<int>(prot), MAP_SHARED, fd_, 0);
130    FALSE_RETURN_V_MSG_E(addr != MAP_FAILED, static_cast<int32_t>(Status::ERROR_INVALID_OPERATION),
131                         "mmap failed, please check params");
132
133    base_ = reinterpret_cast<uint8_t*>(addr);
134#endif
135    return static_cast<int32_t>(Status::OK);
136}
137
138void AVSharedMemoryBase::Close() noexcept
139{
140#ifdef MEDIA_OHOS
141    if (base_ != nullptr) {
142        (void)::munmap(base_, static_cast<size_t>(capacity_));
143        base_ = nullptr;
144        capacity_ = 0;
145        flags_ = 0;
146        size_ = 0;
147    }
148#endif
149    if (fd_ > 0) {
150        (void)::close(fd_);
151        fd_ = -1;
152    }
153}
154
155int32_t AVSharedMemoryBase::Write(const uint8_t *in, int32_t writeSize, int32_t position)
156{
157    FALSE_RETURN_V_MSG_E(in != nullptr, 0, "Input buffer is nullptr");
158    FALSE_RETURN_V_MSG_E(writeSize > 0, 0, "Input writeSize:%{public}d is invalid", writeSize);
159    int32_t start = 0;
160    if (position == INVALID_POSITION) {
161        start = size_;
162    } else {
163        start = std::min(position, capacity_);
164    }
165    int32_t unusedSize = capacity_ - start;
166    int32_t length = std::min(writeSize, unusedSize);
167    MEDIA_LOG_DD("write data,length:%{public}d, start:%{public}d, name:%{public}s", length, start, name_.c_str());
168    FALSE_RETURN_V_MSG_E((length + start) <= capacity_, 0, "Write out of bounds, length:%{public}d, "
169                            "start:%{public}d, capacity_:%{public}d", length, start, capacity_);
170    uint8_t *dstPtr = base_ + start;
171    FALSE_RETURN_V_MSG_E(dstPtr != nullptr, 0, "Inner dstPtr is nullptr");
172
173    auto error = memcpy_s(dstPtr, length, in, length);
174    FALSE_RETURN_V_MSG_E(error == EOK, 0, "Inner memcpy_s failed,name:%{public}s, %{public}s",
175        name_.c_str(), strerror(error));
176    size_ = start + length;
177    return length;
178}
179
180int32_t AVSharedMemoryBase::Read(uint8_t *out, int32_t readSize, int32_t position)
181{
182    FALSE_RETURN_V_MSG_E(out != nullptr, 0, "Input buffer is nullptr");
183    FALSE_RETURN_V_MSG_E(readSize > 0, 0, "Input readSize:%{public}d is invalid", readSize);
184    int32_t start = 0;
185    int32_t maxLength = size_;
186    if (position != INVALID_POSITION) {
187        start = std::min(position, size_);
188        maxLength = size_ - start;
189    }
190    int32_t length = std::min(readSize, maxLength);
191    FALSE_RETURN_V_MSG_E((length + start) <= capacity_, 0, "Read out of bounds, length:%{public}d, "
192                            "start:%{public}d, capacity_:%{public}d", length, start, capacity_);
193    uint8_t *srcPtr = base_ + start;
194    FALSE_RETURN_V_MSG_E(srcPtr != nullptr, 0, "Inner srcPtr is nullptr");
195    auto error = memcpy_s(out, length, srcPtr, length);
196    FALSE_RETURN_V_MSG_E(error == EOK, 0, "Inner memcpy_s failed,name:%{public}s, %{public}s",
197        name_.c_str(), strerror(error));
198    return length;
199}
200
201void AVSharedMemoryBase::ClearUsedSize()
202{
203    size_ = 0;
204}
205
206int32_t AVSharedMemoryBase::GetUsedSize() const
207{
208    return size_;
209}
210} // namespace Media
211} // namespace OHOS
212