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