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 "av_hardware_memory.h"
17 #include <unistd.h>
18 #include <unordered_map>
19 #include "ashmem.h"
20 #include "av_hardware_allocator.h"
21 #include "common/log.h"
22 #include "common/status.h"
23 #include "message_parcel.h"
24 #include "scope_guard.h"
25
26 #ifdef MEDIA_OHOS
27 #include "sys/mman.h"
28 #endif
29 #define HARDWARE_ALLOCATOR std::static_pointer_cast<AVHardwareAllocator>(allocator_)
30
31 namespace {
32 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "AVHardwareMemory" };
33 }
34
35 namespace OHOS {
36 namespace Media {
CreateHardwareAllocator(int32_t fd,int32_t capacity,MemoryFlag memFlag,bool isSecure)37 std::shared_ptr<AVAllocator> AVAllocatorFactory::CreateHardwareAllocator(int32_t fd, int32_t capacity,
38 MemoryFlag memFlag, bool isSecure)
39 {
40 FALSE_RETURN_V_MSG_E(fd > 0, nullptr, "File descriptor is invalid");
41 auto allocator = std::shared_ptr<AVHardwareAllocator>(new AVHardwareAllocator());
42 allocator->fd_ = dup(fd);
43 allocator->capacity_ = capacity;
44 allocator->memFlag_ = memFlag;
45 allocator->isSecure_ = isSecure;
46 return allocator;
47 }
48
AVHardwareAllocator()49 AVHardwareAllocator::AVHardwareAllocator()
50 : fd_(-1),
51 capacity_(-1),
52 allocBase_(nullptr),
53 memFlag_(MemoryFlag::MEMORY_READ_ONLY),
54 isAllocated_(false),
55 isSecure_(false)
56 {
57 MEDIA_LOG_D("AVHardwareAllocator is allocatered");
58 };
59
~AVHardwareAllocator()60 AVHardwareAllocator::~AVHardwareAllocator()
61 {
62 if (fd_ > 0 && (!isAllocated_ || isSecure_)) {
63 (void)::close(fd_);
64 fd_ = -1;
65 }
66 }
67
Alloc(int32_t capacity)68 void *AVHardwareAllocator::Alloc(int32_t capacity)
69 {
70 (void)capacity;
71 FALSE_RETURN_V(!isSecure_, nullptr);
72 Status ret = MapMemoryAddr();
73 FALSE_RETURN_V_MSG_E(ret == Status::OK, nullptr, "Map dma buffer failed");
74 isAllocated_ = true;
75 return reinterpret_cast<void *>(allocBase_);
76 }
77
Free(void * ptr)78 bool AVHardwareAllocator::Free(void *ptr)
79 {
80 #ifdef MEDIA_OHOS
81 FALSE_RETURN_V(!isSecure_, true);
82 FALSE_RETURN_V_MSG_E(static_cast<uint8_t *>(ptr) == allocBase_, false, "Mapped buffer not match");
83 FALSE_RETURN_V_MSG_E(isAllocated_, false, "Never allocated memory by Alloc function of this allocator");
84 if (allocBase_ != nullptr) {
85 (void)::munmap(allocBase_, static_cast<size_t>(capacity_));
86 }
87 if (fd_ > 0) {
88 (void)::close(fd_);
89 fd_ = -1;
90 }
91 allocBase_ = nullptr;
92 capacity_ = -1;
93 #endif
94 return true;
95 }
96
GetMemoryType()97 MemoryType AVHardwareAllocator::GetMemoryType()
98 {
99 return MemoryType::HARDWARE_MEMORY;
100 }
101
GetMemFlag()102 MemoryFlag AVHardwareAllocator::GetMemFlag()
103 {
104 return memFlag_;
105 }
106
GetFileDescriptor()107 int32_t AVHardwareAllocator::GetFileDescriptor()
108 {
109 return fd_;
110 }
111
GetIsSecure()112 bool AVHardwareAllocator::GetIsSecure()
113 {
114 return isSecure_;
115 }
116
MapMemoryAddr()117 Status AVHardwareAllocator::MapMemoryAddr()
118 {
119 #ifdef MEDIA_OHOS
120 ON_SCOPE_EXIT(0)
121 {
122 MEDIA_LOG_E("MapMemoryAddr failed. "
123 "capacity:%{public}d, flags:0x%{public}x, fd:%{public}d",
124 capacity_, memFlag_, fd_);
125 if (allocBase_ != nullptr) {
126 (void)::munmap(allocBase_, static_cast<size_t>(capacity_));
127 allocBase_ = nullptr;
128 }
129 return Status::ERROR_NO_MEMORY;
130 };
131 FALSE_RETURN_V_MSG_E(capacity_ > 0, Status::ERROR_INVALID_DATA, "capacity is invalid, capacity:%{public}d",
132 capacity_);
133 unsigned int prot = PROT_READ | PROT_WRITE;
134 FALSE_RETURN_V_MSG_E(fd_ > 0, Status::ERROR_INVALID_OPERATION, "fd is invalid, fd:%{public}d", fd_);
135 if (memFlag_ == MemoryFlag::MEMORY_READ_ONLY) {
136 prot &= ~PROT_WRITE;
137 } else if (memFlag_ == MemoryFlag::MEMORY_WRITE_ONLY) {
138 prot &= ~PROT_READ;
139 }
140 void *addr = ::mmap(nullptr, static_cast<size_t>(capacity_), static_cast<int>(prot), MAP_SHARED, fd_, 0);
141 FALSE_RETURN_V_MSG_E(addr != MAP_FAILED, Status::ERROR_INVALID_OPERATION, "mmap failed, please check params");
142 allocBase_ = reinterpret_cast<uint8_t *>(addr);
143 CANCEL_SCOPE_EXIT_GUARD(0);
144 #endif
145 return Status::OK;
146 }
147
AVHardwareMemory()148 AVHardwareMemory::AVHardwareMemory() : isStartSync_(false), memFlag_(MemoryFlag::MEMORY_READ_ONLY) {}
149
~AVHardwareMemory()150 AVHardwareMemory::~AVHardwareMemory()
151 {
152 #ifdef MEDIA_OHOS
153 if (allocator_ == nullptr) {
154 if (base_ != nullptr) {
155 (void)::munmap(base_, static_cast<size_t>(capacity_));
156 }
157 if (fd_ > 0) {
158 (void)::close(fd_);
159 fd_ = -1;
160 }
161 return;
162 }
163 #endif
164 allocator_->Free(base_);
165 }
166
Init()167 Status AVHardwareMemory::Init()
168 {
169 fd_ = HARDWARE_ALLOCATOR->GetFileDescriptor();
170 memFlag_ = HARDWARE_ALLOCATOR->GetMemFlag();
171 base_ = static_cast<uint8_t *>(allocator_->Alloc(0));
172
173 FALSE_RETURN_V_MSG_E(base_ != nullptr || HARDWARE_ALLOCATOR->GetIsSecure(), Status::ERROR_NO_MEMORY,
174 "dma memory alloc failed");
175 return Status::OK;
176 }
177
Init(MessageParcel & parcel)178 Status AVHardwareMemory::Init(MessageParcel &parcel)
179 {
180 #ifdef MEDIA_OHOS
181 int32_t fd = parcel.ReadFileDescriptor();
182 FALSE_RETURN_V_MSG_E(fd > 0, Status::ERROR_INVALID_DATA, "File descriptor is invalid");
183
184 memFlag_ = static_cast<MemoryFlag>(parcel.ReadUint32());
185
186 allocator_ = AVAllocatorFactory::CreateHardwareAllocator(fd, capacity_, memFlag_);
187 if (allocator_ == nullptr) {
188 MEDIA_LOG_E("allocator is nullptr");
189 (void)::close(fd);
190 return Status::ERROR_NO_MEMORY;
191 }
192 fd_ = HARDWARE_ALLOCATOR->GetFileDescriptor();
193 (void)::close(fd);
194
195 base_ = static_cast<uint8_t *>(allocator_->Alloc(0));
196 allocator_ = nullptr;
197
198 FALSE_RETURN_V_MSG_E(base_ != nullptr, Status::ERROR_NO_MEMORY, "dma memory alloc failed");
199 #endif
200 return Status::OK;
201 }
202
WriteToMessageParcel(MessageParcel & parcel)203 bool AVHardwareMemory::WriteToMessageParcel(MessageParcel &parcel)
204 {
205 FALSE_RETURN_V_MSG_E(!HARDWARE_ALLOCATOR->GetIsSecure(), false, "AVHardwareAllocator is secure");
206 bool ret = true;
207 #ifdef MEDIA_OHOS
208 MessageParcel bufferParcel;
209 ret = bufferParcel.WriteFileDescriptor(fd_) && bufferParcel.WriteUint32(static_cast<uint32_t>(memFlag_));
210 if (ret) {
211 parcel.Append(bufferParcel);
212 }
213 #endif
214 return ret;
215 }
216
ReadFromMessageParcel(MessageParcel & parcel)217 bool AVHardwareMemory::ReadFromMessageParcel(MessageParcel &parcel)
218 {
219 #ifdef MEDIA_OHOS
220 int32_t fd = parcel.ReadFileDescriptor();
221 (void)parcel.ReadUint32();
222 if (fd > 0) {
223 (void)::close(fd);
224 }
225 #endif
226 return true;
227 }
228
GetMemoryType()229 MemoryType AVHardwareMemory::GetMemoryType()
230 {
231 return MemoryType::HARDWARE_MEMORY;
232 }
233
GetMemoryFlag()234 MemoryFlag AVHardwareMemory::GetMemoryFlag()
235 {
236 return memFlag_;
237 }
238
GetFileDescriptor()239 int32_t AVHardwareMemory::GetFileDescriptor()
240 {
241 return fd_;
242 }
243 } // namespace Media
244 } // namespace OHOS
245